How to get dynamic values from product flavor into a properties file

Viewed 565

I'm developing a Flutter application with different product flavors for Android and want to be able to define a value for each flavor, and select the value based on which flavor I'm building, and interpolate it into a properties file in order to dynamically configure a third party library. I would also be open to having multiple duplicate properties files, each with their flavor-specific values, and then selecting the right one at build time.

My research suggests I'm likely taking the wrong approach. After reading the Android documentation, I tried using BuildConfig to generate the values and then reference them in the properties file. I do see that the BuildConfig.java is built with the right values, but they are not being interpolated in my properties file. I'm not sure what approach I should be taking here, so any suggestions would be great!

thirdPartyLibrary.properties

customProperty=${BuildConfig.CUSTOM_PROPERTY}

build.gradle

...

flavorDimensions "app"

    productFlavors {
        dev {
            dimension "app"
            buildConfigField "String", "CUSTOM_PROPERTY", "\"my custom property for dev\""
        }
        qa {
            dimension "app"
            buildConfigField "String", "CUSTOM_PROPERTY", "\"my custom property for qa\""
        }
    }
    
    ...

2 Answers

I managed to get this working by following the steps outlined here: https://stackoverflow.com/a/47992042/4215892

So I removed the values from my properties file, and instead added this code to the gradle file:

...

def thirdPartyLibraryProperties = new Properties()
File thirdPartyConfig = file("src/main/assets/thirdPartyLibrary.properties")

flavorDimensions "app"

    productFlavors {
        dev {
            dimension "app"
            thirdPartyLibraryProperties.load(thirdPartyConfig.newDataInputStream())
            thirdPartyLibraryProperties.setProperty("customProperty", "my custom property for dev")
            thirdPartyLibraryProperties.store(thirdPartyConfig.newWriter(), null)
        }
        qa {
            dimension "app"
            thirdPartyLibraryProperties.load(thirdPartyConfig.newDataInputStream())
            thirdPartyLibraryProperties.setProperty("customProperty", "my custom property for qa")
            thirdPartyLibraryProperties.store(thirdPartyConfig.newWriter(), null)
        }
    }
    
    ...

However this feels like I'm repeating myself unnecessarily and like there is probably a cleaner solution. It is also modifying a file that is in source and not the build destination, which is generally bad practice.

The correct thing to do here was to simply create duplicate configuration files for each flavor and place the flavor-specific properties files in the correct folder for the flavor, so that it is copied to the correct "build/app/intermediates/merged_assets" folder. So instead of having a single "src/main/assets/thirdPartyLibrary.properties" file, I now have two files, one for dev and one for QA: "src/dev/assets/thirdPartyLibrary.properties" "src/qa/assets/thirdPartyLibrary.properties"

This is so painfully obvious once you understand how Android's build system works, but was initially opaque to me as a new Flutter developer.

This is the thread that pointed me at the right answer: Reference different assets based on build flavor

Related