<meta-data android:value="Channel ID" android:name="UMENG_CHANNEL"/>

       上面的value值Channel_ID就是渠道标识。我们的期望的就是在编译时候这个值能够自动变化以满足区分多渠道的需求。

(一)在AndroidManifest.xml里设置动态渠道变量

<meta-data
    android:name="UMENG_CHANNEL"
    android:value="${UMENG_CHANNEL_VALUE}" />

(二)在build.gradle设置productFlavors

这里假定我们需要打包的渠道为酷安市场、360、小米、百度、豌豆荚
android {  
    productFlavors {
        kuan {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "kuan"]
        }
        xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
        }
        qh360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"]
        }
        baidu {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
        }
        wandoujia {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
        }
    }  
}

或者批量修改

android {  
    productFlavors {
        kuan {}
        xiaomi {}
        qh360 {}
        baidu {}
        wandoujia {}
    }  

    productFlavors.all { 
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
    }
}

       所谓ProductFlavors其实就是可定义的产品特性,配合 manifest merger 使用的时候就可以达成在一次编译过程中产生多个具有自己特性配置的版本。上面这个配置的作用就是,为每个渠道包产生不同的 UMENG_CHANNEL_VALUE 的值。上述的配置在gradle 3.0之前是可以使用的,但是在3.0之后需要添加另外一个配置flavorDimensions,不然会在编译的过程中报错:Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html

    defaultConfig {
        applicationId "com.tongseng.sqlitedemo"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        flavorDimensions "versionCode"
    }

(三)执行打包操作

在AndroidStudio菜单栏点击Build菜单–>Generate signed APK–>选择key,并输入密码

androidstudio 自动生成类图_多渠道打包

然后下一步,选择打包渠道

androidstudio 自动生成类图_Android_02

最后点击完成按钮

androidstudio 自动生成类图_多渠道打包_03

上图可以看到,我们已经成功的将五个渠道包打好。

(四)执行打包命令 ./gradlew assembleRelease

       除了使用AndroidStudio图形打包操作以外,我们也可以使用命令行进行打包操作,具体步骤如下:

  • 在AndroidStudio窗口左下角打开Terminal面板,输入gradlew assembleRelease命令

打包成功之后会显示Build Successful

androidstudio 自动生成类图_多渠道打包_04

在app–>build–>outputs–>apk路径中就可以看到打包成功后的APK

注意,此时这里的APK包名显示为unsigned,也就是说未签名,我们可以继续在build.gradle文件中配置签名信息

signingConfigs {
        release{
            storeFile file("文件路径") //签名文件路径
            storePassword "123456"
            keyAlias "123456"
            keyPassword "123456"  //签名密码
        }
    }
  • 然后再次执行gradlew assembleRelease命令,这次生成的就是含有签名的渠道包了。
  • 当我们的渠道包版本比较多时,可以自定义所打APK包名称,用以区分
// 自定义输出配置,这里我们加上APK版本号1.0
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        // 输出apk名称为wooyun_v1.0_wandoujia.apk
                        def fileName = "tong_v${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }

assemble结合Build Variants来创建task

常用的 assemble 命令,会结合 Build Type 创建自己的task,如:

  • ./gradlew assembleDebug
  • ./gradlew assembleRelease

除此之外 assemble 还能和 Product Flavor 结合创建新的任务,其实 assemble 是和 Build Variants 一起结合使用的,而 Build Variants = Build Type + Product Flavor , 举个例子大家就明白了:

如果我们想打包wandoujia渠道的release版本,执行如下命令就好了:

  • ./gradlew assembleWandoujiaRelease

如果我们只打wandoujia渠道版本,则:

  • ./gradlew assembleWandoujia

此命令会生成wandoujia渠道的Release和Debug版本

同理我想打全部Release版本:

  • ./gradlew assembleRelease

这条命令会把Product Flavor下的所有渠道的Release版本都打出来。

总之,assemble 命令创建task有如下用法:

  • **assemble**: 允许直接构建一个Variant版本,例如assembleFlavor1Debug。
  • **assemble**: 允许构建指定Build Type的所有APK,例如assembleDebug将会构建Flavor1Debug和Flavor2Debug两个Variant版本。
  • **assemble**: 允许构建指定flavor的所有APK,例如assembleFlavor1将会构建Flavor1Debug和Flavor1Release两个Variant版本。

完整的gradle脚本样本:



apply plugin: 'com.android.application'

def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

android {
    compileSdkVersion 21
    buildToolsVersion '21.1.2'

    defaultConfig {
        applicationId "com.tongseng.*"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
        
        // dex突破65535的限制
        multiDexEnabled true
        // 默认是umeng的渠道
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "umeng"]
    }

    lintOptions {
        abortOnError false
    }

    signingConfigs {
        debug {
            // No debug config
        }

        release {
            storeFile file("../yourapp.keystore")
            storePassword "your password"
            keyAlias "your alias"
            keyPassword "your password"
        }
    }

    buildTypes {
        debug {
            // 显示Log
            buildConfigField "boolean", "LOG_DEBUG", "true"

            versionNameSuffix "-debug"
            minifyEnabled false
            zipAlignEnabled false
            shrinkResources false
            signingConfig signingConfigs.debug
        }

        release {
            // 不显示Log
            buildConfigField "boolean", "LOG_DEBUG", "false"

            minifyEnabled true
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release

            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                    	// 输出apk名称为tong_v1.0_2015-01-15_wandoujia.apk
                        def fileName = "tong_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }
        }
    }

    // 友盟多渠道打包
    productFlavors {
        wandoujia {}
        _360 {}
        baidu {}
        xiaomi {}
        tencent {}
        taobao {}
        ...
    }

    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    ...
}

签名密码写在gradle中不安全,故最好在打包上线的时候将相关代码注释掉。