Android热修复技术原理详解(最新最全版本)
Android 热修复 -- 实现原理
(QQ空间)安卓App热补丁动态修复技术介绍
Android热修复实现原理
基本概念
动态修复或者更新app的行为,也被称为动态更新
热修复方案
技术选择
方案简介
AndFix - native解决方案
原理:
与Dexposed一样都基于开源框架Xposed实现,是一种AOP解决方案
优点:
即时生效
支持dalvik和art(AndFix supports Android version from 2.3 to 7.0, both ARM and X86 architecture, both Dalvik and ART runtime, both 32bit and 64bit.)
与Dexposed框架相比AndFix框架更加轻便好用,在进行热修复的过程中更加方便了
缺点:
面临稳定性与兼容性问题
AndFix不支持新增方法,新增类,新增field等
QQ空间--Dex插桩方案(大众点评的Nuwa参考其实现并开源)
原理:
- Hook了ClassLoader.pathList.dexElements[]。因为ClassLoader的findClass是通过遍历dexElements[]中的dex来寻找类的。当然为了支持4.x的机型,需要打包的时候进行插桩。
-
越靠前的Dex优先被系统使用,基于类级别的修复
优点:
- 不需要考虑对dalvik虚拟机和art虚拟机做适配
- 代码是非侵入式的,对apk体积影响不大
缺点:
- 需要下次启动才会生效
- 最大挑战在于性能,即Dalvik平台存在插桩导致的性能损耗,Art平台由于地址偏移问题导致补丁包可能过大的问题
- 虚拟机在安装期间为类打上CLASS_ISPREVERIFIED标志是为了提高性能的,我们强制防止类被打上标志是否会影响性能?这里我们会做一下更加详细的性能测试.但是在大项目中拆分dex的问题已经比较严重,很多类都没有被打上这个标志。
接入举例
1. AndFix
https://github.com/alibaba/AndFix
原理
流程
- 导入
dependencies {
compile 'com.alipay.euler:andfix:0.5.0@aar'
}
- Application onCreate中初始化&load
mPatchManager = new PatchManager(context);
mPatchManager.init(Utils.getVersionName(context));
mPatchManager.loadPatch();
- 加载patch文件
mPatchManager.addPatch(path);
生成patch
usage: apkpatch -f <new> -t <old> -o <output> -k <keystore> -p <***> -a <alias> -e <***>
-a,--alias <alias> keystore entry alias.
-e,--epassword <***> keystore entry password.
-f,--from <loc> new Apk file path.
-k,--keystore <loc> keystore path.
-n,--name <name> patch name.
-o,--out <dir> output dir.
-p,--kpassword <***> keystore password.
-t,--to <loc> old Apk file path.
多个patch合并为1个
usage: apkpatch -m <apatch_path...> -o <output> -k <keystore> -p <***> -a <alias> -e <***>
-a,--alias <alias> keystore entry alias.
-e,--epassword <***> keystore entry password.
-k,--keystore <loc> keystore path.
-m,--merge <loc...> path of .apatch files.
-n,--name <name> patch name.
-o,--out <dir> output dir.
-p,--kpassword <***> keystore password.
优劣
优点:原理简单,继承简单,即时生效
缺点:只能修复方法级别的bug,极大限制了使用场景
Tinker
https://github.com/Tencent/tinker/wiki
https://github.com/Tencent/tinker
Tinker有以下已知问题:
- Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件;//如果要想
- 由于Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
- 在Android N上,补丁对应用启动时间有轻微的影响;
- 不支持部分三星android-21机型,加载补丁时会主动抛出"TinkerRuntimeException:checkDexInstall failed";
- 对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标
集成(gradle接入)
- gradle编译插件: tinker-patch-gradle-plugin
- 核心sdk库: tinker-android-lib
- 非gradle编译用户的命令行版本: tinker-patch-cli.jar
在根目录下的build.gradle中,添加tinker-patch-gradle-plugin的依赖
dependencies {
//optional, help to generate the final application
// 生成appilcation时使用,只参与编译,不参与打包
provided('com.tencent.tinker:tinker-android-anno:1.9.1')
//tinker's main Android lib
compile('com.tencent.tinker:tinker-android-lib:1.9.1')
}
在app的build.gradle中添加依赖
dependencies {
//可选,用于生成application类
provided('com.tencent.tinker:tinker-android-anno:1.8.0')
//tinker的核心库
compile('com.tencent.tinker:tinker-android-lib:1.8.0')
//分包库 下面用得到
compile 'com.android.support:multidex:1.0.1'
}
还是在app的build.gradle的最上面添加插件依赖
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'
初始化
TinkerInstaller.indall(mAppLike);
https://juejin.im/entry/59f7cdbaf265da431e160db1
Tinker进阶
多渠道打包
- 命令行方式只能一个渠道一个渠道的打tpatch
- gradle方式只需要简单修改gradle脚本
自定义Tinker行为
重写DefaultTinkerResultService的onPatchResult方法,去掉kill