Tinker熱更新與AndResGuard資源混淆的結(jié)合

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ā)布的一篇文章:

??APP瘦身大法--AndResGuard的使用

??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ù)制:

image
image

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

image

總結(jié)

一、打包

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

image

二、打補(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ǔ)丁:

image

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

image

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

https://github.com/chaychan/TinkerAndResGuardDemo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容