115

我有 2 种构建风味,例如风味1风味2 。

我希望我的应用程序在为风味 1 构建时命名为“ AppFlavor1 ”,在为风味 2 构建时命名为“ AppFlavor2 ”。

这不是我要更改的活动标题。我想更改应用程序名称,因为它显示在手机菜单和其他地方。

build.gradle可以为我的口味设置各种参数,但似乎不是应用程序标签。而且我也不能基于某些变量以编程方式更改应用程序标签。

那么,人们是如何处理这个问题的呢?

4

9 回答 9

296

删除app_namestrings.xml否则 gradle 会抱怨重复的资源)。然后像这样修改构建文件:

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

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

还要确保为清单中的属性@string/app_name分配了值。android:label

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

这比strings.xml在不同的构建集下创建新的或编写自定义脚本的破坏性要小。

于 2015-06-16T22:35:36.250 回答
32

与其使用脚本更改主要的 strings.xml 并冒着弄乱源代码控制的风险,为什么不依赖 Android Gradle 构建的标准合并行为呢?

我的build.gradle包含

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'
    }
}

所以现在我可以app_namevariants/[release|debug]/res/strings.xml. 还有其他我想改变的东西!

于 2013-11-15T08:55:10.710 回答
18

如果您想保持不同风格的应用程序名称的本地化,那么您可以通过以下方式实现:

1)android:label<application>可用中指定AndroidManifest.xml如下:

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

appLabel2)在应用程序级别指定默认值 fo build.gradle

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

3) 覆盖产品风味的值,如下所示:

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

}

4) 在您的strings.xml. 这将允许您对它们进行本地化。

于 2018-06-16T13:13:55.090 回答
8

您可以为每个风味添加一个字符串资源文件,然后使用这些资源文件来更改您的应用程序名称。例如,在我的一个应用程序中,我有一个免费和付费版本。为了将它们重命名为“Lite”和“Pro”,我创建了一个meta_data.xml文件,并将我的app_name值添加到该 XML 中并将其从strings.xml. 接下来,app/src为每种风味创建一个文件夹(参见下面的示例结构)。在这些目录中,添加res/values/<string resource file name>. 现在,当您构建时,此文件将被复制到您的构建中,并且您的应用程序将被重命名。

文件结构:

app/src
   /pro/res/values/meta_data.xml
   /lite/res/values/meta_data.xml
于 2014-12-15T00:54:49.253 回答
7

我实际使用的另一个选项是更改每个应用程序的清单。您可以为每种风味创建清单,而不是复制资源文件夹。

sourceSets {
  main {
 }

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

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

您必须在您的 src main 中有一个委托人 AndroidManifest,这将是委托人。然后,您可以定义一个清单,其中每个风味只有一些选项,例如 (src/release/AndroidManifest.xml):

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

对于调试,AndroidManifest (src/debug/AndroidManifest.xml):

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

编译器将对清单进行合并,您可以为每种风味设置一个图标。

于 2015-09-16T18:03:18.763 回答
6

这可以在 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
    }
}

只需确保从 strings.xml 中删除 app_name

于 2018-05-25T20:38:55.547 回答
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>
于 2013-11-07T08:32:11.117 回答
0

但是,如何使字符串/应用程序名称因风味而异?

我想写一个更新,但意识到它比原来的答案更大,说我使用了一个修补源的 Python 脚本。

Python 脚本有一个参数,一个目录名。该目录包含每种风格的资产、启动器图标等资源以及带有 Python 字典的文件 properties.txt。

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

Python 脚本从该文件加载字典,<string name="app_name"></string>properties['appTitle'].

以下代码按原样/原样提供等。

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_/@\- ]+")

从一个或多个此类文件中读取属性:

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

fileReplace 函数是:

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+"'")

脚本的第一行是:

#!/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
于 2013-11-08T11:44:29.970 回答
-5

在 AndroidManifest 文件中,在应用程序标记中,您有以下行:

android:label

在那里你可以说应用程序标签如何出现在设备的应用程序菜单中

于 2013-11-07T08:58:54.620 回答