我已经设置Gradle将包名称后缀添加到我的调试应用程序中,因此我可以使用我正在使用的发行版本并在一部手机上调试版本。我引用了这个:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Types
我的build.gradle文件如下所示:
...
android
{
...
buildTypes
{
debug
{
packageNameSuffix ".debug"
versionNameSuffix " debug"
}
}
}
在我开始在我的应用中使用ContentProvider之前,一切正常。我明白了:
Failure [INSTALL_FAILED_CONFLICTING_PROVIDER]
我理解这是因为两个应用程序(发布和调试)正在注册相同的ContentProvider权限。
我认为有一种可能性来解决这个问题。如果我理解正确,您应该能够指定构建时使用的不同文件。然后我应该能够将不同的权限放在不同的资源文件中(并从Manifest设置权限作为字符串资源)并告诉Gradle使用不同的资源进行调试构建。那可能吗?如果是,那么关于如何实现这一点的任何提示都会很棒!
或者也许可以使用Gradle直接修改Manifest?关于如何在一台设备上使用ContentProvider运行相同应用程序的任何其他解决方案始终是受欢迎的。
答案 0 :(得分:217)
现有的答案都没有让我满意,但是Liberty很接近。所以我就是这样做的。 首先,我正在与之合作:
我的目标是使用相同的Debug
在同一设备上运行Release
版本和ContentProvider
版本。
在Debug build的应用程序集后缀的 build.gradle 中:
buildTypes {
debug {
applicationIdSuffix ".debug"
}
}
在您android:authorities
的 AndroidManifest.xml 文件集ContentProvider
属性中
<provider
android:name="com.example.app.YourProvider"
android:authorities="${applicationId}.provider"
android:enabled="true"
android:exported="false" >
</provider>
在您的代码设置AUTHORITY
属性中,可以在您的实现中的任何需要位置使用该属性:
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";
提示:BuildConfig.PACKAGE_NAME
之前
我将再次从目前的设置开始:
基本上,如果您需要为不同的构建定制一些值,可以从build.gradle文件中进行:
BuildConfig.java
类作为资源的替代方法,您可以创建单独的buildType或flavor目录,并覆盖其中的XML或值。但是,我不打算在下面的示例中使用它。
在 build.gradle 文件中添加以下内容:
defaultConfig {
resValue "string", "your_authorities", applicationId + '.provider'
resValue "string", "account_type", "your.syncadapter.type"
buildConfigField "String", "ACCOUNT_TYPE", '"your.syncadapter.type"'
}
buildTypes {
debug {
applicationIdSuffix ".debug"
resValue "string", "your_authorities", defaultConfig.applicationId + '.debug.provider'
resValue "string", "account_type", "your.syncadapter.type.debug"
buildConfigField "String", "ACCOUNT_TYPE", '"your.syncadapter.type.debug"'
}
}
您将在 BuildConfig.java 类
中看到结果public static final String ACCOUNT_TYPE = "your.syncadapter.type.debug";
并在 build / generated / res / generated / debug / values / generated.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Automatically generated file. DO NOT MODIFY -->
<!-- Values from default config. -->
<item name="account_type" type="string">your.syncadapter.type.debug</item>
<item name="authorities" type="string">com.example.app.provider</item>
</resources>
在 authenticator.xml 中使用build.gradle文件中指定的资源
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/account_type"
android:icon="@drawable/ic_launcher"
android:smallIcon="@drawable/ic_launcher"
android:label="@string/app_name"
/>
在 syncadapter.xml 中再次使用相同的资源, @ string / authorities
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="@string/authorities"
android:accountType="@string/account_type"
android:userVisible="true"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true"
/>
提示:自动完成(Ctrl + Space)对这些生成的资源不起作用,因此您必须手动输入
答案 1 :(得分:39)
新的Android构建系统提示:ContentProvider权限重命名
我想大家都听说过基于Android Gradle的新构建系统。说实话,这个新的构建系统与前一个相比是一个巨大的进步。它还不是最终的(截至本文撰写时,最新版本为0.4.2)但您已经可以在大多数项目中安全地使用它了。
我个人将我的大部分项目转换为这个新的构建系统并且由于在某些特定情况下缺乏支持而遇到了一些问题。其中之一是对ContentProvider权限重命名的支持
新的Android构建系统允许您通过在构建时修改程序包名称来处理不同类型的应用程序。这种改进的主要优点之一是您现在可以在同一设备上同时安装两个不同版本的应用程序。例如:
android {
compileSdkVersion 17
buildToolsVersion "17.0.0"
defaultConfig {
packageName "com.cyrilmottier.android.app"
versionCode 1
versionName "1"
minSdkVersion 14 // Listen to +Jeff Gilfelt advices :)
targetSdkVersion 17
}
buildTypes {
debug {
packageNameSuffix ".debug"
versionNameSuffix "-debug"
}
}
}
使用这样的Gradle配置,您可以组合两个不同的APK:
•带有com.cyrilmottier.android.app.debug包名称的调试APK •具有com.cyrilmottier.android.app包名称的发布APK
唯一的问题是如果它们都暴露具有相同权限的ContentProvider,您将无法同时安装这两个APK。从逻辑上讲,我们需要根据当前的构建类型重命名权限......但是Gradle构建系统不支持这个(但是?我确定它很快就会被修复)。所以这是一个方法:
首先,我们需要将提供程序Android清单ContentProvider声明移动到适当的构建类型。为此,我们只需:
<强> SRC /调试/ AndroidManifest.xml中强>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cyrilmottier.android.app"
android:versionCode="1"
android:versionName="1">
<application>
<provider
android:name=".provider.Provider1"
android:authorities="com.cyrilmottier.android.app.debug.provider"
android:exported="false" />
</application>
</manifest>
<强>的src /释放/ AndroidManifest.xml中强>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cyrilmottier.android.app"
android:versionCode="1"
android:versionName="1">
<application>
<provider
android:name=".provider.Provider1"
android:authorities="com.cyrilmottier.android.app.provider"
android:exported="false" />
</application>
</manifest>
确保从src / main /中的AndroidManifest.xml中删除ContentProvider声明,因为Gradle不知道如何合并具有相同名称但具有不同权限的ContentProviders。
最后,我们可能需要访问代码中的权限。使用BuildConfig文件和buildConfig方法可以非常轻松地完成此操作:
android {
// ...
final PROVIDER_DEBUG = "com.cyrilmottier.android.app.debug.provider"
final PROVIDER_RELEASE = "com.cyrilmottier.android.app.provider"
buildTypes {
debug {
// ...
buildConfigField "String", "PROVIDER_AUTHORITY", PROVIDER_DEBUG
}
release {
buildConfigField "String", "PROVIDER_AUTHORITY", PROVIDER_RELEASE
}
}
}
由于这种解决方法,您可以在ProviderContract中使用BuildConfig.PROVIDER_AUTHORITY并同时安装两个不同版本的应用。
最初在Google+上: https://plus.google.com/u/0/118417777153109946393/posts/EATUmhntaCQ
答案 2 :(得分:23)
虽然Cyril的示例在您只有少量构建类型时效果很好,但如果您有许多构建类型和/或产品风格,则需要维护许多不同的AndroidManifest.xml,这很快就会变得复杂。
我们的项目包含3种不同的构建类型和6种风格,总共18种构建变体,因此我们在ContentProvider权限中添加了对“.res-auto”的支持,它扩展到当前的包名称,无需维护不同的AndroidManifest。 xml
/**
* Version 1.1.
*
* Add support for installing multiple variants of the same app which have a
* content provider. Do this by overriding occurrences of ".res-auto" in
* android:authorities with the current package name (which should be unique)
*
* V1.0 : Initial version
* V1.1 : Support for ".res-auto" in strings added,
* eg. use "<string name="auth">.res-auto.path.to.provider</string>"
*
*/
def overrideProviderAuthority(buildVariant) {
def flavor = buildVariant.productFlavors.get(0).name
def buildType = buildVariant.buildType.name
def pathToManifest = "${buildDir}/manifests/${flavor}/${buildType}/AndroidManifest.xml"
def ns = new groovy.xml.Namespace("http://schemas.android.com/apk/res/android", "android")
def xml = new XmlParser().parse(pathToManifest)
def variantPackageName = xml.@package
// Update all content providers
xml.application.provider.each { provider ->
def newAuthorities = provider.attribute(ns.authorities).replaceAll('.res-auto', variantPackageName)
provider.attributes().put(ns.authorities, newAuthorities)
}
// Save modified AndroidManifest back into build dir
saveXML(pathToManifest, xml)
// Also make sure that all strings with ".res-auto" are expanded automagically
def pathToValues = "${buildDir}/res/all/${flavor}/${buildType}/values/values.xml"
xml = new XmlParser().parse(pathToValues)
xml.findAll{it.name() == 'string'}.each{item ->
if (!item.value().isEmpty() && item.value()[0].startsWith(".res-auto")) {
item.value()[0] = item.value()[0].replace(".res-auto", variantPackageName)
}
}
saveXML(pathToValues, xml)
}
def saveXML(pathToFile, xml) {
def writer = new FileWriter(pathToFile)
def printer = new XmlNodePrinter(new PrintWriter(writer))
printer.preserveWhitespace = true
printer.print(xml)
}
// Post processing of AndroidManifest.xml for supporting provider authorities
// across build variants.
android.applicationVariants.all { variant ->
variant.processManifest.doLast {
overrideProviderAuthority(variant)
}
}
示例代码可在此处找到:https://gist.github.com/cmelchior/6988275
答案 3 :(得分:20)
由于插件版本为0.8.3(实际上是0.8.1,但它没有正常工作),您可以在构建文件中定义资源,因此这可能是一个更清晰的解决方案,因为您不需要创建字符串文件或其他调试/发布文件夹。
<强>的build.gradle 强>
android {
buildTypes {
debug{
resValue "string", "authority", "com.yourpackage.debug.provider"
}
release {
resValue "string", "authority", "com.yourpackage.provider"
}
}
}
<强>的AndroidManifest.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yourpackage"
android:versionCode="1"
android:versionName="1">
<application>
<provider
android:name=".provider.Provider1"
android:authorities="@string/authority"
android:exported="false" />
</application>
</manifest>
答案 4 :(得分:13)
我不知道是否有人提到它。实际上在android gradle插件0.10+之后,manifest merger将为这个函数提供官方支持: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger
在AndroidManifest.xml中,您可以使用$ {packageName},如下所示:
<provider
android:name=".provider.DatabasesProvider"
android:authorities="${packageName}.databasesprovider"
android:exported="true"
android:multiprocess="true" />
在你的build.gradle中你可以拥有:
productFlavors {
free {
packageName "org.pkg1"
}
pro {
packageName "org.pkg2"
}
}
在此处查看完整示例: https://code.google.com/p/anymemo/source/browse/AndroidManifest.xml#152
在这里: https://code.google.com/p/anymemo/source/browse/build.gradle#41
答案 5 :(得分:8)
在xml中使用${applicationId}
占位符,在代码中使用BuildConfig.APPLICATION_ID
。
您需要扩展构建脚本以在清单以外的xml文件中启用占位符。您可以使用每个构建变体的源目录来提供不同版本的xml文件,但维护很快就会变得很麻烦。
<强>的AndroidManifest.xml 强>
您可以在清单中使用开箱即用的applicationId占位符。像这样声明你的提供者:
<provider
android:name=".provider.DatabaseProvider"
android:authorities="${applicationId}.DatabaseProvider"
android:exported="false" />
注意${applicationId}
位。这在构建时被替换为正在构建的构建变体的实际applicationId。
代码
您的ContentProvider需要在代码中构造权限字符串。它可以使用BuildConfig类。
public class DatabaseContract {
/** The authority for the database provider */
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".DatabaseProvider";
// ...
}
注意BuildConfig.APPLICATION_ID
位。它是一个生成的类,其中构建变体的实际applicationId正在构建。
res / xml / files,例如syncadapter.xml,accountauthenticator.xml
如果要使用同步适配器,则需要在res / xml /目录的xml文件中为ContentProvider和AccountManager提供元数据。此处不支持applicationId占位符。但是你可以自己扩展构建脚本来破解它。
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="${applicationId}"
android:allowParallelSyncs="false"
android:contentAuthority="${applicationId}.DatabaseProvider"
android:isAlwaysSyncable="true"
android:supportsUploading="true"
android:userVisible="true" />
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="${applicationId}"
android:icon="@drawable/ic_launcher"
android:label="@string/account_authenticator_label"
android:smallIcon="@drawable/ic_launcher" />
再次注意${applicationId}
。这仅适用于将以下gradle脚本添加到模块的根目录并从build.gradle应用它。
<强>的build.gradle 强>
从模块build.gradle脚本应用额外的构建脚本。一个好地方在Android gradle插件下面。
apply plugin: 'com.android.application'
apply from: './build-processApplicationId.gradle'
android {
compileSdkVersion 21
// etc.
<强>集结processApplicationId.gradle 强>
以下是res / xml / placeholder构建脚本的工作源代码。 github上提供了更好的文档版本。欢迎改进和扩展。
def replace(File file, String target, String replacement) {
def result = false;
def reader = new FileReader(file)
def lines = reader.readLines()
reader.close()
def writer = new FileWriter(file)
lines.each { line ->
String replacedLine = line.replace(target, replacement)
writer.write(replacedLine)
writer.write("\n")
result = result || !replacedLine.equals(line)
}
writer.close()
return result
}
def processXmlFile(File file, String applicationId) {
if (replace(file, "\${applicationId}", applicationId)) {
logger.info("Processed \${applicationId} in $file")
}
}
def processXmlDir(File dir, String applicationId) {
dir.list().each { entry ->
File file = new File(dir, entry)
if (file.isFile()) {
processXmlFile(file, applicationId)
}
}
}
android.applicationVariants.all { variant ->
variant.mergeResources.doLast {
def applicationId = variant.mergedFlavor.applicationId + (variant.buildType.applicationIdSuffix == null ? "" : variant.buildType.applicationIdSuffix)
def path = "${buildDir}/intermediates/res/${variant.dirName}/xml/"
processXmlDir(new File(path), applicationId)
}
}
<强>的strings.xml 强>
在我看来,没有必要为资源字符串添加占位符支持。对于上述用例,至少不需要它。但是,您可以轻松地将脚本更改为不仅替换res / xml /目录中的占位符,还替换res / values /目录中的占位符。
答案 6 :(得分:6)
我宁愿选择Cyril和rciovati之间的混合物。我认为更简单,你只有两个修改。
build.gradle
看起来像:
android {
...
productFlavors {
production {
packageName "package.name.production"
resValue "string", "authority", "package.name.production.provider"
buildConfigField "String", "AUTHORITY", "package.name.production.provider"
}
testing {
packageName "package.name.debug"
resValue "string", "authority", "package.name.debug.provider"
buildConfigField "String", "AUTHORITY", "package.name.debug.provider"
}
}
...
}
AndroidManifest.xml
:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="package.name" >
<application
...>
<provider android:name=".contentprovider.Provider" android:authorities="@string/authority" />
</application>
</manifest>
答案 7 :(得分:5)
gradle.build
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.example.awsomeapp"
minSdkVersion 9
targetSdkVersion 23
versionCode 1
versionName "1.0.0"
}
productFlavors
{
prod {
applicationId = "com.example.awsomeapp"
}
demo {
applicationId = "com.example.awsomeapp.demo"
versionName = defaultConfig.versionName + ".DEMO"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
debuggable false
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
applicationIdSuffix ".debug"
versionNameSuffix = ".DEBUG"
debuggable true
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
// rename the apk
def file = output.outputFile;
def newName;
newName = file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk");
newName = newName.replace(project.name, "awsomeapp");
output.outputFile = new File(file.parent, newName);
}
//Generate values Content Authority and Account Type used in Sync Adapter, Content Provider, Authenticator
def valueAccountType = applicationId + '.account'
def valueContentAuthority = applicationId + '.authority'
//generate fields in Resource string file generated.xml
resValue "string", "content_authority", valueContentAuthority
resValue "string", "account_type", valueAccountType
//generate fields in BuildConfig class
buildConfigField "String", "ACCOUNT_TYPE", '"'+valueAccountType+'"'
buildConfigField "String", "CONTENT_AUTHORITY", '"'+valueContentAuthority+'"'
//replace field ${valueContentAuthority} in AndroidManifest.xml
mergedFlavor.manifestPlaceholders = [ valueContentAuthority: valueContentAuthority ]
}
}
authenticator.xml
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/account_type"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:smallIcon="@drawable/ic_launcher" />
sync_adapter.xml
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="@string/content_authority"
android:accountType="@string/account_type"
android:userVisible="true"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true"
android:supportsUploading="true"/>
的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.0" package="com.example.awsomeapp">
<uses-permission android:name="android.permission.GET_ACCOUNTS"/><!-- SyncAdapter and GCM requires a Google account. -->
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<!-- GCM Creates a custom permission so only this app can receive its messages. -->
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>
<application....
.......
<!-- Stub Authenticator -->
<service
android:name="com.example.awsomeapp.service.authenticator.CAuthenticatorService"
android:exported="true">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator"/>
</service>
<!-- -->
<!-- Sync Adapter -->
<service
android:name="com.example.awsomeapp.service.sync.CSyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data android:name="android.content.SyncAdapter" android:resource="@xml/sync_adapter" />
</service>
<!-- -->
<!-- Content Provider -->
<provider android:authorities="${valueContentAuthority}"
android:exported="false"
android:name="com.example.awsomeapp.database.contentprovider.CProvider">
</provider>
<!-- -->
</application>
</manifest>
代码:
public static final String CONTENT_AUTHORITY = BuildConfig.CONTENT_AUTHORITY;
public static final String ACCOUNT_TYPE = BuildConfig.ACCOUNT_TYPE;
答案 8 :(得分:4)
基于@ChristianMelchior的样本,这是我的解决方案,它修复了以前解决方案中的两个问题:
更改构建目录中的values.xml的解决方案会导致资源的完全重建(包括所有drawable的aapt)
由于未知原因,IntelliJ(可能还有Android Studio)无法可靠地处理资源,导致构建包含未替换的.res-auto
提供商权限
这个新的解决方案通过创建新任务来完成Gradle方式,并通过定义输入和输出文件来实现增量构建。
创建一个文件(在我把它放在variants
目录中的示例中),格式化为资源xml文件,其中包含字符串资源。这些将合并到应用的资源中,值中.res-auto
的任何出现都将替换为变体的包名称,例如<string name="search_provider">.res-auto.MySearchProvider</string>
将this gist的build_extras.gradle
文件添加到您的项目中,并通过在build.gradle
块上方的某处添加apply from: './build_extras.gradle'
从主android
引用该文件
确保通过将默认包名称添加到android.defaultConfig
build.gradle
块来设置默认包名称
在AndroidManifest.xml
和其他配置文件(例如xml/searchable.xml
中的自动完成搜索提供程序)中,引用提供程序(例如@string/search_provider
)
如果您需要使用相同的名称,可以使用BuildConfig.PACKAGE_NAME
变量,例如BuildConfig.PACKAGE_NAME + ".MySearchProvider"
https://gist.github.com/paour/9189462
<小时/> 更新:此方法仅适用于Android 2.2.1及更高版本。对于早期的平台,请参阅this answer,它有自己的一组问题,因为新的清单合并在边缘仍然非常粗糙...
答案 9 :(得分:3)
我写了一篇关于Github示例项目的博文,解决了这个问题(以及其他类似的问题),与Cyril的方式略有不同。
http://brad-android.blogspot.com/2013/08/android-gradle-building-unique-build.html
答案 10 :(得分:2)
不幸的是,Android插件的当前版本(0.4.1)似乎没有提供一个很好的解决方案。我还没有时间尝试这个,但是这个问题的一个可能的解决方法是使用字符串资源@string/provider_authority
,并在清单中使用它:android:authority="@string/provider_authority"
。然后,您在每个构建类型的res文件夹中都有一个res/values/provider.xml
,它应该覆盖权限,在您的情况下,这将是src/debug/res
我已经考虑过动态生成xml文件,但同样,在当前版本的插件中似乎没有任何好的钩子。我建议输入功能请求,我可以想象会有更多人遇到同样的问题。
答案 11 :(得分:2)
这篇文章的答案对我有用。
我使用了3种不同的口味,所以我在每种口味中创建了3个包含内容提供者的清单,如kevinrschultz所说:
productFlavors {
free {
packageName "your.package.name.free"
}
paid {
packageName "your.package.name.paid"
}
other {
packageName "your.package.name.other"
}
}
您的主要清单不包括提供商:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Permissions -->
<application>
<!-- Nothing about Content Providers at all -->
<!-- Activities -->
...
<!-- Services -->
...
</application>
你的每一种风格都包括提供者。
免:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<application>
<!-- Content Providers -->
<provider
android:name="your.package.name.Provider"
android:authorities="your.package.name.free"
android:exported="false" >
</provider>
</application>
</manifest>
付费:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<application>
<!-- Content Providers -->
<provider
android:name="your.package.name.Provider"
android:authorities="your.package.name.paid"
android:exported="false" >
</provider>
</application>
</manifest>
其他:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<application>
<!-- Content Providers -->
<provider
android:name="your.package.name.Provider"
android:authorities="your.package.name.other"
android:exported="false" >
</provider>
</application>
</manifest>
答案 12 :(得分:0)
为什么不加一下呢?
type.packageNameSuffix =“。$ type.name”
答案 13 :(得分:0)
我的解决方案是在AndroidManifest.xml
中使用占位符替换。它还处理packageNameSuffix
个属性,因此您可以在同一设备上拥有debug
和release
以及任何其他自定义构建。
applicationVariants.all { variant ->
def flavor = variant.productFlavors.get(0)
def buildType = variant.buildType
variant.processManifest.doLast {
println '################# Adding Package Names to Manifest #######################'
replaceInManifest(variant,
'PACKAGE_NAME',
[flavor.packageName, buildType.packageNameSuffix].findAll().join()) // ignores null
}
}
def replaceInManifest(variant, fromString, toString) {
def flavor = variant.productFlavors.get(0)
def buildtype = variant.buildType
def manifestFile = "$buildDir/manifests/${flavor.name}/${buildtype.name}/AndroidManifest.xml"
def updatedContent = new File(manifestFile).getText('UTF-8').replaceAll(fromString, toString)
new File(manifestFile).write(updatedContent, 'UTF-8')
}
如果你想看看它是否会在以后发展,我也会在gist
上完成它。
我发现这是一种比多种资源和XML解析方法更优雅的方法。