Customization

July 5, 2024 ยท View on GitHub

Some customers want a custom APK, with their own logo and other build-time customizations.

In order to do keep these customizations private, we do not store customer-specific customizations in this repository.

We support fetching a "customization" directory from another git repository during build time.

In order to fetch from this repository, the following values must be set as environment variables or in the local.properties file during Gradle configuration:

VariableDescription
CUSTOM_REPOSITORYURL to the Git repository that contains all customizations
GRGIT_USERGit credentials: username for checking out the repository
GRGIT_PASSWORDGit credentials: password for checking out the repository
CUSTOM_FOLDERName/path of the "customization root" directory. Represented below as "customizationRoot", but it can be whatever.
CLIENT_FOLDERName of the custom build directory within the "CUSTOM_FOLDER"

Note

This CUSTOM_FOLDER and CLIENT_FOLDER were made to keep compatibility with the old Android app. It would make more sense to combine them in a single variable with the full path to the custom build. If someone is looking into refactoring stuff, this is one I'd change at some point.

The Customization Files

When customizing a build, it is expected that a directory with the following structure exists:

-customizationRoot/
    |-myCustomBuildA/
        |-custom-reloaded.json
        |-resources/
            |-[optional - custom resources to overwrite src/res]

Build-time flags and values

Everything in the default.json file can be overwritten by the values in the custom-reloaded.json. Both files must have the same exact format, and the custom-reloaded.json will have the final say in which value will be bundled with the application.

Consider that the same property ("app_name") is defined in all possible places (i.e. both in default and custom-reloaded files, and both within a flavor and for all flavors).

default.json:

{
    "flavors": {
        "prod": {
            "app_name": "Wire - Prod Flavor"
        }
    },
    "app_name": "Wire"
}

custom-reloaded.json

{
    "flavors": {
        "prod": {
            "app_name": "My Custom App - Prod Flavor"
        }
    },
    "app_name": "My Custom App"
}

When building the prod flavor, the value will be chosen based on the following priority order ( highest priority first):

PriorityValueExplanation
1 - HighestMy Custom App - Prod FlavorCustom build and specific flavor
2My Custom AppCustom build
3Wire - Prod FlavorSpecific flavor
4 - LowestWireGeneric

Resources

These files will overwrite the Android Resources present in src/prod/res (or any other flavor).

During build time, these files will be copied into src/prod/res, src/beta/res, src/dev/res, etc. and will overwrite files in case of conflict.

This means that unlike the build flags and values, it is not possible to overwrite resources from a specific flavor. This use case was never needed, but it could be adapted for it.

Because of Resource Merging, this can be used to overwrite specific strings and other resources. For example, consider the following structure:

-app/src/main/
    |-res/
        |-mipmap/
        |    |-file1.png (picture of a cat)
        |-values/
        |    |-all-strings.xml
-app/src/prod/
    |-res/
        |-mipmap/
        |    |-file1.png (picture of a monkey)

-custom/
    |-resources/
        |-mipmap/
        |    |-file1.png (picture of a dog)
        |-values/
        |    |-custom-string-replacements.xml

Drawables and Mipmaps

Without the customization, the app would have a picture of a monkey as file1.png when building the prod flavor, and a picture of a cat for the other flavors. With the customization, the file1.png will be overwritten with the picture of a dog for all flavors.

Strings

Consider that the all-strings.xml file contains two strings:


<resources>
    <string name="buildType">Wire</string>
    <string name="color">Red</string>
</resources>

Consider that the custom-string-replacements.xml contains one string:


<resources>
    <string name="buildType">Customized!</string>
</resources>

Without Customization: the app displays "Wire" for the buildType string. With Customization: the app displays "Customized!" for the buildType.

Again, thanks to Resource Merging, the color string doesn't need to be overwritten. Because the custom-string-replacements file will be copied into the prod directory, the buildType will be chosen based on the flavor over the generic one put in main.

Implementation details

Take a look into the customization files within buildSrc for more details on how it works.