Tinker的配置
??目前公司項(xiàng)目中使用Tinker作為熱更新方案,由于Bugly的熱更新是基于Tinker,并且提供了補(bǔ)丁的自動(dòng)下載、合成、應(yīng)用的功能以及補(bǔ)丁管理后臺(tái),所以集成了Bugly的熱更新修復(fù),關(guān)于Bugly熱更新的集成,可以參考我之前發(fā)布的一篇文章:
??Android熱更新初探,Bugly熱更新的集成和使用(讓你的應(yīng)用輕松具備熱更新能力)
??Tinker的配置劃分在tinker-support.gradle文件中,相關(guān)的配置在后面的demo中會(huì)給出。
AndResGuard的配置
??關(guān)于AndResGuard的介紹和集成,可以參考我之前發(fā)布的一篇文章:
??AndResGuard的配置劃分在and_res_guard.gradle文件中,相關(guān)的配置在后面的demo中會(huì)給出。
Tinker與AndResGuard的結(jié)合
??由于現(xiàn)在Tinker和AndResGuard是分開配置,還沒(méi)有進(jìn)行結(jié)合。此時(shí)使用Tinker生成的基準(zhǔn)包、打出來(lái)的補(bǔ)丁,資源并沒(méi)有進(jìn)行混淆;如果使用AndResGuard生成apk,資源是混淆過(guò)的,當(dāng)出現(xiàn)bug時(shí),使用Tinker生成補(bǔ)丁,由于補(bǔ)丁中的資源文件沒(méi)有進(jìn)行過(guò)混淆,所以合成補(bǔ)丁的時(shí)候會(huì)失敗。
所以現(xiàn)在的思路是:
??當(dāng)使用resguardRelease打包后,將生成的混淆過(guò)的apk文件、mapping文件、R文件和resouce_mapping文件拷貝到"${buildDir}/bakApk/resguard-MM-dd-HH-mm-ss" 目錄下;若是待上線的新版本,則該目錄為基準(zhǔn)包備份目錄,需要將其保存,當(dāng)需要打補(bǔ)丁的時(shí)候,該目錄下的文件需要用到。
??當(dāng)使用tinkerPatchRelease生成補(bǔ)丁前,加入resguardTask任務(wù),這樣生成補(bǔ)丁時(shí),使用到的新舊Apk都是資源混淆過(guò)的,生成的補(bǔ)丁的資源也是混淆過(guò)的,此時(shí),合成補(bǔ)丁的時(shí)候,就可以成功了。
主要的配置:
def bakPath(){
return file("${buildDir}/bakApk/")
}
/**
* 此處填寫每次構(gòu)建生成的基準(zhǔn)包目錄
*/
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 { }中的代碼,判斷如果執(zhí)行的是release類型的指令,則需要進(jìn)行處理。
if (variant.buildType.name == 'release') {
//是release指令,進(jìn)行相關(guān)處理
}
如果是執(zhí)行tinkerPatchRelease任務(wù),即打補(bǔ)丁,在打補(bǔ)丁之前,需要先調(diào)用reguardTask,代碼中有" it.dependsOn resguardTask",即該命令依賴于resguardTask,需要先執(zhí)行resguardTask任務(wù)。
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
}
}
??如果是執(zhí)行reguardRelease任務(wù),則需要執(zhí)行備份操作,將混淆過(guò)的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")
}
...
}
}
}
即將下圖四個(gè)文件復(fù)制:


存放在/bakApk/reguard-MMdd-HH-mm-ss/目錄下

總結(jié)
一、打包
??上線前,先執(zhí)行reguardRelease任務(wù),打出資源混淆過(guò)的Apk,生成在備份目錄/bakApk/reguard-MM-dd-HH-mm-ss/目錄中,同時(shí),需要將該文件夾備份,作為下次熱更新的基準(zhǔn)包;

二、打補(bǔ)丁
上線后,若出現(xiàn)bug,需要打補(bǔ)?。?/p>
??1.在修復(fù)完bug的時(shí)候,先執(zhí)行reguardRelease任務(wù),生成新的進(jìn)行過(guò)資源混淆的apk;
??2.將備份好的基準(zhǔn)包放置在app模塊下的/build/bakApk/目錄下,修改app模塊下build.gradle中基準(zhǔn)包目錄,如下:
/**
* 此處填寫每次構(gòu)建生成的基準(zhǔn)包目錄
*/
def baseApkDir(){
return "resguard-0119-11-29-43"
}
然后執(zhí)行tinkerPatchRelease任務(wù),生成補(bǔ)丁:

??3.找到patch目錄下的補(bǔ)丁包,登錄bugly后臺(tái),上傳補(bǔ)丁

??到這里結(jié)合Tinker和AndResGuard的介紹就完了,依舊會(huì)提供我寫的demo,如果有不清楚的地方可以參考下,如果遇到什么問(wèn)題,可以在評(píng)論區(qū)留言: