多渠道打包

国内Android应用下载有360、小米、豌豆荚、百度等等非常多的渠道, 如果我们想统计每个渠道的下载量和活跃度,就需要使用统计平台.

我们以友盟统计为例,介绍如何配置渠道信息并执行自动化打包.

1.在AndroidMainfest.xml配置可动态替换的渠道参数

友盟集成文档中有说明,使用友盟统计需要在AndroidMainfest.xml配置相应的渠道号:

  1. <meta-data
  2. android:name="UMENG_CHANNEL"
  3. android:value="xiaomi" /><!--渠道号为:小米-->

如果想动态的替换渠道号怎么办呢?

  1. <meta-data
  2. android:name="UMENG_CHANNEL"
  3. android:value="${CHANNEL_ID}" /><!--动态替换渠道号-->

2.在build.gradle中配置渠道信息和自动替换脚本

  1. // 多渠道打包
  2. productFlavors {
  3. xiaomi {} //渠道名name为xiaomi
  4. baidu {}
  5. wandoujia {}
  6. // 自动替换AndroidManifest.xml中的渠道号
  7. productFlavors.all { flavor ->
  8. flavor.manifestPlaceholders = [CHANNEL_ID: name]
  9. }
  10. }

配置好以后在Build Variants窗口中可以选择不同渠道的变种版本:

Gradle工具栏也会生成相应的任务:

3.默认配置

  1. // 默认配置
  2. defaultConfig {
  3. applicationId "com.wirelessqa.basebuildsample" //apk包名
  4. minSdkVersion 16
  5. targetSdkVersion 23
  6. versionCode 1
  7. versionName "1.0" //版本号
  8. //android单元测试test runner
  9. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  10. }

所有渠道默认使用这一配置,如果渠道有特殊需求,可以在productFlavors对应的渠道号中单独配置.

4.打包后自动修改apk的名字

  1. // 打包后自动修改apk的名字
  2. // release包的命名格式为:产品名_版本号_渠道号.apk
  3. // debug包的命名格式为:产品名_版本号_渠道号_Debug_打包时间.apk
  4. applicationVariants.all { variant ->
  5. variant.outputs.each { output ->
  6. def outputFile = output.outputFile
  7. if (null != outputFile && outputFile.name.endsWith('.apk')) {
  8. File outputDir = new File(outputFile.parent);
  9. def baseName = PRODUCT_NAME + "${defaultConfig.versionName}" + "_" + variant.productFlavors[0].name
  10. def newApkName
  11. if (variant.buildType.name.equals('release')) {
  12. newApkName = baseName + '.apk'
  13. } else if (variant.buildType.name.equals('debug')) {
  14. newApkName = baseName + "_Debug_${packageTime()}.apk"
  15. }
  16. output.outputFile = new File(outputDir, newApkName)
  17. }
  18. }
  19. }

5.自动化打包

如何一次打出所有渠道的Release的包呢?

方法一: 命令行:

  1. $ ./gradlew assembleRelease

方法二: Gradle工具窗口:

方法三: 菜单栏 —> Build —> Generate Signed APK —> 一步步下去 —> Flavors中全选—> Finish.

这样所有渠道的Release包都被打出来了.

6.查看渠道号是否被正确替换.

单击apk之后,Android Studio会自动解析apk,这样我们就可以在Android Studio中直接查看apk的信息了.

1.单击baidu这个渠道 —>2.点击AndroidManifest.xml —>3.查看渠道号为baidu

由此证明我们的打包脚本是OK的.

如果要打Debug包,执行assembleDebug任务就可以了.

如果只想打某一个渠道的包,执行对应的打包任务就可以了.

本例中全部的build.gradle脚本如下:

  1. //插件:
  2. //这个module是一个android程序,使用com.android.application
  3. //如果是android库,应该使用com.android.library
  4. apply plugin: 'com.android.application'
  5. //产品名
  6. def PRODUCT_NAME = "wirelessqa"
  7. //打包时间
  8. def packageTime() {
  9. return new Date().format("MMddhhmmss", TimeZone.getTimeZone("GMT+8"))
  10. }
  11. android {
  12. // 签名配置
  13. signingConfigs {
  14. MySigning {
  15. keyAlias 'myandroid'
  16. keyPassword '123456'
  17. storeFile file('/Users/bixiaopeng/myandroid.jks')
  18. storePassword '123456'
  19. }
  20. }
  21. // 编译sdk版本
  22. compileSdkVersion 23
  23. // 构建工具版本
  24. buildToolsVersion "23.0.2"
  25. // 默认配置
  26. defaultConfig {
  27. applicationId "com.wirelessqa.basebuildsample" //apk包名
  28. minSdkVersion 16
  29. targetSdkVersion 23
  30. versionCode 1
  31. versionName "1.0" //版本号
  32. //android单元测试test runner
  33. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  34. versionNameSuffix 'test'
  35. }
  36. // 产品特性
  37. productFlavors {
  38. xiaomi {} //渠道名name为xiaomi
  39. baidu {
  40. }
  41. wandoujia {}
  42. // 自动替换AndroidManifest.xml中的渠道号
  43. productFlavors.all { flavor ->
  44. flavor.manifestPlaceholders = [CHANNEL_ID: name]
  45. }
  46. }
  47. // 构建类型,此处配置debug和release版本的一些参数,像混淆、签名配置.
  48. buildTypes {
  49. // release包的配置
  50. release {
  51. //开启混淆
  52. minifyEnabled true
  53. // 指定混淆文件
  54. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  55. // 指定签名配置
  56. signingConfig signingConfigs.MySigning
  57. zipAlignEnabled true
  58. //移除无用的资源文件
  59. shrinkResources true
  60. }
  61. }
  62. // 打包后自动修改apk的名字
  63. // release包的命名格式为:产品名_版本号_渠道号.apk
  64. // debug包的命名格式为:产品名_版本号_渠道号_Debug_打包时间.apk
  65. applicationVariants.all { variant ->
  66. variant.outputs.each { output ->
  67. def outputFile = output.outputFile
  68. if (null != outputFile && outputFile.name.endsWith('.apk')) {
  69. File outputDir = new File(outputFile.parent);
  70. def baseName = PRODUCT_NAME + "${defaultConfig.versionName}" + "_" + variant.productFlavors[0].name
  71. def newApkName
  72. if (variant.buildType.name.equals('release')) {
  73. newApkName = baseName + '.apk'
  74. } else if (variant.buildType.name.equals('debug')) {
  75. newApkName = baseName + "_Debug_${packageTime()}.apk"
  76. }
  77. output.outputFile = new File(outputDir, newApkName)
  78. }
  79. }
  80. }
  81. }
  82. // 依赖的第三方库
  83. dependencies {
  84. compile fileTree(include: ['*.jar'], dir: 'libs')
  85. compile 'com.android.support:appcompat-v7:23.4.0'
  86. compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha1'
  87. compile 'com.android.support:design:23.4.0'
  88. testCompile 'junit:junit:4.12'
  89. androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
  90. androidTestCompile 'com.android.support.test:runner:0.5'
  91. androidTestCompile 'com.android.support:support-annotations:23.4.0'
  92. }