Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
357 views
in Technique[技术] by (71.8m points)

android - Using flavors for publishing an app on AppGallery and Google Play

I am trying to figure it out how to publish my app on AppGallery and Google Play. (My app is currently available on Google Play)

I am researching it for three hours and the best option looks like using flavors. Because I want to use same code base for different stores. To do that I decided to I add flavors like this:

productFlavors {
    gms {
        dimension "services"
        buildConfigField "String", "SERVICE_USED", '"g"'

    }
    hms {
        dimension "services"
        buildConfigField "String", "SERVICE_USED", '"h"'
    }
}
gmsImplementation 'com.google.firebase:firebase-analytics:17.2.0'
gmsImplementation 'com.google.firebase:firebase-messaging:20.0.0'
gmsImplementation 'com.google.firebase:firebase-ads:18.2.0'
gmsImplementation 'com.google.firebase:firebase-crashlytics:17.2.2'
hmsImplementation 'com.huawei.hms:ads-installreferrer:3.4.34.301'
hmsImplementation 'com.huawei.hms:ads-identifier:3.4.34.301'
hmsImplementation 'com.huawei.hms:hianalytics:5.0.5.301'
hmsImplementation 'com.huawei.hms:iap:5.0.4.301'
hmsImplementation 'com.huawei.hms:push:5.0.4.302'

Now I have a question:

Please correct me if I am wrong, I need to use an abstraction layer for common services right? For example, If I need to use IAP, I need a wrapper class that decides to use GMS or HMS which depends on the device type. If I go with this way I need something like that:

  1. Need an interface that needs to be implemented on HmsIAP and GmsIAP classes for the common methods like requestProduct method, purchaseMethod. etc

  2. A parent class that creates these classes and manages which class to use. That will called "AppIAP" class. The logic layer will use that class for IAP operations which will be not depented to the platform.

This approach makes sense to me, there will be one codebase for two platforms. It looks clean and easy to manage in the future. But the problem is I added flavor for the platform dependencies. So If I try to build hms variant of my code, it won't compile because Gms libraries will be missing. And I still has a GmsIAP class that needs to be build despite I am on the Hms variant.

To resolve that I could try to not use the flavors, with this approach I need to package my app with both platform's libraries, and my app will compile fine. But as looks like in the below link Google play will reject my app due to Hms libraries.

Is Huawei HMS tolerated on Google Play Store?

How can I resolve that?

question from:https://stackoverflow.com/questions/65860957/using-flavors-for-publishing-an-app-on-appgallery-and-google-play

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I think the most maintainable solution is to use dependency injection with different source sets for different flavors. You can put your GMS dependent code inside src/gms/java and your HMS dependent code inside src/hms/java. Only the selected product flavor source set will be compiled. Very basic example with Hilt would look like this:

Inside your main source set you will have

src/main/java/your/package/AppMobileServices.kt

interface AppMobileServices {
    val isAvailable: Boolean
}

Then for GMS source set

src/gms/java/your/package/GmsModule.kt:

@Module
@InstallIn(SingletonComponent::class)
class GmsModule {
    @Provides
    fun googleMobileServices(@ApplicationContext context: Context): AppMobileServices {
        return GmsServices(context)
    }
}

src/gms/java/your/package/GmsServices.kt:

@Singleton
class GmsServices(@ApplicationContext private val context: Context) : AppMobileServices {
    override val isAvailable: Boolean
        get() = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
}

And then HMS source set

src/hms/java/your/package/HmsModule.kt:

@Module
@InstallIn(SingletonComponent::class)
class HmsModule {
    @Provides
    fun huaweiMobileServices(@ApplicationContext context: Context): AppMobileServices {
        return HmsServices(context)
    }
}

src/hms/java/your/package/HmsServices.kt:

@Singleton
class HmsServices(@ApplicationContext private val context: Context) : AppMobileServices {
    override val isAvailable: Boolean
        get() = HuaweiApiAvailability.getInstance().isHuaweiMobileServicesAvailable(context) == ConnectionResult.SUCCESS
}

Then in your main source set you can just inject the AppMobileServices and the correct one will be provided. Also, all code that is dependent on either GMS or HMS would go inside their flavor source sets.

@Inject
lateinit var appMobileServices: AppMobileServices

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...