Android官方多渠道方案详解

640?wx_fmt=jpeg


640?wx_fmt=png

魏子翔,2017年加入去哪儿网技术团队,目前在平台事业部/大前端技术中心,主要负责Android平台的基础框架和跨端混合应用方向研发。关注前沿技术,热爱分享,拥抱开源。

简介

实际应用开发中,不可避免的会接触到多渠道打包,不过其实大家常用的多渠道打包其实分为两种。第一:只是需要简单的渠道标识,然后通过标识代码里做一些必要的逻辑处理,这种情况现在网上有很多开源的方案,可以做到快速打包,这里就不在多做介绍了。第二:需要对代码、资源、依赖、配置等做到更深度的定制,比如为不同的应用市场设置不同的启动页和 Logo,这种情况就可以采用官方的 ProductFlavors,下面也会详细介绍这种方案。 简单总结下这两种方案,第一种打包速度快,但是不够灵活,第二种有很强的定制性,但是由于每次回重新编译并签名所以在打包速度上慢很多,大家可以根据需求自由选择不同的方案,或者搭配使用。

方案介绍

构建配置

首先需要在 Module中 的 Build.Gradle 配置你需要的渠道,渠道中可以修改一些 DefaultConfig 中的配置。

 
 
  1. android {

  2.    ···

  3.    defaultConfig {

  4.        minSdkVersion 19

  5.        versionCode 1

  6.        ...

  7.    }

  8.    // 渠道的维度,支持不同维度的渠道

  9.    flavorDimensions "channel"

  10.    productFlavors {

  11.        common {

  12.            dimension "channel"

  13.        }

  14.        xiaomi {

  15.            minSdkVersion '21'

  16.            versionCode 20000  + android.defaultConfig.versionCode

  17.            versionNameSuffix "-minApi21"

  18.            dimension "channel"

  19.        }

  20.        huawei {

  21.            minSdkVersion '23'

  22.            versionCode 20000  + android.defaultConfig.versionCode

  23.            versionNameSuffix "-minApi23"

  24.            dimension "channel"

  25.        }

  26.    }

  27.    buildTypes {

  28.        debug {

  29.            minifyEnabled false

  30.            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

  31.        }

  32.        release {

  33.            minifyEnabled false

  34.            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

  35.        }

  36.    }

  37.    ...

  38. }

Gradle 会通过上面的配置创建维度 * 维度中的渠道 * 构建类型数量的构建变体。在 Gradle 为对应构建变体的 APK 命名时,首先是渠道,之后是构建类型。以上面的构建配置为例,Gradle 可以使用以下命名方案创建共6个构建变体:

构建变体:

 
 
  1. [common, xiaomi, huawei][debug, release]

对应 APK:

 
 
  1. app-[common, xiaomi, huawei]-[debug, release].apk

过滤变体

变体过滤器,以移除某些构建变体配置。

 
 
  1. android {

  2.    ···

  3.    variantFilter { variant ->

  4.        def names = variant.flavors*.name

  5.        def buildTypeName = variant.buildType.name

  6.        println (names + "==" + buildTypeName)

  7.        // 这样就会移除 commonDebug的变体

  8.        if (buildTypeName.contains("debug") && names.contains("common")) {

  9.            setIgnore(true)

  10.        }

  11.    }

  12.    ...

  13. }

Dependencies依赖

现实场景中有的时候不同的渠道,提供的功能也不尽相同,这样就需要对不同的渠道引入不同的组件包(前提App已经进行了组件拆分),如下简单配置就可以实现。

 
 
  1. configurations {

  2.    // Gradle没有提供此细粒度级别的依赖方式,需要自己配置下不然会报错

  3.    xiaomiDebugImplementation {}

  4. }

  5. dependencies {

  6.    implementation fileTree(dir: 'libs', include: ['*.jar'])

  7.    implementation('com.android.support:appcompat-v7:26.1.0')

  8.    // 可以控制 xiaomi渠道下 的 debug 构建类型才去引入此包

  9.    xiaomiDebugImplementation('com.xxx:xxx:1.6.0')

  10.    debugImplementation('com.xxx:xxx:1.6.0')

  11.    commonImplementation('com.xxx:xxx:1.6.0')

  12. }

不同渠道的独立签名

同上面需求,对于功能不同的安装包,大概率是要独立的签名,通过简单的配置一样可以实现,不过对于 Debug 的构建类型,是不支持定制签名的,具体原因未知...

 
 
  1. signingConfigs {

  2.    test11 {

  3.        storeFile file("../test11.keystore")

  4.        storePassword 'test11'

  5.        keyAlias 'test11'

  6.        keyPassword 'test11'

  7.    }

  8.    test22 {

  9.        storeFile file("../test22.keystore")

  10.        storePassword 'test22'

  11.        keyAlias 'test22'

  12.        keyPassword 'test22'

  13.    }

  14. }

  15. // 渠道的维度,支持不同维度的渠道

  16. flavorDimensions "channel"

  17. productFlavors {

  18.    common {

  19.        dimension "channel"

  20.    }

  21.    xiaomi {

  22.        dimension "channel"

  23.    }

  24.    huawei {

  25.        dimension "channel"

  26.    }

  27. }

  28. buildTypes {

  29.    debug {

  30.        //debug定制签名无效 只能指定一个或者使用默认的签名

  31. //            productFlavors.huawei.signingConfig signingConfigs.test11

  32. //            productFlavors.xiaomi.signingConfig signingConfigs.test22

  33. //            productFlavors.common.signingConfig signingConfigs.test11

  34.        minifyEnabled false

  35.        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

  36.    }

  37.    release {

  38.        productFlavors.huawei.signingConfig signingConfigs.test11

  39.        productFlavors.xiaomi.signingConfig signingConfigs.test22

  40.        productFlavors.common.signingConfig signingConfigs.test11

  41.        minifyEnabled false

  42.        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

  43.    }

  44. }

Manifest配置

有时我们需要对 Mainfest 中的某个属性值做些调整,如配置不同渠道数据,App 的 Icon,还有替换声明 Activity 等等,都可以通过下面的配置实现,如果感觉这种简单的调整还不足以满足你的需求,可以看下方的定制源集的方案去深度的定制。

 
 
  1. // build.gradle

  2. android {

  3.    ···

  4.    flavorDimensions "channel"

  5.    productFlavors {

  6.        common {

  7.            dimension "channel"

  8.            manifestPlaceholders = ["ChannelData" : "Common Meta Data",

  9.                                    "AppIcon"     : "@mipmap/ic_common",

  10.                                    "MainActivity":CommonActivity"]

  11.        }

  12.        xiaomi {

  13.            dimension "channel"

  14.            manifestPlaceholders = ["ChannelData" : "XiaoMi Meta Data",

  15.                                    "AppIcon"     : "@mipmap/ic_launcher",

  16.                                    "MainActivity":"XMActivity"]

  17.        }

  18.        huawei {

  19.            dimension "channel"

  20.            manifestPlaceholders = ["ChannelData" : "HuaWei Meta Data",

  21.                                    "AppIcon"     : "@mipmap/ic_launcher",

  22.                                    "MainActivity": "HWActivity"]

  23.        }

  24.    }

  25.    ...

  26. }

  27. // Manifest

  28. <application

  29.    //${AppIcon} 替换AppIcon

  30.    android:icon="${AppIcon}"

  31.    ... >

  32.    //${ChannelData} 替换ChannelData

  33.    <meta-data

  34.        android:name="ChannelData"

  35.        android:value="${ChannelData}"/>

  36.    //${ChannelData} 替换声明Activity

  37.    <activity android:name="${MainActivity}">

  38.        ...

  39.    </activity>

  40. </application>

定制代码,资源Manifest等源集

有时候简单的调整可能不足以解决实际问题,这个时候可以直接定制源集解决问题,找到 youModule\src,当前目录下有个 Main 文件夹为我们工程的核心代码和资源,我们可以在同级下创建不同的渠道目录,如:common``xiaomi 等,此目录可以放置自定义的 Java 代码、Res 资源、AndroidManifest、Assets 等。 不同变体目录(按优先级排列):

 
 
  1. src/commonDebug/(构建变体源集)

  2. src/debug/(buildTypes源集)

  3. src/common/(productFlavors源集)

  4. src/main/(主源集)

上面列出的顺序决定了在 Gradle 合并代码和资源时哪个源集具有较高的优先级。如果 commonDebug/ 和 Debug/ 包含相同的文件,Gradle 将使用 commonDebug/ 源集中的文件。同样,Gradle 会为其他源集中的文件赋予比 Main/ 中相同文件更高的优先级。Gradle 在应用以下构建规则时会考虑此优先级顺序:

对于 Java/ 下的源代码只能有单一的类文件。注:对于给定的渠道目录,如果找到两个或两个以上定义同一 Java 类的源集目录,Gradle 就会引发一个构建错误。例如,在构建调试 APK 时,您不能同时定义src/common/Utility.java&src/main/Utility. java。这是因为 Gradle 会在构建过程中检查这两个目录并引发duplicate class错误。如果针对不同的构建类型需要不同版本的 Utility. java,您可以让每个渠道定义其自己的文件版本,如:src/common/Utility.java &src/xiaomi/Utility.Java,而不将其包含在 Main/ 中。

所有Manifest合并为单个Manifest。将按照上述列表中的相同顺序指定优先级。也就是说,某个构建类型的Manifest设置会替换某个渠道的Manifest设置。同样,Value/ Res/ 和 Asset/ 目录中的如果存在有两个或两个以上的同名资源,比如在渠道中的资源将会替换 Main 中资源,以下对于同时存在于 strings.xml 的同名资源和资源图标做个示例:

 
 
  1. // main 下的 图标资源

  2. main\res\mipmap-hdpi\ic_launcher.png

  3. // 在 xiaomi 下的 图标资源

  4. xiaomi\res\mipmap-hdpi\ic_launcher.png

  5. //打包 xiaomi 渠道的时候会自动替换图片。

 
 
  1. // main 下的 strings.xml

  2. <resource>

  3.    <string name="app_name">MultiChannel</string>

  4.    <string name="string_merge">我是string,没被合并</string>

  5. </resource>

  6. // 在 xiaomi 下的 strings.xml 内容为:

  7. <resource>

  8.    <string name="string_merge">我是xiaomi,已经合并</string>

  9. </resource>

  10. //当打 xiaomi 渠道包时,最终 strings.xml 会变成:

  11. <resource>

  12.    <string name="app_name">MultiChannel</string>

  13.    <string name="string_merge">我是xiaomi,已经合并</string>

  14. </resource>

其他

命令构建

对于习惯于使用命令构建的同学来说有以下几点需要补充

打全部包: gradle assemble。 打全部 Debug 包: gradle assembleDebug,可以简写为 gradle aD 或 aDebug。 打全部 Release 包: gradle assembleRelease,可以简写为 gradle aR 或 aRelease。 打指定 flavor 包: gradle assemble(flavor)(Debug|Release),如:gradle assembleXiaomiDebug。 打包完成后安装: gradle install(flavor)(Debug|Release),如:gradle installXiaomiDebug。 打包前先 clean 一下,在测试的时候很必要: gradle clean assembleXiaomiDebug。

参考阅读

推荐:官方文档 http://android.jobbole.com/84752/ https://juejin.im/post/58be7b8dac502e006c28869

640?wx_fmt=jpeg

640?wx_fmt=jpeg



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值