本文来自网易云社区
作者:王晨彦
前言
热修复和插件化是目前 Android 领域很火热的两门技术,也是 Android 开发工程师必备的技能。
目前比较流行的热修复方案有微信的 Tinker,手淘的 Sophix,美团的 Robust,以及 QQ 空间热修复方案。
QQ 空间热修复方案使用Java实现,比较容易上手。
如果还不了解 QQ 空间方案的原理,请先学习安卓App热补丁动态修复技术介绍
今天,我们就基于 QQ 空间方案来深入学习热修复原理,并且手把手完成一个热修复框架。
本文参考了 Nuwa,在此表示感谢。
本文基于 Gradle 2.3.3 版本,支持 Gradle 1.5.0-3.0.1。
实战
了解了热修复原理后,我们就开始打造一个热修复框架
-
关闭dex校验
根据文章中提到的第一个问题,在 Android 5.0 以上,APK安装时,为了提高 dex 加载速度,未引用其他 dex 的 class 将会被打上 CLASS_ISPREVERIFIED 标志。
打上 CLASS_ISPREVERIFIED 标志的 class,类加载器就不会去其他 dex 中寻找 class,我们就无法使用插桩的方式替换 class。
文章给出了解决办法,即让所有类都依赖其他 dex。如何实现呢?
新建一个 Hack 类,让所有类都依赖该类,将该类打包成 dex,在应用启动时优先将该 dex 插入到数组的最前面,即可实现。
OK,确定思路后,我们就开始动手。
-
找出编译后的 class
听起来好像很简单,那么如何让所有类依赖 Hack 类呢,总不能一个一个类改吧,怎么才能在打包时自动添加依赖呢?
接下来就要用到 Gradle Hook 和 ASM。
还不了解 Gradle 构建流程的赶快去学习啦
要想修改编译后的 class 文件,首先要 Hook 打包过程,在 Gradle 编译出 class 文件到打包成 APK 之间植入我们的代码,对 class 文件进行修改。
找到编译后的class文件要依赖 Gradle Hook ,而修改 class 文件要依赖 ASM。
首先,我们要找到编译后的 class 文件
新建一个 Project CFixExample,然后执行 assembleDebug
观察 Gradle Console 输出
:app:preBuild UP-TO-DATE:app:preDebugBuild UP-TO-DATE:app:checkDebugManifest:app:preReleaseBuild UP-TO-DATE:app:prepareComAndroidSupportAnimatedVectorDrawable2540Library// 省略部分Task:app:prepareComAndroidSupportSupportVectorDrawable2540Library:app:prepareDebugDependencies:app:compileDebugAidl UP-TO-DATE:app:compileDebugRenderscript UP-TO-DATE:app:generateDebugBuildConfig UP-TO-DATE:app:generateDebugResValues UP-TO-DATE:app:generateDebugResources UP-TO-DATE:app:mergeDebugResources UP-TO-DATE:app:processDebugManifest UP-TO-DATE:app:processDebugResources UP-TO-DATE:app:generateDebugSources UP-TO-DATE:app:incrementalDebugJavaCompilationSafeguard:app:javaPreCompileDebug:app:compileDebugJavaWithJavac:app:compileDebugNdk NO-SOURCE:app:compileDebugSources:app:mergeDebugShaders:app:compileDebugShaders:app:generateDebugAssets:app:mergeDebugAssets:app:transformClassesWithDexForDebug:app:mergeDebugJniLibFolders:app:transformNativeLibsWithMergeJniLibsForDebug:app:processDebugJavaRes NO-SOURCE:app:transformResourcesWithMergeJavaResForDebug:app:validateSigningDebug:app:packageDebug:app:assembleDebugBUILD SUCCESSFUL in 10s
这些就是 Gradle 打包时执行的所有任务,不同版本的 Gradle 会有所不同,这里我们基于 Gradle 2.3.3。
