可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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!
回答2:
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", "AppFlavor1"
}
flavor2{
resValue "string", "app_name", "AppFlavor2"
}
}
This is less disruptive than creating new strings.xml under different built sets or writing custom scripts.
I have a production app running using this method
https://play.google.com/store/apps/details?id=co.getintouch.play with app name "InTouch Messenger: Premium Edition"
https://play.google.com/store/apps/details?id=co.getintouch with app name "InTouch Messenger"
productFlavors {
main{
resValue "string", "app_name", "InTouch Messenger"
}
googlePlay{
resValue "string", "app_name", "InTouch Messenger: GPE Edition"
}
}
Don't forget to remove app_name from strings.xml!
回答3:
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
回答4:
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.
回答5:
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.
回答6:
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>
回答7:
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
回答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
回答9:
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