Tinker的配置
目前公司项目中使用Tinker作为热更新方案,由于Bugly的热更新是基于Tinker,并且提供了补丁的自动下载、合成、应用的功能以及补丁管理后台,所以集成了Bugly的热更新修复,关于Bugly热更新的集成,可以参考我之前发布的一篇文章:
Android热更新初探,Bugly热更新的集成和使用(让你的应用轻松具备热更新能力)
Tinker的配置划分在tinker-support.gradle文件中,相关的配置在后面的demo中会给出。
AndResGuard的配置
关于AndResGuard的介绍和集成,可以参考我之前发布的一篇文章:
APP瘦身大法--AndResGuard的使用
AndResGuard的配置划分在and_res_guard.gradle文件中,相关的配置在后面的demo中会给出。
Tinker与AndResGuard的结合
由于现在Tinker和AndResGuard是分开配置,还没有进行结合。此时使用Tinker生成的基准包、打出来的补丁,资源并没有进行混淆;如果使用AndResGuard生成apk,资源是混淆过的,当出现bug时,使用Tinker生成补丁,由于补丁中的资源文件没有进行过混淆,所以合成补丁的时候会失败。
所以现在的思路是:
当使用resguardRelease打包后,将生成的混淆过的apk文件、mapping文件、R文件和resouce_mapping文件拷贝到"${buildDir}/bakApk/resguard-MM-dd-HH-mm-ss" 目录下;若是待上线的新版本,则该目录为基准包备份目录,需要将其保存,当需要打补丁的时候,该目录下的文件需要用到。
当使用tinkerPatchRelease生成补丁前,加入resguardTask任务,这样生成补丁时,使用到的新旧Apk都是资源混淆过的,生成的补丁的资源也是混淆过的,此时,合成补丁的时候,就可以成功了。
主要的配置:
def bakPath(){
return file("${buildDir}/bakApk/")
}
/**
* 此处填写每次构建生成的基准包目录
*/
def baseApkDir(){
return "resguard-0119-11-29-43"
}
def detailedBuildTime() {
return new Date().format("MMdd-HH-mm-ss", TimeZone.getTimeZone("GMT+8"))
}
def appName(){
return "${project.getName()}"
}
android {
... //省略
/**
* bak apk and mapping
*/
android.applicationVariants.all { variant ->
/**
* task type, you want to bak
*/
def taskName = variant.name
tasks.all {
if (variant.buildType.name == 'release') {
def andResDir = "${buildDir}/outputs/apk/${taskName}/AndResGuard_${project.getName()}-${taskName}";
if ("tinkerPatch${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
// find resguard task
def resguardTask
tasks.all {
if (it.name.startsWith("resguard${taskName.capitalize()}")) {
resguardTask = it
}
}
it.doFirst({
// change build apk path
it.buildApkPath = "${andResDir}/${project.getName()}-${taskName}_aligned_signed.apk"
})
// change task dependence to resguard task
it.dependsOn resguardTask
}
if ("resguard${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
it.doLast {
copy {
def outDir = file("${bakPath()}/resguard-${detailedBuildTime()}")
from "${andResDir}/${project.getName()}-${taskName}_aligned_signed.apk"
into outDir
rename { String fileName ->
fileName.replace("${project.getName()}-${taskName}_aligned_signed.apk", "${appName()}.apk")
}
from "${buildDir}/outputs/mapping/${taskName}/mapping.txt"
into outDir
rename { String fileName ->
fileName.replace("mapping.txt", "${appName()}-mapping.txt")
}
from "${buildDir}/intermediates/symbols/${taskName}/R.txt"
into outDir
rename { String fileName ->
fileName.replace("R.txt", "${appName()}-R.txt")
}
from "${andResDir}/resource_mapping_${project.getName()}-release.txt"
into outDir
rename { String fileName ->
fileName.replace("resource_mapping_${project.getName()}-release.txt", "${appName()}-resource_mapping.txt")
}
}
}
}
}
}
}
}
主要是tasks.all { }中的代码,判断如果执行的是release类型的指令,则需要进行处理。
if (variant.buildType.name == 'release') {
//是release指令,进行相关处理
}
如果是执行tinkerPatchRelease任务,即打补丁,在打补丁之前,需要先调用reguardTask,代码中有" it.dependsOn resguardTask",即该命令依赖于resguardTask,需要先执行resguardTask任务。
if (variant.buildType.name == 'release') {
def andResDir = "${buildDir}/outputs/apk/${taskName}/AndResGuard_${project.getName()}-${taskName}";
if ("tinkerPatch${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
// find resguard task
def resguardTask
tasks.all {
if (it.name.startsWith("resguard${taskName.capitalize()}")) {
resguardTask = it
}
}
it.doFirst({
// change build apk path
it.buildApkPath = "${andResDir}/${project.getName()}-${taskName}_aligned_signed.apk"
})
// change task dependence to resguard task
it.dependsOn resguardTask
}
}
如果是执行reguardRelease任务,则需要执行备份操作,将混淆过的apk、mapping.txt、R.txt、resource_mapping.txt备份到app目录下的/build/bakApk/reguard-MMdd-HH-mm-ss/目录下:
if ("resguard${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
it.doLast {
copy {
def outDir = file("${bakPath()}/resguard-${detailedBuildTime()}")
from "${andResDir}/${project.getName()}-${taskName}_aligned_signed.apk"
into outDir
rename { String fileName ->
fileName.replace("${project.getName()}-${taskName}_aligned_signed.apk", "${appName()}.apk")
}
...
}
}
}
即将下图四个文件复制:
存放在/bakApk/reguard-MMdd-HH-mm-ss/目录下
总结
一、打包
上线前,先执行reguardRelease任务,打出资源混淆过的Apk,生成在备份目录/bakApk/reguard-MM-dd-HH-mm-ss/目录中,同时,需要将该文件夹备份,作为下次热更新的基准包;
二、打补丁
上线后,若出现bug,需要打补丁:
1.在修复完bug的时候,先执行reguardRelease任务,生成新的进行过资源混淆的apk;
2.将备份好的基准包放置在app模块下的/build/bakApk/目录下,修改app模块下build.gradle中基准包目录,如下:
/**
* 此处填写每次构建生成的基准包目录
*/
def baseApkDir(){
return "resguard-0119-11-29-43"
}
然后执行tinkerPatchRelease任务,生成补丁:
3.找到patch目录下的补丁包,登录bugly后台,上传补丁
到这里结合Tinker和AndResGuard的介绍就完了,依旧会提供我写的demo,如果有不清楚的地方可以参考下,如果遇到什么问题,可以在评论区留言:
https://github.com/chaychan/TinkerAndResGuardDemo