Gradle-only solution to modify App name based on Build Variant
Asked Answered
L

2

6

I am trying to modify my gradle file to allow for different names for my app based on Flavor and Build Type. So far, I have been successful in being concise with Flavor based naming using Manifest Merging techniques via the Android Gradle Plugin Docs

Current

These are the names of the applications on my home screen for both my debug and release builds.

Flavor     Debug App Name             Release App Name
--------   --------------             ----------------
entity_1   App Name                   App Name
entity_2   App Name                   App Name
...        ...                        ...
entity_2   App Name                   App Name
hub        Hub                        Hub

Its's close, but...

Desired

Flavor     Debug App Name             Release App Name
--------   --------------             ----------------
entity_1   App Name - Entity_1_name   App Name
entity_2   App Name - Entity_2_name   App Name
...        ...                        ...
entity_n   App Name - Entity_n_name   App Name
hub        Hub                        Hub

I want this so I know which debug flavor is which on my home screen. I don't care about differentiating on the release flavors as a user will only have one on their device (it might be possible to have more than one, but I am not concerned with that)

Given how extensible Gradle is, I assume this is possible; however, I am not an advanced Gradle user.

So, how can I concisely (as possible) extend my code to get to my desired output?

Note: the above tables use versionNameSuffix as a suffix for my app name; however, it can be anything (another added variable??) that will allow me to tell which flavor I am using only in my debug build type.

Non-goals

Code

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "..."
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        manifestPlaceholders = [ applicationLabel:"App Name"]
    }

    productFlavors {
        entity_1 {
            versionNameSuffix ' - Entity_1_name'
            applicationIdSuffix 'entity_1'
        }
        entity_2 {
            versionNameSuffix ' - Entity_2_name'
            applicationIdSuffix 'entity_2'
        }
        hub {
            versionNameSuffix ' - Hub'
            applicationIdSuffix 'hub'
            manifestPlaceholders = [ applicationLabel:"Hub" ]
        }
    }

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

Manifest

<manifest ...>

    <application
        ...
        android:label="${applicationLabel}"
        ... >

Update

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    ext {
        APP_NAME = "App Name"
        HUB_NAME = "Hub"
    }

    defaultConfig {
        applicationId "..."
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }

    productFlavors {
        one_million {
            versionNameSuffix ' - Entity_1'
            applicationIdSuffix 'entity_1'
            manifestPlaceholders = [ applicationLabel: APP_NAME + versionNameSuffix ]
        }
        udacity {
            versionNameSuffix ' - Entity_2'
            applicationIdSuffix 'entity_2'
            manifestPlaceholders = [ applicationLabel: APP_NAME + versionNameSuffix ]
        }
        hub {
            versionNameSuffix ' - Hub'
            applicationIdSuffix 'hub'
            manifestPlaceholders = [ applicationLabel: HUB_NAME ]
        }
    }

    buildTypes {
        release {
            manifestPlaceholders = [ applicationLabel: APP_NAME ]
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

New Output

Flavor     Debug App Name             Release App Name
--------   --------------             ----------------
entity_1   App Name - Entity_1_name   App Name
entity_2   App Name - Entity_2_name   App Name
...        ...                        ...
entity_n   App Name - Entity_n_name   App Name
hub        Hub                        App Name          <- Issue (Release)
Luminary answered 12/6, 2016 at 10:0 Comment(3)
Do you mind telling why are you not using string resources solution? That's the cleanest solution.Belorussia
You can do it all in build.gradle file for learning but even Google creates multiple res/string.xml for storing Google Maps key for different environments. I store name in each flavours string.xml and in gradle add "Debug" to name in buildTypes/debug/versionNameSuffix.Belorussia
@Sharj "Do you mind telling why are you not using string resources solution? That's the cleanest solution." Well, because I didn't believe that was actually the cleanest solution, and it turns out that a Gradle-only solution is actually simpler, cleaner, more maintainable, and quite extensible. This way should allow you to use translated string resources in your release build if you so desire (have not tested this part yet).Luminary
L
6

The first try was a closer solution to the right answer than the updated code.

Further refactoring could possibly done by moving all the manifestPlaceholders code inside the applicationVariants.all section; however, this is a working copy of a semi-clean, gradle-only solution...

android {
    ext {
        APP_NAME = "App Name"
        HUB_NAME = "Hub"
    }
    defaultConfig {
        manifestPlaceholders = [ applicationLabel: APP_NAME ]
    }
    productFlavors {
        entity_1 {
            versionNameSuffix ' - Entity_1'
            applicationIdSuffix 'entity_1'
        }

        ...

        entity_n {
            versionNameSuffix ' - Entity_n'
            applicationIdSuffix 'entity_n'
        }

        hub {
            versionNameSuffix ' - Hub'
            applicationIdSuffix 'hub'
            manifestPlaceholders = [ applicationLabel: HUB_NAME ]
        }
    }

    applicationVariants.all { variant ->
        // Don't modify the release build or the hub flavor. They are good already.
        if (variant.buildType.name == "release" || variant.flavorName == "hub") return
        variant.mergedFlavor.manifestPlaceholders = [applicationLabel: APP_NAME + variant.mergedFlavor.versionNameSuffix]
    }

Notes:

BEFORE the applicationVariants.all { ... } code runs, this is what all the applicationLabel look like. We are close, but need to ADD to them...

Flavor     Debug App Name             Release App Name
--------   --------------             ----------------
entity_1   App Name                   App Name
entity_2   App Name                   App Name
...        ...                        ...
entity_n   App Name                   App Name
hub        Hub                        Hub

AFTER the applicationVariants.all { ... } code runs, this is what all the applicationLabel look like. We are done!

Flavor     Debug App Name             Release App Name
--------   --------------             ----------------
entity_1   App Name - Entity_1_name   App Name
entity_2   App Name - Entity_2_name   App Name
...        ...                        ...
entity_n   App Name - Entity_n_name   App Name
hub        Hub                        Hub

Also...

defaultConfig does not have a way of accessing information within the individual productFlavors. Although defaultConfig is a Flavor kind of, only the specified Flavors can read information from within the defaultConfig. There are no mechanism to go the other way (that I am aware of). So you need to set the most generic type in the defaultConfig

Any information within the buildTypes block will get the final say, and the code within applicationVariants.all will not override that. In order to overcome that, you have to remove the needed code from the buildType block and move it within the applicationVariants.all block (with the correct logic statements)

Luminary answered 12/6, 2016 at 13:12 Comment(0)
G
5

Christopher's solution didn't work for me. I spent another few hours trying different patterns, and I finally found one that worked in my case, so I'll share it here.

First, productFlavors definition in build.gradle:

productFlavors {

    uat {
        manifestPlaceholders.appNameSuffix = " UAT"
    }

    live {
        manifestPlaceholders.appNameSuffix = ""
    }
}

Then, buildTypes:

buildTypes {

    debug {
        manifestPlaceholders.appName = "Preg Debug"
    }

    qa {
        manifestPlaceholders.appName = "Preg QA"
    }

    release {
        manifestPlaceholders.appName = "Pregnancy"
    }

}

Last but not least, android:label in manifest > application:

    android:label="${appName}${appNameSuffix}"

As a result, I'm getting the following 6 variants of the app name:

  • Pregnancy
  • Pregnancy UAT
  • Preg QA
  • Preg QA UAT
  • Preg Debug
  • Preg Debug UAT

So, the conclusion is, I had to concatenate manifest placeholders from product flavor and build type in the manifest file, et voila!

In terms of being clean, readable, and maintainable, I think this is the way to go :)

Grownup answered 13/7, 2017 at 9:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.