不同口味的不同应用名称?


93

我有2种构建口味,例如,flavor1flavor2

我想我的应用程序被命名,比如“ AppFlavor1 ”当我建立flavor1和“ AppFlavor2 ”当我建立的味道2。

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

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

那么,人们如何处理呢?

Answers:


24

除了使用脚本更改主要的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_name字符串了variants/[release|debug]/res/strings.xml。还有其他我想更改的内容!


编辑:使用res.srcDir添加到数组,而不是完全重新定义它。
Pierre-Luc Paour,

是的,我现在也已经知道了。非常感谢
Alexander Kulyakhtin

1
一个应该在哪里添加sourceSets块?是在android{...}街区下吗?
Abel Callejo

确实在该android区块内有@AbelMelquiadesCallejo 。
Pierre-Luc Paour '18

259

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

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

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

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

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

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


9
这就像一个咒语,但是有一个问题:添加这样的字符串资源时,如何为其他语言环境添加本地化的字符串?
AndroidMechanic-Viral Patel

在这里发布了对此的问题:stackoverflow.com/questions/36105494/…您介意看看吗?
AndroidMechanic-Viral Patel'Mar

3
如何使用多个尺寸维度?如何为每种风味/风味组合命名不同?
Zocket

1
一切都很好,但是启动器图标下方显示的“应用程序名称”并没有按照gradle产品风格设置进行更改。我从strings.xml中删除了“ app_name”,并设置了产品风格。如果我从android的“应用信息”页面中看到了应用名称,则显示了由产品口味设置的应用名称,但在启动器图标下显示了我以前的应用名称。
iamcrypticcoder

2
您正在使用@ mahbub.kuet作为@string/app_name启动器activity标签吗?请记住,优先使用label来自主启动器activityapplication label,而不是应用程序显示名称的。
user650881

13

如果要以不同的方式维护应用程序名称的本地化,则可以按以下步骤实现:

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

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

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

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

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

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

}

4)为中的每个字符串(defaultName,flavor1,flavor2)添加字符串资源strings.xml。这将允许您本地化它们。


步骤#2必须处于build.gradle的'defaultConfig'级别,而不是'android'级别,否则您将收到与manifestPlaceholders名称相关的未知属性错误。
布伦登·怀特利

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

1
这比在gradle文件中声明更好。奇迹般有效。谢谢。
Filip Luchianenco

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>

编译器将合并清单,您可以为每种口味添加一个图标。


4

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


2

首先,回答以下问题:“用户可以在同一设备上安装两种版本的应用程序吗?”

我使用修补源代码的Python脚本。它包含一些可重用的功能,并且当然知道在此特定项目中需要修补的内容。因此,脚本是特定于应用程序的。

修补程序很多,用于修补的数据保存在Python字典中(包括应用程序包名称,它们的BTW与Java包名称不同),每种口味一个字典。

至于l10n,字符串可能指向其他字符串,例如在我的代码中,我有:

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

我认为用户可能会同时拥有Light vs Pro版本
Alexander Kulyakhtin

然后,您将必须更改应用程序包名称,例如com.example.mysoft.procom.example.mysoft.light,否则用户将只能在同一设备上安装其中一个。
13446744073709551615 2013年

我做到了,但是如何在电话菜单中获得“我的应用程序”与“我的应用程序专业版”?我现在有2个应用程序(light和pro),但是名称相同。我确实需要2个不同的应用程序名称,这就是您所说的不容易吗?
2013年

正如另一个(被否决的)答案提到的那样,在AndroidManifest.xml中有<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >。清理并重新构建所有内容(两次,每种口味一次)后,您应该获得两个具有不同android软件包名称和不同启动器标签的apk-s。顺便说一句,Eclipse通常不会检测到资源的变化,因此您必须要求它进行清理。
18446744073709551615

我如何使字符串/ app_name的每种口味不同?对不起,我还是听不懂。
亚历山大·库里亚赫汀

0

我如何使字符串/ app_name的每种口味不同?

我想编写一个更新,但意识到它比原始答案要大,因为我使用修补源代码的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

-4

在AndroidManifest文件的application标签中,您具有以下这一行:

android:label

您可以说如何在设备上的应用程序菜单中显示应用程序标签


是的,我读过这个问题...您可以设置2个分支,每个分支(一个用于flavour1,一个用于flavour2)在您的AndroidManifest文件中设置不同的android:label。
杀手》

6
啊,我不知道。我如何放置这两个清单文件?我虽然不可能
亚历山大·库里亚赫汀
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.