Android热修复方案研究(含AOP知识)

[

一、概述

  以前对Android 的热修复方案有一些了解,知道几个有名的开源方案,原理大概理解,但是没有整理汇总一下,上周听了玉斌大哥在公司做的分享后,感受颇多觉得写篇博客记一下,不能浪费。

  热修复是指在不发新版的情况下修复线上的紧急 bug,长久以来做移动开发的人员都羡慕做后端或者做 web 前端的人员可以随时发布来修复 bug。那么 移动开发有没有这样的方案呢?

  1. Hybrid

如:PhoneGap、国内的 AppCan。本质还是利用了 Web 开发在更新上的优势,但体验不如 Native。

  1. ReactNative

像Web一样可以随时发布,又有原生的体验,所以这个方案优势挺大,有很多项目都在尝试。

  1. Native HotFix

可以不用发新版本,直接下发补丁包修复 bug,纯原生体验。

iOS有JSPatch、Android 有 AndFix、Nuwa、DroidFix 等

二、Android Native HotFix

下面按照原理分类为

(一) Dex分包方案(如 Nuwa、DroidFix、HotFix)

  原理:如果多个 dex 里有相同的class,那么虚拟机会优先使用最先加载的 dex 中的 class。所以将有问题的类打包到一个新dex(pathc.dex),然后下发给 app,app 启动时将该patch.dex插入到其他 dex 前面优先加载。就达到了 替换有问题 class 的目的。

这里有两个难点:

1. 改变dex加载顺序

2. class_ispreverified

错误信息:java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation

原因

Android热修复方案研究(含AOP知识)_第1张图片

  dex转化成odex时会执行dvmVerifyClass进行类的校验,如 B的引用和B都在一个 dex 里,则 B 会被打上class_ispreverified标记,但是我们优先加载 A’,A’和B在两个不同的 dex,但 B 却打上了class_ispreverified标识所以就报错了。

  两个相关联的类在不同的dex中并且有class_ispreverified就会报错,谷歌MultiDex拆分dex的时候就会处理这种情况如果A 和 B 不在同一个 Dex 就不会给 B标记class_ispreverified。

  但我们是热修复,patch.dex 是事后打的 dex,class.dex已经安装的用户手机里了,所以我们无法修改 B 的标识。

解决方案:

Android热修复方案研究(含AOP知识)_第2张图片

我们发布版本打包时,将所有的类都引用一个单独dex的一个类,这个所有的类都不会标记class_ispreverified了,当然这也就失去了class_ispreverified的意义,会有性能上的影响。

更具体的分析请看 http://bugly.qq.com/blog/?p=781

(二)smali diff方案(以 AndFix为例)

1. 原理

Android热修复方案研究(含AOP知识)_第3张图片

2. 方法替换(AOP)

  搞过 Android Aop 的同学知道,我们可以在执行一个方法的前插入另一个方法,运用这个思路,我们可以把有 bug 的方法替换成我们下发的新方法。

下边是 AndFix 使用 JNI hook 方法的一段代码,供大家理解。

Android热修复方案研究(含AOP知识)_第4张图片

Android AOP 常用有的方法有 JNI HOOK 和 静态织入。
常用的静态织入的库有:
Aspectj是静态织入。静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。
ASM或者Javassist 是Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。

3. ApkPatch tool

  AndFix 提供了一个打包 patch 的工具,这个工具将旧Apk和新Apk做 diff 得出一个patch apk。

熟悉增量更新的同学应该知道,增量更新也是做 diff 求增量包,但是他是在字节码层面上求增量包,增量包+旧 apk 合并成新 apk。

  而ApkPatch是通过对比两个 apk 反编译后的 smali 文本文件来求 diff 的。所以他是从 class 层面上求 diff。得到的patch就是标准的 dex 包。 该 dex 可直接被 load。

4. 以前注意事项

  1. 一个 patch 包要修复哪些类的哪些方法,这个路径信息会被打包到 patch.apk 的META-INFO里

  2. patch.apk在打包时要使用相同的签名。

  3. 混淆的情况:打包 patch.apk 时要使用主apk混淆时导出的 mapping 文件,防止主apk和patch.apk 由于混淆而无法对应相应的类和函数。

  4. 目前 apkpatch 没有开源,还有一些小 bug,如不支持 mulitdex。虽然没有开源但还是有方法修复的,比如反编译导出源码、还有 javasist 神器。具体怎么修复以后再说,也可能官方会修复。

你可能感兴趣的:(android,移动开发,hotfix,热修复)