Android Studio两种不同清单文件的两个flavors

87
我在Android Studio中为我的flavors定义两个不同的清单文件时遇到了问题。这是我当前的项目结构:

Current project structure

free flavor中的AndroidManifest.xml如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="se.example.package">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>

main版本中的AndroidManifest.xml文件没有使用权限,但包含了所有版本共享的其他清单代码。

pro版本中的AndroidManifest.xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="se.example.package">
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
</manifest>

build.gradle定义了两种flavor,例如:

productFlavors {
    free {
        applicationId 'se.example.package.free'
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName '1.0'
    }
    pro {
        minSdkVersion 14
        applicationId 'se.example.package.pro'
        targetSdkVersion 21
        versionCode 2
        versionName '1.1'
    }
}

我期望的结果是不同的 flavor 定义了不同的 uses-permission 权限,但事实并非如此。目前的结果是两个 flavor 都只定义了在 pro flavor 的 AndroidManifest.xml 中定义的 。
我已经尝试过:
- 清理项目 - 重新构建项目 - 重启 Android Studio - 同步 Gradle 但都没有成功。我该怎么解决? 感谢任何帮助。
编辑1:
我将每个 flavor 的 AndroidManifest.xml 文件的位置从各自的 res 文件夹更改为 free 和 pro 文件夹。这样做的结果是:
- Pro flavor 显示了预期的许可证权限。 - 免费 flavor 显示了来自两个 AndroidManifest.xml 文件的权限:许可证和网络权限(应该只有网络权限)。
这感觉像是一个项目结构的问题。怎么解决?
编辑2:
我按照 Commonsware 的提示提取了合并报告,以下是与 uses-permissions 相关的报告:
Free:
uses-permission#com.android.vending.CHECK_LICENSE
ADDED from qwknoteGIT:licencing-library:unspecified:26:5
    android:name
        ADDED from qwknoteGIT:licencing-library:unspecified:26:22

专业:

uses-permission#com.android.vending.CHECK_LICENSE
MERGED from qwknoteGIT:licencing-library:unspecified:26:5

1
查看 app/build/output/apk/ 中的清单合并报告,了解它们告诉你什么。 - CommonsWare
我将每个口味的AndroidManifest.xml文件从各自的res文件夹中移动到了free和pro文件夹中 - 这就是它们应该在的地方。清单文件位于源集的根目录中,无论它是main、一个口味的源集还是一个构建类型的源集。"这意味着什么?" - 我重申之前的建议:查看app/build/output/apk/中的清单合并报告,并查看它们告诉您的内容。 - CommonsWare
我从未进行过权限合并,但是一些 tools:node 应该可以。请查看我发布的链接。也许将所有权限添加到主清单中,并从各个文件中使用 <permission android:name="name" tools:node="remove" 删除不需要的权限。 - Budius
1
你的问题来自于一个库,而不是你的flavors。具体来说,qwknoteGIT:licencing-library正在请求CHECK_LICENSE。如果你没有在所有flavors中使用该库,请使用带有flavor的compile语句(例如proCompile)仅在该flavor中使用该库。 - CommonsWare
@Marcus,你能不能也帮我看一下这个问题:https://dev59.com/eGgMtIcB2Jgan1znLpyf - Edgar
显示剩余6条评论
7个回答

67

技术背景:

在这个链接上,它解释了可以用于清单合并的技术和参数:https://developer.android.com/studio/build/manage-manifests#merge_rule_markers

其中一个特定的是tools:node,它指出合并时应如何处理清单上某些XML节点。

解决方案:

为了在一个清单中实现某些权限,在其他清单中添加所有需要的权限到main中,然后在不需要的flavors清单中移除不需要的权限,就像下面的例子一样:

free删除检查许可证

<uses-permission
   android:name="com.android.vending.CHECK_LICENSE" 
   tools:node="remove"/>

18
为什么不能将android:name="com.android.vending.CHECK_LICENSE"只添加到单个“专业版”清单中,而不是将其添加到主清单并从“免费”版本中删除? - Rajkiran

25

你的问题出现在一个库中,而不是你的flavors。具体来说,qwknoteGIT:licencing-library正在请求CHECK_LICENSE

如果你没有在所有的flavors中使用该库,则可以使用特定于flavor的compile语句(例如proCompile)仅在该flavor中使用该库。

如果你为所有的flavors都使用该库,但是对于某个flavor感到自信,认为自己不需要该权限,那么可以在该flavor的清单文件中使用tools:node属性来阻止库提供的该权限。

并且清单合并报告是你的朋友。 :-)


非常感谢您的努力,虽然我不能接受两个答案,但是您提供了很好的解释和可行的解决方案。+1 - Marcus
@Marcus,您可以更改已接受的答案。在我看来,这个答案应该被接受。 - Ely

13
这应该至少能解决问题。我发现在指定每个变体使用的确切清单方面很有用。干杯!它明确指向每个变体文件夹下的清单文件。
    android {
      productFlavors {
        prod {
          manifest.srcFile "prod/AndroidManifest.xml"
        }
        dev {
          manifest.srcFile "dev/AndroidManifest.xml"
        }
      }
      ...

}

7
不需要指定AndroidManifest.xml文件的路径,Gradle会自动从口味文件夹中获取它们,除非您更改了其默认路径(我不建议这样做)。 - GoRoS
3
当仍然使用Maven风格的项目布局时,这个工具仍然是有用的。 - Nicolas Cornette
是的,@GoRos,就像我说的那样,当您需要指定确切的路径时,这非常有用。人们有各种各样的原因需要这样做。 - Otieno Rowland
@OtienoRowland 我尝试了你的答案,但它没有起作用,也许你可以查看一下我的帖子 https://dev59.com/eGgMtIcB2Jgan1znLpyf - Edgar

6

在您的应用程序build.gradle文件中,专门在sourceSets下指定您的清单文件。

 android {
    productFlavors {
                bizdartFlavourNoCallLog {
            minSdkVersion 16
            applicationIdSuffix '.bizdart'
            targetSdkVersion 26
            dimension "tier"
            sourceSets {
                main {
                    manifest.srcFile "src/bizdartFlavourNoCallLog/AndroidManifest.xml"
                }
            }
            copy {
                from 'src/bizdartFlavourNoCallLog/'
                include '*.json'
                into '.'
                }
            }
       }
    }

5

请参阅带有参数tools:node="merge"https://developer.android.com/studio/build/manifest-merge

高优先级清单(免费):

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge">
</activity>

低优先级清单(主要):
<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

合并清单结果:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

1

你应该修改你的代码:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="se.example.package">

for:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.your.appid">

0

我遇到了同样的问题,后来发现是因为我把“pro”和“tree”风味文件夹放在了lib项目下,将这些风味文件夹移动到app项目下后问题得以解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接