最近项目集成了 Tinker,开始认为集成会比较简单,但是在实际操作的过程中还是遇到了一些问题,本文就会介绍在集成过程大家基本会遇到的主要问题。下面跟着小编一起来看下吧
Android 是一种基于 Linux 的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由 Google 公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用 "安卓" 或 "安致"。
前言
最近项目集成了 Tinker,开始认为集成会比较简单,但是在实际操作的过程中还是遇到了一些问题,本文就会介绍在集成过程大家基本会遇到的主要问题。
考虑一:后台的选取
目前后台功能可以通过三种方式实现:
1、自己搭建后台布丁下发系统
2、第三方提供的服务,目前如原微信 simsun 大神的个人 tinkerpatch 平台,目前出于内测阶段,暂时免费。后期应该会按下发量对 app 进行收费。
3、腾讯 Bugly 提供的服务,提供了热更新的下发后台,集成到了 bugly 的升级 sdk 中。免费。
根据公司的精神,我们选择了 Bugly 作为我们的方案,这个大家都懂得。
考虑二:多渠道打包的问题
我们有将近 100 个渠道,每个渠道需要一个不同的渠道号,按 product flavor 的方式打出来的包的 dex 都有差异。这样就造成 100 个渠道包的热更新就需要 100 个补丁,这对管理简直是一个灾难。Tinker 也对这种问题给出了推荐的方案,那就是使用开源项目 packer-ng-plugin,它的原理是将渠道信息写在 apk 文件的 zip comment 中,这样在多渠道打包时就不会影响 dex 的内容。
考虑三:资源混淆所造成的问题
目前项目使用了资源混淆项目 AndResGuard,关于 AndResGuard 的介绍,可以参考文档 AndResGuard[Android 混淆工具 AndResGuard]。
也正是引入了资源混淆,热更新和多渠道打包都必须依赖资源混淆后生成的 apk 包才行。所以我们对编译流程进行了整合。
** 整合前 **
编译:编译直接使用 AndResGuard 提供的命令 resguardRelease 生成即可。resguardRelease 生成的 apk 文件是没有资源混淆的。
- ./gradlew resguardRelease
Tinker 生成补丁:直接调用 tinkerPatchRelease 任务生成的 Release 文件没有进行资源混淆
- ./gradlew tinkerPatchRelease
多渠道打包:使用 packer-ng 的命令 apkRelease 生成多渠道文件没有进行资源混淆
- ./gradlew apkRelease
** 整合后 **
主要解决两个问题:
1、Tinker 生成补丁的原始和新的 apk,需要使用资源混淆后的 apk
2、多渠道打包所使用的原始 apk,需要使用资源混淆后的 apk
针对问题 1:
当使用 resguardRelease 进行编译,在编译完成后,将生成的 apk 文件、R 文件、map 文件和 resouce map 文件拷贝到 ${buildDir}/bakApk/resguard 目录下;
当使用 tinkerPatchRelease 生成补丁时,在 tinkerPatchRelease 任务前加入 resguardTask 任务,这样生成补丁时使用的新旧 apk 都是资源混淆过的。核心的 gradle 代码如下:
- android.applicationVariants.all { variant ->
- /**
- * task type, you want to bak
- */
- def taskName = variant.name
- tasks.all {
- if (variant.buildType.name == 'release') {
- if ("tinkerPatch${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
- // find resguard task
- def resguardTask
- tasks.all {
- if (it.name.startsWith("resguard")) {
- resguardTask = it
- }
- }
- it.doFirst({
- // change build apk path
- it.buildApkPath = "${buildDir}/outputs/apk/AndResGuard_${project.getName()}-${taskName}/${project.getName()}-${taskName}_signed.apk"
- })
- // change task dependence to resguard task
- it.dependsOn resguardTask
- }
- if ("resguard${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
- it.doLast {
- copy {
- def date = new Date().format("MMdd-HH-mm-ss")
- from "${buildDir}/outputs/apk/AndResGuard_${project.getName()}-${taskName}/${project.getName()}-${taskName}_signed_7zip_aligned.apk"
- into file(bakPath.absolutePath + "/resguard")
- rename { String fileName ->
- fileName.replace("${project.getName()}-${taskName}_signed_7zip_aligned.apk", "${project.getName()}-${taskName}-${date}.apk")
- }
- from "${buildDir}/outputs/mapping/${taskName}/mapping.txt"
- into file(bakPath.absolutePath + "/resguard")
- rename { String fileName ->
- fileName.replace("mapping.txt", "${project.getName()}-${taskName}-${date}-mapping.txt")
- }
- from "${buildDir}/intermediates/symbols/${taskName}/R.txt"
- into file(bakPath.absolutePath + "/resguard")
- rename { String fileName ->
- fileName.replace("R.txt", "${project.getName()}-${taskName}-${date}-R.txt")
- }
- from "${buildDir}/outputs/apk/AndResGuard_${project.getName()}-${taskName}/resource_mapping_${project.getName()}-release.txt"
- into file(bakPath.absolutePath + "/resguard")
- rename { String fileName ->
- fileName.replace("resource_mapping_${project.getName()}-release.txt", "${project.getName()}-${taskName}-${date}-resource_mapping.txt")
- }
- }
- }
- }
- }
- }
针对问题 2、在 AS 中使用 apkRelease 任务打包的方式不再适用,可直接使用 packer-ng 所提供的命令行方式进行生成渠道包,经过测试,100 个渠道包的确在 10s 左右就能打完,速度相当之快。考虑到市场推广人员会打不同渠道包,后期可做一个简易工具提供给市场推广人员。
整合后操作:
编译:
- ./gradlew resguardRelease
生成的 apk 文件放在 ${app}\build\bakApk\resguard \ 目录下
打补丁包:
- ./gradlew tinkerPatchRelease
- ./gradlew generateManifestForReleaseTinkerPatch
最终生成的补丁放在 ${app}\build\outputs\patch \ 目录下
多渠道打包:
针对编译后生成的包,使用 packer-ng 提供的命令行操作即可
- java -jar PackerNg-x.x.x.jar apkFile marketFile outputDir
来源: