引言
为满足产品运营需要,APP多渠道打包是必须的,所以Android多渠道打包是所有Android程序员绕不过去的路, 今天就使用AndroidManifest占位符及gradle的相关配置实现Android多渠道打包。\
以友盟统计为例,友盟会要求我们在在AndroidManifest文件中指定渠道名称。
<meta-data android:value="Channel ID" android:name="UMENG_CHANNEL"/>
示例中的Channel ID我们要替换成不同渠道的名称,比如google,huawei,xiaomi等等
-
先来认识下
manifestPlaceholders
manifestPlaceholders是ProductFlavor的一个属性, 它是一个Map<String, Object>类型,所以我们可以同时配置很多个占位符。示例:
android { productFlavors { huawei { manifestPlaceholders.put("UMENG_CHANNEL","huawei") } xiaomi { manifestPlaceholders.put("UMENG_CHANNEL","xiaomi") } ...(此处可以配置N个渠道信息) } } -
AndroidManifest 中以
UMENG_CHANNEL为占位符,在构建的时候, 它会把AndroidManifest文件文件中所有占位符变量为UMENG_CHANNEL 的内容替换为我们manifestPlaceholders中对应的value值
示例:
<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.zdream.app"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Black">
<meta-data android:value="${UMENG_CHANNEL}" android:name="UMENG_CHANNEL"/>
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
看到以上示例中的meta-data标签了吗?其中${UMENG_CHANNEL}就是一个占位符,
它的变量名是UMENG_CHANNEL。构建的时候${UMENG_CHANNEL}将会被替换为builde.gradle中配置的相关值,
比如xiaomi,huawei等等。
- 现在我们运行
./gradlew app:assembleXiaomiRelease,当然也可以直接用AS build, 打一个小米渠道的包,然后通过apktool反编译,可以看到AndroidManifest文件中的${UMENG_CHANNEL}已经被替换为了xiaomi。
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.zdream.app"
platformBuildVersionCode="23"
platformBuildVersionName="6.0">
<application android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Black">
<meta-data android:name="UMENG_CHANNEL" android:value="xiaomi"/>
<activity android:label="@string/title_activity_main"
android:name="org.zdream.app.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
- 虽然以上我们已经解决了,定制渠道信息的问题,但是对于整个Android应用市场特别是国内市场五花八门的环境,我们是不是要重复上面的代码N次呢? 当然不用。 示例:
android {
productFlavors {
huawei {
...
}
xiaomi {
...
}
}
productFlavors.all { flavor ->
manifestPlaceholders.put("UMENG_CHANNEL",name)
}
}
我们通过all函数遍历每一个ProductFlavor, 然后把他们的name作为我们友盟中渠道的名字,非常方便,这里不止可以做这一个事情, 在遍历ProductFlavor的时候,你可以做很多你想做的事情,这就是Gradle的灵活之处,把脚本当成程序写。
Android Gradle为我们提供的manifestPlaceholders占位符的方式, 让我们可以替换AndroidManifest文件中任何${Var}格式的占位符, 所以它的使用场景不限于渠道名这一个,比如其他动态想配置meta信息等等,灵活的运用它能帮助我们做很多事情, 让我们的构建更灵活,更方便。
更多Android技术分享可以关注我的Android技术圈子添码猩球, 也可以加入QQ群号:690347536,学习交流Android开发技能。