文章目录
前言
两年前的持续集成完成之后,一直用到了最近都没啥大的变更要做。直到国内应用市场开始推 32 位和 64 位架构分包。
刚好前一段时间我们的 app 因为名称的原因,在 vivo 商店需要改名称才能上架,这就难受了,每次发版除了自动打包其他渠道外,还要单独编译加固 vivo 渠道,刚好这次一并解决了。
这篇文章相当于是对第三篇文章的一个补充。
注意这篇文章是以我自己配置的持续集成为基础的,以下为系列文章回顾。
系列文章
Android 持续集成实践(一)——从0开始搭建 Gitlab 服务器
Android 持续集成实践(二)——配置 Docker + gitlab-runner 实现线上自动编译
Android 持续集成实践(三)——编写 .gitlab-ci.yml 实现自动化
Android 持续集成实践(四)——配置 WebHook 通知编译结果
Android 持续集成实践(五)—— ABI 分包、特殊渠道编译需求
正文开始
ABI 分包
实现目标
发布正式版
时,分别自动编译+自动多渠道 armeabi-v7a(32位) 和 arm64-v8a(64位) 的 apk;
发布测试版
时,编译一个同时包含 armeabi-v7a 和 x86 so 库的 apk。
实践
-
abi 分割
abi 分割可以直接配置 gradle 的 splits 节点来实现,需求是 release 版才需要分包,所以还需要在 abi 分割时,判断是 release 还是 debug。
release 时启用 abi 分割;debug 时禁用分割,并且使用原来的 ndk 过滤配置多个架构 so 库// main module's build.gradle android{ ... // 架构分包配置,只有 release 版需要架构分包;debug版还走以前的 ndk 过滤配置 splits { boolean isReleaseTask = gradle.startParameter.taskNames.any { it.contains("Release") } if (!isReleaseTask) { // debug 使用 ndk 过滤方式(splits 执行时机太靠前了,ndk配置在 buildTypes 中不生效) android.defaultConfig.ndk { abiFilters "armeabi-v7a", "x86" } } // release 才会启用 abi 分割 abi { enable isReleaseTask reset() include "armeabi-v7a", "arm64-v8a" universalApk false } } ... }
-
apk 文件名修改
abi 分割后,需要把 abi 的配置体现在 apk 名字上边,持续集成的流程在编译完后,要拿到 apk 继续执行自动加固、自动多渠道的任务,所以我们需要一个已知的确定的文件名,方便后边的持续集成任务拿到 apk。
// main module's build.gradle ... import com.android.build.OutputFile ... android{ ... applicationVariants.all { variant -> variant.outputs.all { output -> def abiName = output.getFilter(OutputFile.ABI) if (abiName != null) outputFileName = "${variant.buildType.name}_${defaultConfig.applicationId}_${defaultConfig.versionName}_${defaultConfig.versionCode}_${abiName}.apk" else outputFileName = "${variant.buildType.name}_${defaultConfig.applicationId}_${defaultConfig.versionName}_${defaultConfig.versionCode}.apk" } } ... }
-
修改自动加固的配置
现在 release 打包完是两个 apk 了,所以后续的加固和多渠道任务也需要改为支持两个 apk
//修改文件 360jiagu #!/usr/bin/env bash ################ #360加固 配置文件 # ################ ... # 32位apk路径 APK_NAME_32=release_com.wln100.future_${CI_COMMIT_TAG}_${CI_PIPELINE_ID}_armeabi-v7a.apk APK_PATH_32=app/build/outputs/apk/release/${APK_NAME_32} #需要加固的apk路径 # 64位apk路径 APK_NAME_64=release_com.wln100.future_${CI_COMMIT_TAG}_${CI_PIPELINE_ID}_arm64-v8a.apk APK_PATH_64=app/build/outputs/apk/release/${APK_NAME_64} #需要加固的apk路径 # 输出加固包路径 DEST=app/build/outputs/apk/release/ ... echo "------ running! ------" chmod +x ${JAVACMD} ${JAVACMD} -jar ${BASE} -version ${JAVACMD} -jar ${BASE} -login ${NAME} ${PASSWORD} ${JAVACMD} -jar ${BASE} -importsign ${KEYSTORE_PATH} ${KEY_PASSWORD} ${KEY_ALIAS} ${STORE_PASSWORD} # 配置签名信息 ${JAVACMD} -jar ${BASE} -showsign ${JAVACMD} -jar ${BASE} -deletemulpkg # 清除已配置的渠道信息 ${JAVACMD} -jar ${BASE} -importmulpkg ./channels.txt # 配置渠道信息 ${JAVACMD} -jar ${BASE} -showmulpkg ${JAVACMD} -jar ${BASE} -showconfig echo "------ 开始加固 32 位 apk ------" ${JAVACMD} -jar ${BASE} -jiagu ${APK_PATH_32} ${DEST} -autosign -automulpkg echo "------ 开始加固 64 位 apk ------" ${JAVACMD} -jar ${BASE} -jiagu ${APK_PATH_64} ${DEST} -autosign -automulpkg echo "------ finished! ------"
以上,配置结束,使用打包正式版的标签验证一下结果:
特殊渠道编译需求
特别说明,特殊渠道编译需求与上边的 abi 分包,这俩是没有关联的,各自独立的。如果你的项目刚好要 abi 分包的同时还要自动输出特殊需求的渠道包,就需要你自己来融合了
实现目标
持续集成时,自动编译加固多渠道 apk,同时需要 vivo 渠道的 apk 更改应用名称
实践
自动多渠道是依托 360 加固的 sdk 实现的,现在要 vivo 渠道自动编译的时候更改 app 名称,那 vivo 这个渠道就不能走 360 加固的多渠道命令统一处理了。
不自动编译的话,如何打包 vivo 渠道的 apk?修改版本号和版本名与自动编译生成的版本号版本名一致;修改清单文件中渠道原数据为 vivo;修改资源文件中 app_name 为运营要求的名称;执行编译任务 gradlew assembleRelease
坐等编译完成。。。
这个手动的过程,不复杂但是很繁琐,必须搞进程序集成流程中实现自动化解放双手。
一开始实现的思路是直接使用 gradle 的产品变种配置节点 productFlavors
来配置一个 vivo 渠道,这样是可行的,但是不太完美,配置变种后,无论打包 release 还是 debug,指定变种后都会打包变种包,不指定的话会打包所有的变种包。但是我们需要的只是在 release 的时候,去打包 vivo 这个特殊渠道,其他情况根本不需要。
定义变种后的打包命令结构是[编译类型+产品变种]
,=,既然定义变种后, debug 编译类型也会同时支持变种的话,那何不直接定义一个新的编译类型,与默认的 release 和 debug 编译类型并列呢。
-
移除 vivo 渠道的配置
-
新建编译类型
releaseVivo
//main module's build.gradle ... android{ ... buildTypes{ ... create("releaseVivo") { initWith(getByName("release")) //继承 release 编译类型的配置 manifestPlaceholders["app_label"] = "@string/app_name_vivo" //修改 vivo 渠道的 app 名字 manifestPlaceholders["umeng_channel"] = "vivo" //设置 vivo 渠道标识字段 matchingFallbacks = ["release"] //其他 module 没有定义这个编译类型,匹配不到时使用 release 编译类型 } ... } ... } ...
输入 gradle 命令
gradlew assembleReleaseVivo
,等待编译完后,其可以看到 vivo 渠道的 apk 了 -
修改
.gitlab-ci.yml
... # 编译阶段 # 利用标签打正式包,格式:“x.x.x” release: stage: build only: - /^[\d]+\.[\d]+\.[\d]+$/ except: - branches script: - ./update-version-code - ./gradlew assembleRelease assembleReleaseVivo artifacts: paths: - app/build/outputs/apk/release/ - app/build/outputs/apk/releaseVivo/ - app/build/outputs/mapping/release/ tags: - android #region 加固和打渠道包阶段 reinforceAndChannel: stage: reinforceAndChannel only: - /^[\d]+\.[\d]+\.[\d]+$/ script: - ./360jiagu artifacts: paths: - app/build/outputs/apk/release/ - app/build/outputs/apk/releaseVivo/ - app/build/outputs/mapping/release/ tags: - android #endregion ...
-
修改加固命令,支持同时加固 releaseVivo 编译出的 apk
#!/usr/bin/env bash ################ #360加固 配置文件 # ################ ... APK_NAME=release_com.wln100.future_${CI_COMMIT_TAG}_${CI_PIPELINE_ID}.apk APK_PATH=app/build/outputs/apk/release/${APK_NAME} #需要加固的apk路径 DEST=app/build/outputs/apk/release/ #输出加固包路径 # vivo 安装包加固路径配置 VIVO_APK_NAME=releaseVivo_com.wln100.future_${CI_COMMIT_TAG}_${CI_PIPELINE_ID}.apk VIVO_APK_PATH=app/build/outputs/apk/releaseVivo/${VIVO_APK_NAME} #需要加固的apk路径 VIVO_DEST=app/build/outputs/apk/releaseVivo/ #输出加固包路径 ... echo "------ running! ------" chmod +x ${JAVACMD} ${JAVACMD} -jar ${BASE} -version ${JAVACMD} -jar ${BASE} -login ${NAME} ${PASSWORD} ${JAVACMD} -jar ${BASE} -importsign ${KEYSTORE_PATH} ${KEY_PASSWORD} ${KEY_ALIAS} ${STORE_PASSWORD} # 配置签名信息 ${JAVACMD} -jar ${BASE} -showsign ${JAVACMD} -jar ${BASE} -deletemulpkg # 清除已配置的渠道信息 ${JAVACMD} -jar ${BASE} -importmulpkg ./channels.txt # 配置渠道信息 ${JAVACMD} -jar ${BASE} -showmulpkg ${JAVACMD} -jar ${BASE} -showconfig ${JAVACMD} -jar ${BASE} -jiagu ${APK_PATH} ${DEST} -autosign -automulpkg echo "------ 开始加固 vivo 渠道 apk ------" ${JAVACMD} -jar ${BASE} -deletemulpkg # 清除已配置的渠道信息 ${JAVACMD} -jar ${BASE} -showconfig ${JAVACMD} -jar ${BASE} -jiagu ${VIVO_APK_PATH} ${VIVO_DEST} -autosign echo "------ finished! ------"
以上,配置结束,使用打包正式版的标签验证一下结果:
Q&A
看的一头雾水?代码不完整?
再回顾一下持续集成系列文章,代码都有贴完整的,重复的就不在这篇里边加了
gradle 编译遇到 OOM?
同时异步走两个编译任务,需要的内存更大了,增加 jvm 内存配置吧
# 在 project 的 gradle.properties 中修改配置
...
# 我的设置是,初始 2g,最大 4g
org.gradle.jvmargs=-Xms2048M -Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
...
gitlab 线上 ci 报错:ERROR: Uploading artifacts to coordinator… too large archive
架构分割后,输出的 apk 成倍增长了,原来是一个 apk 打 6 个渠道包,总共 7 个 apk,现在 32 位和 64 位都要分别多渠道,有 14 个 apk,最后输出的 文件大小可想而知。我设置的 gitlab 输出文件大小最大是 300m,需要再加大点:
一些想法
最近 aab(Android App Bundle) 也在逐渐升温,墙外的 google 商店已经要求强制支持了。墙内的各商店,好像只是华为支持 aab 格式上传 app,再说到持续集成,以后可能还要实践 release 编译时输出 aab 格式文件,debug 编译时输出 apk 文件;国内加固工具对 aab 文件的加固支持情况具体怎么样还没研究(或者说 aab 文件其实已经不需要加固了?)