Tinker热更新与AndResGuard资源混淆的结合

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")
            }
             ...
         }
      }
 }
 

即将下图四个文件复制:

image
image

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

image

总结

一、打包

  上线前,先执行reguardRelease任务,打出资源混淆过的Apk,生成在备份目录/bakApk/reguard-MM-dd-HH-mm-ss/目录中,同时,需要将该文件夹备份,作为下次热更新的基准包;

image

二、打补丁

上线后,若出现bug,需要打补丁:

  1.在修复完bug的时候,先执行reguardRelease任务,生成新的进行过资源混淆的apk;

  2.将备份好的基准包放置在app模块下的/build/bakApk/目录下,修改app模块下build.gradle中基准包目录,如下:

/**
 * 此处填写每次构建生成的基准包目录
 */
def baseApkDir(){
    return "resguard-0119-11-29-43" 
}

然后执行tinkerPatchRelease任务,生成补丁:

image

  3.找到patch目录下的补丁包,登录bugly后台,上传补丁

image

  到这里结合Tinker和AndResGuard的介绍就完了,依旧会提供我写的demo,如果有不清楚的地方可以参考下,如果遇到什么问题,可以在评论区留言:

https://github.com/chaychan/TinkerAndResGuardDemo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容