I have 2 build flavors, say, flavor1 and flavor2.
I would like my application to be named, say, \"AppFlavor1\" when I build for flavor1 an
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.
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
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
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.
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!
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