Android官方多渠道方案详解

简介

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

方案介绍

构建配置

首先须要在module中的build.gradle配置你须要的渠道,渠道中能够修改一些defaultConfig中的配置android

android {
    ···
    defaultConfig {
        minSdkVersion 19
        versionCode 1
        ...
    }
    
    // 渠道的维度,支持不一样维度的渠道
    flavorDimensions "channel"
    productFlavors {
        common {
            dimension "channel"
        }
        xiaomi {
            minSdkVersion '21'
            versionCode 20000  + android.defaultConfig.versionCode
            versionNameSuffix "-minApi21"
            dimension "channel"
        }
        huawei {
            minSdkVersion '23'
            versionCode 20000  + android.defaultConfig.versionCode
            versionNameSuffix "-minApi23"
            dimension "channel"
        }
    }
    
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    ...
}

复制代码

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

构建变体:[common, xiaomi, huawei][debug, release]
对应 APK:app-[common, xiaomi, huawei]-[debug, release].apkpost

过滤变体

Gradle 会为每一个可能的组合建立构建变体。都在Android Studio -> Build Variants中显示出来,不过某些特定的构建变体在您的项目环境中并没必要要,也可能没有意义。您能够在build.gradle 文件中建立一个变体过滤器,以移除某些构建变体配置。测试

android {
    ···
    variantFilter { variant ->
        def names = variant.flavors*.name
        def buildTypeName = variant.buildType.name
        println (names + "==" + buildTypeName)
        // 这样就会移除 commonDebug的变体
        if (buildTypeName.contains("debug") && names.contains("common")) {
            setIgnore(true)
        }
    }
    ...
}

复制代码

dependencies依赖

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

configurations {
    // Gradle没有提供此细粒度级别的依赖方式,须要本身配置下否则会报错
    xiaomiDebugImplementation {}
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation('com.android.support:appcompat-v7:26.1.0')

    // 能够控制 xiaomi渠道下 的 debug 构建类型才去引入此包
    xiaomiDebugImplementation('com.xxx:xxx:1.6.0')
    debugImplementation('com.xxx:xxx:1.6.0')
    commonImplementation('com.xxx:xxx:1.6.0')
}
复制代码

不一样渠道的独立签名

同上面需求,对于功能不一样的安装包,大几率是要独立的签名,经过简单的配置同样能够实现,不过对于debug的构建类型,是不支持定制签名的,具体缘由未知...ui

signingConfigs {
    test11 {
        storeFile file("../test11.keystore")
        storePassword 'test11'
        keyAlias 'test11'
        keyPassword 'test11'
    }
    test22 {
        storeFile file("../test22.keystore")
        storePassword 'test22'
        keyAlias 'test22'
        keyPassword 'test22'
    }
}
// 渠道的维度,支持不一样维度的渠道
flavorDimensions "channel"
productFlavors {
    common {
        dimension "channel"
    }
    xiaomi {
        dimension "channel"
    }
    huawei {
        dimension "channel"
    }
}
buildTypes {
    debug {
        //debug定制签名无效 只能指定一个或者使用默认的签名
// productFlavors.huawei.signingConfig signingConfigs.test11
// productFlavors.xiaomi.signingConfig signingConfigs.test22
// productFlavors.common.signingConfig signingConfigs.test11
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

    }
    release {
        productFlavors.huawei.signingConfig signingConfigs.test11
        productFlavors.xiaomi.signingConfig signingConfigs.test22
        productFlavors.common.signingConfig signingConfigs.test11
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
复制代码

Manifest配置

有时咱们须要对Mainfest中的某个属性值作些调整,如配置不一样渠道数据,App的Icon,还有替换声明Activity等等,均可以经过下面的配置实现,若是感受这种简单的调整还不足以知足你的需求,能够看下方的定制源集的方案去深度的定制spa

// build.gradle
android {
    ···
    flavorDimensions "channel"
    productFlavors {
        common {
            dimension "channel"
            manifestPlaceholders = ["ChannelData" : "Common Meta Data",
                                    "AppIcon"     : "@mipmap/ic_common",
                                    "MainActivity":CommonActivity"]
        }
        xiaomi {
            dimension "channel"
            manifestPlaceholders = ["ChannelData" : "XiaoMi Meta Data",
                                    "AppIcon"     : "@mipmap/ic_launcher",
                                    "MainActivity":"XMActivity"]
        }
        huawei {
            dimension "channel"
            manifestPlaceholders = ["ChannelData" : "HuaWei Meta Data",
                                    "AppIcon"     : "@mipmap/ic_launcher",
                                    "MainActivity": "HWActivity"]
        }
    }
    ...
}

// Manifest 
<application
    //${AppIcon} 替换AppIcon
    android:icon="${AppIcon}"
    ... >

    //${ChannelData} 替换ChannelData
    <meta-data
        android:name="ChannelData"
        android:value="${ChannelData}"/>

    //${ChannelData} 替换声明Activity
    <activity android:name="${MainActivity}">
        ...
    </activity>
</application>



复制代码

定制代码 资源 Manifest 等源集

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

src/commonDebug/(构建变体源集)
src/debug/(buildTypes源集)
src/common/(productFlavors源集)
src/main/(主源集)
复制代码

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

  • 对于java/ 下的源代码只能有单一的类文件
    注:对于给定的渠道目录,若是找到两个或两个以上定义同一 Java 类的源集目录,Gradle 就会引起一个构建错误。例如,在构建调试 APK 时,您不能同时定义 src/common/Utility.javasrc/main/Utility.java。这是由于 Gradle 会在构建过程当中检查这两个目录并引起duplicate class错误。若是针对不一样的构建类型须要不一样版本的 Utility.java,您可让每一个渠道定义其本身的文件版本,如:src/common/Utility.javasrc/xiaomi/Utility.java,而不将其包含在 main/ 中。
  • 全部Manifest合并为单个Manifest。将按照上述列表中的相同顺序指定优先级。也就是说,某个构建类型的Manifest设置会替换某个渠道的Manifest设置
  • 一样,values/ res/ 和 asset/ 目录中的若是存在有两个或两个以上的同名资源,好比在渠道中的资源将会替换main中资源,如下对于同时存在于strings.xml的同名资源和资源图标作个示例
// main 下的 图标资源
main\res\mipmap-hdpi\ic_launcher.png

// 在 xiaomi 下的 图标资源
xiaomi\res\mipmap-hdpi\ic_launcher.png 

//打包 xiaomi 渠道的时候会自动替换图片。
复制代码
// main 下的 strings.xml
<resource>
    <string name="app_name">MultiChannel</string>
    <string name="string_merge">我是string,没被合并</string>
</resource>
// 在 xiaomi 下的 strings.xml 内容为:
<resource>
    <string name="string_merge">我是xiaomi,已经合并</string>
</resource>
//当打 xiaomi 渠道包时,最终 strings.xml 会变成:
<resource>
    <string name="app_name">MultiChannel</string>
    <string name="string_merge">我是xiaomi,已经合并</string>
</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

参考阅读

推荐:官方文档
android.jobbole.com/84752/
juejin.im/post/58be7b…

相关文章
相关标签/搜索