Different app names for different build flavors?
Asked Answered
W

11

138

I have 2 build flavors, say, flavor1 and flavor2.

I would like my application to be named, say, "AppFlavor1" when I build for flavor1 and "AppFlavor2" when I build for flavor 2.

It is not the title of activities I want to change. I want to change the app name as it's displayed on the phone menu and elsewhere.

From build.gradle I can set various parameters for my flavors but, it seems, not the app label. And I can not change the app label programmatically based on some variable, too.

So, how do people handle this?

Workbench answered 7/11, 2013 at 8:21 Comment(0)
U
35

Instead of changing your main strings.xml with a script and risk messing up your source control, why not rely on the standard merging behavior of the Android Gradle build?

My build.gradle contains

sourceSets {
    main {
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        resources.srcDirs = ['src']
        aidl.srcDirs = ['src']
        renderscript.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
    }

    release {
        res.srcDir 'variants/release/res'
    }

    debug {
        res.srcDir 'variants/debug/res'
    }
}

So now I can define my app_name string in the variants/[release|debug]/res/strings.xml. And anything else I want to change, too!

Uela answered 15/11, 2013 at 8:55 Comment(4)
Edited: use res.srcDir to add to the array instead of redefining it altogether.Uela
Yes, I have figured that out too by now. Thanks a lotWorkbench
Where should one add the sourceSets block? Is it under the android{...} block?Hemipode
@AbelMelquiadesCallejo inside the android block indeed.Uela
S
346

Remove app_name from strings.xml (else gradle will complain of duplicate resources). Then modify build file like this:

productFlavors {
    flavor1{
        resValue "string", "app_name", "AppNameFlavor1"
    }

    flavor2{
        resValue "string", "app_name", "AppNameFlavor2"
    }
   } 

Also make sure @string/app_name value is assigned for android:label attribute in the manifest.

<application
        ...
        android:label="@string/app_name"
        ...

This is less disruptive than creating new strings.xml under different built sets or writing custom scripts.

Sherri answered 16/6, 2015 at 22:35 Comment(9)
This works like a charm, but question: how do we add localized strings for other locales when adding the string resource like this?Adamok
posted a question for this here: #36105994 Do you mind taking a look please?Adamok
@kevin, no it still does. The app is still in active development using this paradigmSherri
I found that a resValue in the build type overwrites the resValue from the product flavor. I was using both, and I think the order was different before.Hamlen
The only place where you should set app_name should be in these productFlavors tag. Remove it from everywhere else.Sherri
What about using multiple flavor dimensions? How can I name it diferently for each flavor/flavor combination?Kolinsky
Everything is fine, but App Name showing below launcher icon isn't changing as set by gradle product flavor. I removed "app_name" from strings.xml and set in product flavor. If I see app name from App Info page of android, showing app name set by product flavor, but under launcher icon showing my previous app name.Condyloid
@mahbub.kuet are you using @string/app_name for your launcher activity label? Keep in mind that the label from the main launcher activity is used in preference to the application label for the app display name.Brickey
In my case I had to delete the app_name XML element from the strings.xml files BEFORE adding the app_name value to the build.gradle file.Berey
U
35

Instead of changing your main strings.xml with a script and risk messing up your source control, why not rely on the standard merging behavior of the Android Gradle build?

My build.gradle contains

sourceSets {
    main {
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        resources.srcDirs = ['src']
        aidl.srcDirs = ['src']
        renderscript.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
    }

    release {
        res.srcDir 'variants/release/res'
    }

    debug {
        res.srcDir 'variants/debug/res'
    }
}

So now I can define my app_name string in the variants/[release|debug]/res/strings.xml. And anything else I want to change, too!

Uela answered 15/11, 2013 at 8:55 Comment(4)
Edited: use res.srcDir to add to the array instead of redefining it altogether.Uela
Yes, I have figured that out too by now. Thanks a lotWorkbench
Where should one add the sourceSets block? Is it under the android{...} block?Hemipode
@AbelMelquiadesCallejo inside the android block indeed.Uela
M
21

If you want to maintain localization for the app name in different flavors, then you can achieve it as follows:

1) Specify android:label in <application> available in AndroidManifest.xml as follows:

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

2) Specify default value fo appLabel in app level build.gradle:

manifestPlaceholders = [appLabel:"@string/defaultName"]

3) Override the value for product flavors as follows:

productFlavors {
    AppFlavor1 {
        manifestPlaceholders = [appLabel:"@string/flavor1"]
    }
    AppFlavor2 {
        manifestPlaceholders = [appLabel:"@string/flavor2"]
    }

}

4) Add string resources for each of Strings (defaultName, flavor1, flavor2) in your strings.xml. This will allow you to localize them.

Mylo answered 16/6, 2018 at 13:13 Comment(2)
Step #2 must be in the 'defaultConfig' level of the build.gradle NOT in the 'android' level, else you will get an unknown property error related to the manifestPlaceholders name.Weller
To implement this I had to add tools:replace="android:label" attribute also in the <application> element.Neille
F
9

You can add a strings resource file to each flavor, then use those resource files to change your app name. For example in one of my apps, I have a free and paid version. To rename them "Lite" and "Pro", I created a meta_data.xml file, and added my app_name value to that XML and removed it from strings.xml. Next, in app/src create a folder for each flavor (see below for example structure). Inside these directories, add res/values/<string resource file name>. Now, when you build, this file will be copied into your build and your app will be renamed.

File structure:

app/src
   /pro/res/values/meta_data.xml
   /lite/res/values/meta_data.xml
Fr answered 15/12, 2014 at 0:54 Comment(2)
This is better than declaring in gradle file. Works like a charm. Thank you.Purificator
This is the android way of doing it. The flavor's resources override the main resources. Localization works as expected, eg with /pro/res/values-es/strings.xml. You can also keep app_name in main's strings.xml if you want a fallback. Should be the accepted answer.Ambulacrum
I
8

Another option that I actually use is change the manifest for each application. Instead of copy the resource folder, you can create a manifest for each flavour.

sourceSets {
  main {
 }

  release {
    manifest.srcFile 'src/release/AndroidManifest.xml'
 }

  debug {
    manifest.srcFile 'src/debug/AndroidManifest.xml'
 }
}

You have to have a principal AndroidManifest in your src main that will be the principal. Then you can define a manifest with only some options for each flavour like (src/release/AndroidManifest.xml):

<manifest package="com.application.yourapp">
  <application android:icon="@drawable/ic_launcher">
  </application>
</manifest>

For debug, AndroidManifest (src/debug/AndroidManifest.xml):

<manifest package="com.application.yourapp">
  <application android:icon="@drawable/ic_launcher2">
  </application>
</manifest>

Compiler will do a merge of the manifest and you can have a icon for each flavour.

Institutional answered 16/9, 2015 at 18:3 Comment(0)
F
8

This can easily be accomplished under buildTypes

buildTypes {
    debug {
        buildConfigField("String", "server_type", "\"TEST\"")
        resValue "string", "app_name", "Eventful-Test"
        debuggable true
        signingConfig signingConfigs.debug_key_sign
    }

    stage {
        buildConfigField("String", "server_type", "\"STAGE\"")
        resValue "string", "app_name", "Eventful-Stage"
        debuggable true
        signingConfig signingConfigs.debug_key_sign
    }

    release {
        buildConfigField("String", "server_type", "\"PROD\"")
        resValue "string", "app_name", "Eventful"
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        //TODO - add release signing
    }
}

Just make sure to remove app_name from strings.xml

Freestone answered 25/5, 2018 at 20:38 Comment(1)
How to localize the app name with this approach?Ambulacrum
R
2

First of all, answer this question: "Can the user install both flavors of your application on the same device?"

I use a Python script that patches the source. It contains some reusable functions and, of course, knowledge what needs be patched in this particular project. So the script is application-specific.

There is a lot of patching, the data for patching are kept in a Python dictionary (including application package names, they BTW are different from the Java package name), one dictionary per flavor.

As to l10n, strings may point to other strings, e.g. in my code I have:

<string name="app_name">@string/x_app_name_xyz</string>

<string name="x_app_name_default">My Application</string>
<string name="x_app_name_xyz">My App</string>
Ramie answered 7/11, 2013 at 8:32 Comment(5)
It's kind of Light vs Pro versions I think user may well have them bothWorkbench
Then you will have to change the app package name, e.g. com.example.mysoft.pro vs com.example.mysoft.light, otherwise the user will be able to install only one of them on the same device.Ramie
I did that but how do I get "My App " vs "My App Pro" in phone menu? I now have 2 apps (light and pro) but both have the same name. I do need 2 distinct app names for that and that is, as you're saying, not that easy?Workbench
As the other (downvoted) answer mentions, in AndroidManifest.xml there is <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >. After you clean and re-build everything (two times, once per flavor), you should get two apk-s with different android package names and different launcher labels. BTW, Eclipse often does not detect changes in resources, so you have to ask it to clean.Ramie
How do I make string/app_name different per flavor though? I'm sorry I still can't get it.Workbench
J
1

This is super simple to achieve. If you have already created flavors in your app and if the app name is coming from AndroidManifest.xml. Let's say

<application
    android:name="com.prakash.sampleapp"
    android:label="@string/app_name">

All you have to do is create string/app_name for your flavors.

  1. Switch to Project pane on Android studio. enter image description here
  2. Right click on app/src and choose New>XML>Values XML File
  3. Select the appropriate Target Source Set and create strings.xml file.enter image description here
  4. Update app_name to your liking.
  5. Install the flavor ./gradlew installFlavorNameDebug and you will see the updated name for app.

you could also create strings.xml manually but AS makes it easier to create all directories and resources files for you with above method.

Jennine answered 4/8, 2022 at 19:22 Comment(0)
K
0

You can create separate strings.xml file with app_name key for specific flavor. For example, for storybook flavor, we'll have the following strings.xml

enter image description here

In this case, we need to set only minimal config in build.gradle

enter image description here

Kosak answered 7/7, 2023 at 14:16 Comment(0)
R
-1

How do I make string/app_name different per flavor though?

I wanted to write an update, but realized that it is bigger than the original answer saying that I use a Python script that patches the source.

The Python script has a parameter, a directory name. That directory contains per-flavor assets, resources like launcher icons, and the file properties.txt with a Python dictionary.

{ 'someBoolean' : True
, 'someParam' : 'none'
, 'appTitle' : '@string/x_app_name_xyz'
}

The Python script loads the dictionary from that file and replaces the value between <string name="app_name"> and </string> by the value of properties['appTitle'].

The below code is provided on the as-is/as-was basis etc.

for strings_xml in glob.glob("res/values*/strings.xml"):
    fileReplace(strings_xml,'<string name="app_name">',properties['appTitle'],'</string>',oldtextpattern=r"[a-zA-Z0-9_/@\- ]+")

to read properties from one or more such file:

with open(filename1) as f:
    properties = eval(f.read())
with open(filename2) as f:
    properties.update(eval(f.read()))

and the fileReplace function is:

really = True
#False for debugging

# In the file 'fname',
# find the text matching "before oldtext after" (all occurrences) and
# replace 'oldtext' with 'newtext' (all occurrences).
# If 'mandatory' is true, raise an exception if no replacements were made.
def fileReplace(fname,before,newtext,after,oldtextpattern=r"[\w.]+",mandatory=True):
    with open(fname, 'r+') as f:
        read_data = f.read()
        pattern = r"("+re.escape(before)+r")"+oldtextpattern+"("+re.escape(after)+r")"
        replacement = r"\g<1>"+newtext+r"\g<2>"
        new_data,replacements_made = re.subn(pattern,replacement,read_data,flags=re.MULTILINE)
        if replacements_made and really:
            f.seek(0)
            f.truncate()
            f.write(new_data)
            if verbose:
                print "patching ",fname," (",replacements_made," occurrence" + ("s" if 1!=replacements_made else ""),")",newtext,("-- no changes" if new_data==read_data else "-- ***CHANGED***")
        elif replacements_made:
            print fname,":"
            print new_data
        elif mandatory:
            raise Exception("cannot patch the file: "+fname+" with ["+newtext+"] instead of '"+before+"{"+oldtextpattern+"}"+after+"'")

The first lines of the script are:

#!/usr/bin/python
# coding: utf-8

import sys
import os
import re
import os.path
import shutil
import argparse
import string
import glob
from myutils import copytreeover
Ramie answered 8/11, 2013 at 11:44 Comment(0)
C
-5

In AndroidManifest file, in the application tag you have this line:

android:label

And there you can say how to application label will appear in applications menu on device

Cipango answered 7/11, 2013 at 8:58 Comment(2)
Yes I read the question... You could set 2 branches and for each one ( one for flavor1 and one for flavor2 ) to set a different android:label in you AndroidManifest file.Cipango
Ah, I didn't know that. How do I place those 2 manifest files though? I though it's not possibleWorkbench

© 2022 - 2024 — McMap. All rights reserved.