在Gradle中使用构buildtypes来运行在一台设备上使用ContentProvider的相同应用程序
我已经设置Gradle添加包名称后缀到我的debugging应用程序,所以我可以有我使用和debugging版本在一个手机上的发行版本。 我引用这个: 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]
我知道这是因为两个应用程序(发行版和debugging版)注册了相同的ContentProvider权限。
我看到一个可能性来解决这个问题。 如果我理解正确,你应该能够指定不同的文件来build设时使用。 然后,我应该能够将不同的权限放在不同的资源文件中(并且从Manifest设置权限作为string资源),并告诉Gradle使用不同的资源进行debugging构build。 那可能吗? 如果是,那么关于如何实现这一点的提示将是非常棒的!
或者也许有可能使用Gradle直接修改Manifest? 任何其他解决scheme,如何在一台设备上运行与ContentProvider相同的应用程序总是受欢迎的。
现在的答案都没有让我满意,但是自由已经接近了。 所以我就是这么做的 首先,我正在与之合作:
- Android Studio Beta 0.8.2
- Gradle插件0.12。+
- Gradle 1.12
我的目标是使用同一个ContentProvider
在同一个设备上运行Debug
版本和Release
版本。
在你的应用程序的build.gradle后缀的debugging版本:
buildTypes { debug { applicationIdSuffix ".debug" } }
在AndroidManifest.xml文件中设置你的ContentProvider
android:authorities
属性:
<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
而已! 它会像魅力一样工作。 如果您使用SyncAdapter,请继续阅读!
SyncAdapter更新(14.11.2014)
我再次从我目前的设置开始:
- Android Studio Beta 0.9.2
- Gradle插件0.14.1
- Gradle 2.1
基本上,如果你需要为不同的构build定制一些值,你可以从build.gradle文件中完成:
- 使用buildConfigField从
BuildConfig.java
类访问它 - 使用resValue从资源,例如@ string / your_value来访问它
作为资源的替代方法,您可以创build单独的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 / authority
<?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 +空格)不适用于这些生成的资源,因此您必须手动input它们
新的Android构build系统提示:ContentProvider权限重命名
我猜你们都听说过新的基于Android Gradle的构build系统。 说实话,这个新的构build系统比前一个系统向前迈进了一大步。 这还不是最终的(截至撰写本文时为止,最新的版本是0.4.2),但是您已经可以在大多数项目中安全地使用它。
我已经把我的大部分项目转换到这个新的构build系统,并且由于在某些特定情况下缺乏支持而出现了一些问题。 其中之一是对ContentProvider权限重命名的支持
新的Android构build系统可以让您在构build时只需修改软件包名称即可处理不同types的应用程序。 这种改进的主要优势之一是,您现在可以同时在同一设备上安装两个不同版本的应用程序。 例如:
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" } } }
使用这样的Gradleconfiguration,你可以组装两个不同的APK:
•包含com.cyrilmottier.android.app.debug包名的debuggingAPK•包含com.cyrilmottier.android.app包的发行版APK
唯一的问题是你将无法同时安装两个APK,如果他们都暴露一个ContentProvider与相同的权限。 从逻辑上来说,我们需要根据当前的构buildtypes来重新命名权限……但是Gradle构build系统不支持这个function(但是我相信它很快就会被修复)。 所以这里有一条路要走:
首先,我们需要将提供者Android清单ContentProvider声明移动到适当的构buildtypes。 为了做到这一点,我们只需要:
SRC /debugging/ 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不知道如何合并具有相同名称但具有不同权限的ContentProvider。
最后,我们可能需要访问代码中的权限。 这可以使用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
虽然Cyril的例子工作得很好,如果你只有一些构buildtypes,如果你有很多不同的构buildtypes和/或产品风格,它会很快变得复杂,因为你需要维护许多不同的AndroidManifest.xml。
我们的项目由3种不同的构buildtypes和6种不同的构build方式组成,所以我们增加了对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) } }
示例代码可以在这里find: https : //gist.github.com/cmelchior/6988275
由于插件的版本是0.8.3(实际上是0.8.1,但工作不正常),您可以在构build文件中定义资源,因此这可能是一个更清洁的解决scheme,因为您不需要创buildstring文件,也不需要额外的debugging/发布文件夹。
的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>
我不知道有没有人提到它。 实际上,在Android的gradle插件0.10+之后,清单合并将提供官方对这个函数的支持: 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
在代码中使用xml中的${applicationId}
占位符和BuildConfig.APPLICATION_ID
。
您将需要扩展构build脚本以在清单以外的xml文件中启用占位符。 您可以使用每个构build版本的源代码目录来提供不同版本的xml文件,但维护将很快变得麻烦。
AndroidManifest.xml中
您可以使用清单中开箱即用的applicationId占位符。 声明你的提供者是这样的:
<provider android:name=".provider.DatabaseProvider" android:authorities="${applicationId}.DatabaseProvider" android:exported="false" />
请注意${applicationId}
位。 在构build时,这将replace为正在构build的构build变体的实际applicationId。
在代码中
您的ContentProvider需要在代码中构build授权string。 它可以使用BuildConfig类。
public class DatabaseContract { /** The authority for the database provider */ public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".DatabaseProvider"; // ... }
请注意BuildConfig.APPLICATION_ID
位。 它是一个生成的类,具有正在构build的构build变体的实际applicationId。
res / xml /文件,例如syncadapter.xml,accountauthenticator.xml
如果要使用同步适配器,则需要在res / xml /目录中的xml文件中为ContentProvider和AccountManager提供元数据。 applicationId占位符在这里不受支持。 但是你可以自己扩展构build脚本来破解它。
<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脚本中应用额外的构build脚本。 Android gradle插件下方是个好地方。
apply plugin: 'com.android.application' apply from: './build-processApplicationId.gradle' android { compileSdkVersion 21 // etc.
集结processApplicationId.gradle
以下是res / xml / placeholder构build脚本的源代码。 一个更好的文档版本可以在github上find 。 欢迎改进和扩展。
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中
在我看来,没有必要为资源string添加占位符支持。 对于上述用例,至less不需要。 但是,您可以轻松地将脚本更改为不仅replaceres / xml /目录中的占位符,而且还将其replace为res / values /目录中的占位符。
我宁愿喜欢西里尔和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>
基于@ChristianMelchior的样本,这是我的解决scheme,它解决了以前解决scheme中的两个问题:
-
在build目录中更改values.xml的解决scheme会导致资源的完全重build(包括所有drawable的适配)
-
由于不明原因,IntelliJ(也可能是Android Studio)不能可靠地处理资源,导致构build包含未replace的
.res-auto
提供程序权限
这个新的解决scheme通过创build一个新的任务来执行更多的Gradle方法,并通过定义input和输出文件来允许增量构build。
-
创build一个文件(在我把它放在一个
variants
目录中),格式化为一个资源XML文件,其中包含string资源。 这些将被合并到应用程序的资源中,值中的任何.res-auto
将被replace为变体的包名称,例如<string name="search_provider">.res-auto.MySearchProvider</string>
-
从这个要点添加
build_extras.gradle
文件到您的项目,并从主build.gradle
通过添加apply from: './build_extras.gradle'
在android
块之上的某个地方 -
请确保通过将其添加到
build.gradle
的android.defaultConfig
块来设置默认包名称 -
在
AndroidManifest.xml
和其他configuration文件(例如自动完成search提供程序的xml/searchable.xml
)中,引用提供者(例如@string/search_provider
) -
如果您需要获取相同的名称,则可以使用
BuildConfig.PACKAGE_NAME
variables,例如BuildConfig.PACKAGE_NAME + ".MySearchProvider"
https://gist.github.com/paour/9189462
更新:此方法仅适用于Android 2.2.1及更高版本。 对于早期的平台,看到这个答案 ,它有自己的问题,因为新的清单合并仍然是非常粗糙的边缘…
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;
我已经写了一个Github示例项目的博客post,以与Cyril稍有不同的方式处理这个问题(和其他类似的问题)。
http://brad-android.blogspot.com/2013/08/android-gradle-building-unique-build.html
不幸的是,Android插件的当前版本(0.4.1)似乎没有提供一个很好的解决scheme。 我还没有时间来尝试这个,但是对于这个问题可能的解决方法是使用stringresource @string/provider_authority
,并在manifest: android:authority="@string/provider_authority"
。 然后在每个构buildtypes的res文件夹中都有一个res/values/provider.xml
文件,这个文件夹应该覆盖权限,在你的情况下,这将是src/debug/res
我已经研究过生成xml文件,但是在当前版本的插件中似乎没有任何好的钩子。 尽pipe如此,我build议提出一个function请求,我可以想象更多的人会遇到同样的问题。
这篇文章的答案适用于我。
我使用3种不同的口味,所以我创build了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>
为什么不添加这个?
type.packageNameSuffix =“。$ type.name”
我的解决scheme是在AndroidManifest.xml
使用占位符replace。 它还处理packageNameSuffix
属性,因此您可以在同一设备上进行debug
和release
以及任何其他自定义构build。
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') }
如果你想看看它是否会在以后发展的话,我也会把它写出来。
我发现这是比多种资源和XMLparsing方法更优雅的方法。