Android Gradle 替换清单中某个值的包名称

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21109019/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:00:19  来源:igfitidea点击:

Android Gradle replace Package name for a value in manifest

androidgradle

提问by DArkO

I am using Gradle with Product flavors where I set a different package name for each one.

我将 Gradle 与产品风格一起使用,我为每个风格设置了不同的包名称。

productFlavors {

    appone {
        packageName "com.dg.app1"
    }

    apptwo {
        packageName "com.dg.app2"
    }

    appthree {
        packageName "com.dg.app3"
    }

    appfour {
        packageName "com.dg.app4"
    }

}

I need to be able to replace the package name inside the manifest for each corresponding app.

我需要能够为每个相应的应用程序替换清单中的包名称。

My manifest has this:

我的清单有这个:

<receiver android:name="com.parse.GcmBroadcastReceiver"
          android:permission="com.google.android.c2dm.permission.SEND">
  <intent-filter>
    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

    <category android:name="com.dg.example" />
  </intent-filter>
</receiver>

So I need to replace com.dg.example for each app flavor's package name. What is the best way to do this?

所以我需要为每个应用程序风格的包名替换 com.dg.example 。做这个的最好方式是什么?

回答by Kevin Coppock

Gradle Plugin v0.12 and higher:

Gradle 插件 v0.12 及更高版本:

Use ${applicationId}instead of ${packageName}.

使用${applicationId}代替${packageName}

Gradle Plugin v0.11 and higher:

Gradle 插件 v0.11 及更高版本:

As of v0.11, you no longer need to specify not to use the old manifest merger.

从 v0.11 开始,您不再需要指定不使用旧的清单合并。

Gradle Plugin v0.10 and higher:

Gradle 插件 v0.10 及更高版本:

Assuming you're using version 0.10 or higher, this is now officially supported:

假设您使用的是 0.10 或更高版本,现在正式支持:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        // Make sure this is at least 0.10.+
        classpath 'com.android.tools.build:gradle:0.10.+'
    }
}

As of v0.10, you'll also have to manually enable the new manifest merger, although I'd expect that requirement to go away in a version or two whenever the new merger becomes the default:

从 v0.10 开始,您还必须手动启用新的清单合并,尽管我希望只要新合并成为默认值,该要求就会在一两个版本中消失:

android {
    useOldManifestMerger false
}

Then, just use ${packageName}anywhere in AndroidManifest.xmlthat you would normally hardcode the package name. For example:

然后,只需${packageName}AndroidManifest.xml您通常对包名称进行硬编码的任何地方使用即可。例如:

<category android:name="my.package.name"/>

would become

会成为

<category android:name="${packageName}"/>

<category android:name="${packageName}"/>



Gradle Plugin v0.9 and below:

Gradle 插件 v0.9 及以下:

So, referencing this post, it appears this is not yet officially supported through Gradle. A simple workaround is the following:

因此,参考这篇文章,似乎 Gradle 尚未正式支持此功能。一个简单的解决方法如下:

  1. Replace the package name with a custom tag (e.g. <category android:name="my.package.name"/>becomes <category android:name="_PACKAGENAME_"/>
  2. Add the following to your build.gradle, under the androidscope:
  1. 用自定义标签替换包名(例如<category android:name="my.package.name"/>变成<category android:name="_PACKAGENAME_"/>
  2. 将以下内容添加到您的build.gradle,android范围内:


applicationVariants.all { variant ->
    // After processing the manifest, replace all instances of your tag
    // with the variant's actual package name.
    variant.processManifest << {
        def manifestOutFile = variant.processManifest.manifestOutputFile
        def newFileContents = manifestOutFile.getText('UTF-8').replace("_PACKAGENAME_", variant.packageName)
        manifestOutFile.write(newFileContents, 'UTF-8')
    }
}

回答by maiatoday

To do something like this, I use buildTypes in my gradle file but I am pretty sure this will work with flavours as well. For me I am trying to set the label field in the activities.

为了做这样的事情,我在我的 gradle 文件中使用了 buildTypes,但我很确定这也适用于口味。对我来说,我正在尝试在活动中设置标签字段。

I have a strings xml file for each of my buildTypes. Then I have a sourceSet for each buildType which includes the correct strings file. Then in the manifest I do not use a hard coded string but rather "@string/my_var" which will pull the correct string depending on how the sourceSets are defined.

我的每个 buildType 都有一个字符串 xml 文件。然后我为每个 buildType 都有一个 sourceSet,其中包含正确的字符串文件。然后在清单中,我不使用硬编码字符串,而是使用“@string/my_var”,它将根据 sourceSet 的定义方式提取正确的字符串。

This google+ postand related gistmay help.

这个google+ 帖子相关要点可能会有所帮助。

Something else to do is to put a AndroidManifest.xml file into the src/flavour which only contains the bits which are relevant to each flavour. Then take those bits out of the main manifest file. At build time the Manifest files will be merged into one file. You can see the result all of the merged manifests in build/manifests.

要做的其他事情是将 AndroidManifest.xml 文件放入 src/flavor 中,该文件仅包含与每种风味相关的位。然后从主清单文件中取出这些位。在构建时,清单文件将合并为一个文件。您可以在 build/manifests 中看到所有合并清单的结果。

回答by Saad Farooq

I had the same problem and implemented a placeholder replace method in Gradle. It does exactly what you'd expect but also takes care about packageNameSuffixattributes so you can have debugand releaseas well as any other custom builds on the same device.

我遇到了同样的问题并在 Gradle 中实现了一个占位符替换方法。它确实你期望什么,但也需要关心packageNameSuffix属性,所以你可以有debugrelease,以及任何其他自定义建立在同一设备上。

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

I have it up on a gisttoo if you want to see if it evolves later.

gist如果你想看看它是否会在以后发展,我也有它。

I found to be a more elegant approach than the multiple resources and XML parsing approaches.

我发现这是一种比多资源和 XML 解析方法更优雅的方法。

回答by Ilya Gazman

Option Gradle:

选项摇篮:

Use grade attributesAPI. Some thing like this

使用成绩属性API。像这样的事情

manifest.attributes(["attr1":"value1", "attr2":"value2"])

Option 1

选项1

How about converting your project to Android - library project, and making extra project for each company. Than you can edit the Manifestfile as you wish.

如何将您的项目转换为 Android - 库项目,并为每个公司制作额外的项目。您可以根据需要编辑Manifest文件。

Option 2

选项 2

Write a batch file.

写一个批处理文件。