手记

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

Tinker的配置

  目前公司项目中使用Tinker作为热更新方案,由于Bugly的热更新是基于Tinker,并且提供了补丁的自动下载、合成、应用的功能以及补丁管理后台,所以集成了Bugly的热更新修复,关于Bugly热更新的集成,可以参考我之前发布的一篇文章:

  Tinker的配置划分在tinker-support.gradle文件中,相关的配置在后面的demo中会给出。

AndResGuard的配置

  关于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,如果有不清楚的地方可以参考下,如果遇到什么问题,可以在评论区留言:

0人推荐
随时随地看视频
慕课网APP

热门评论

楼主我写完这行报错  it.dependsOn resguardTask
请问怎么解决

查看全部评论