Gradle配置详解系列(四)--巧用manifestPlaceholders实现多渠道打包

3,223 阅读2分钟
引言

为满足产品运营需要,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开发技能。