Search code examples
androidbuildconfigproduct

Build one apk with multiple configs and resource files


I have multiple applications but it is one application with many flavors for many domains.

For every app I have separate package with AppConfig file and res folder which contains images for every domain.

Paths: app/src/eu/java/in/AppConfig; app/src/com/java/in/AppConfig; app/src/fr/java/in/AppConfig and etc.

And separate productFlavors for every build. I'm making for every domain separate apk.

But now I need to make one app and app itself must on run time change configs and resources then user change it.

For example menu where user choose domain and app must take for all application correct configs.

How I can achieve this solution? How can i build one opp which change on runtime its resources and configurations.

//config example
object AppConfig {
    const val oauthToken = "url"
    const val oauthClientID = "id"
   ....
}
//build.gradle example
productFlavors {
        dev {
            applicationId "dev.in.app"
            dimension "default"
        }
        eu {
            applicationId "eu.in.app"
            dimension "default"
        }
        ....
    }

Solution

  • To summarise, you currently have a multi-flavour app that requires a rebuild to change, and you instead want end users to be able to switch?

    Unfortunately there's no "type this code and it'll work" solution, you're going to need to rearchitect your app. You're going to need to move away from Gradle variant switching to in-code variant switching. The overall approach will be something like:

    1. Transition from multiple flavours of code to packages within your app. This will make all of your files / configs available in your single flavour. For example /eu/java/...MyFile.kt needs to become /java/.../eu/MyFile.kt.
    2. Figure out how to transition between your variants. This is very dependant on your situation, but one way is an enum of variants, then a store of which one is currently active (e.g. in memory, shared prefs, Room, from server).
    3. Everywhere you currently do things like isFeatureEnabled, you need to ensure these checks pay attention to the currently selected variant instead of being fixed values.

    Using your AppConfig example, you might have /Config/ directory with EuConfig, UsConfig etc defining those values. Then, a ConfigManager class that lets the user change the active Config and look up which features are required. For resources (strings, colours) you have 2 solutions:

    1. Each variant has their own UI, with their resources hardcoded (e.g. R.string.eu_title instead of R.string.title).
    2. Each resource is dynamically loaded, either by string concatenation or some sort of resource fetching helper. This will need a lot of testing.

    Ultimately this is probably going to take a fair bit of work, and it's hard to answer in detail without more information on your exact setup. Luckily when I've performed similar migrations before the work isn't necessarily hard, just takes a bit of thought and lots of testing.

    Edit: Just realised I answered a similar question 3 years ago, there's more helpful tips there!