134

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?

Alexander Kulyakhtin
  • 47,782
  • 38
  • 107
  • 158

11 Answers11

338

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.

Roshana Pitigala
  • 8,437
  • 8
  • 49
  • 80
Ganesh Krishnan
  • 7,155
  • 2
  • 44
  • 52
  • 12
    This works like a charm, but question: how do we add localized strings for other locales when adding the string resource like this? – Viral Patel Mar 19 '16 at 18:24
  • posted a question for this here: http://stackoverflow.com/questions/36105494/localizing-string-resources-added-via-build-gradle Do you mind taking a look please? – Viral Patel Mar 19 '16 at 18:28
  • @kevin, no it still does. The app is still in active development using this paradigm – Ganesh Krishnan May 25 '16 at 02:21
  • 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. – Kevin Krumwiede May 26 '16 at 19:09
  • The only place where you should set app_name should be in these productFlavors tag. Remove it from everywhere else. – Ganesh Krishnan May 27 '16 at 05:35
  • 5
    What about using multiple flavor dimensions? How can I name it diferently for each flavor/flavor combination? – Zocket Jan 05 '17 at 14:31
  • 1
    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. – iamcrypticcoder Feb 24 '17 at 06:10
  • 3
    @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. – user650881 Jul 25 '17 at 19:42
  • 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. – James111 Aug 31 '18 at 04:48
34

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!

Pierre-Luc Paour
  • 1,725
  • 17
  • 21
20

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.

Sagar
  • 23,903
  • 4
  • 62
  • 62
  • 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. – Brendon Whateley Jul 21 '18 at 23:42
  • To implement this I had to add `tools:replace="android:label"` attribute also in the `` element. – rineez Apr 08 '21 at 17:50
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
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
James
  • 141
  • 1
  • 4
  • 2
    This is better than declaring in gradle file. Works like a charm. Thank you. – Filip Luchianenco Jan 30 '17 at 16:04
  • 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. – sulai Mar 21 '22 at 11:53
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.

Juanma Jurado
  • 574
  • 10
  • 18
7

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

Droid Chris
  • 3,455
  • 28
  • 31
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>
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
  • It's kind of Light vs Pro versions I think user may well have them both – Alexander Kulyakhtin Nov 07 '13 at 18:30
  • 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. – 18446744073709551615 Nov 08 '13 at 05:59
  • 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? – Alexander Kulyakhtin Nov 08 '13 at 09:40
  • As the other (downvoted) answer mentions, in AndroidManifest.xml there is ``. 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. – 18446744073709551615 Nov 08 '13 at 09:56
  • How do I make string/app_name different per flavor though? I'm sorry I still can't get it. – Alexander Kulyakhtin Nov 08 '13 at 11:15
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.

Prakash
  • 7,794
  • 4
  • 48
  • 44
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

Amerzilla
  • 1,212
  • 12
  • 12
-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
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
-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

Hitman
  • 588
  • 4
  • 10
  • 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. – Hitman Nov 07 '13 at 12:22
  • 6
    Ah, I didn't know that. How do I place those 2 manifest files though? I though it's not possible – Alexander Kulyakhtin Nov 07 '13 at 18:30