美文网首页
Android热修复浅析

Android热修复浅析

作者: 灬丨墨殇丶 | 来源:发表于2015-12-31 13:59 被阅读0次

    背景

    当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。有时候仅仅是为了修改了一行代码,也要付出巨大的成本进行换包和重新发布。

    这时候就提出一个问题:有没有办法以补丁的方式动态修复紧急Bug,不再需要重新发布App,不再需要用户重新下载,覆盖安装?

    答案是:可以的

    解决方案

    1、Xposed

    先来了解一下Xposed:诞生于XDA论坛,类似一个应用平台,不同的是其提供诸多系统级的应用。可实现许多神奇的功能。Xposed需要以越狱为前提,也就是说需要root权限,想了解详细,可以自行查阅相关资料,由于需要root权限,但我们的APP对于用户的手机来说,不太可能人人都root,用户也不会自行去安装这个工具,所以此方案对我们APP来说不合适。

    2、Dexposed

    DexPosed是强大而无侵入的AOP(面向切面编程)运行Android应用程序开发框架,基于开源的Xposed框架项目的工作(Xposed是修改系统框架服务的框架),拥有强大的:「原方法前hook」「方法替换」「原方法后hook」三种方式。相互组合,可依据你的hook思想,解决和规避几乎所有的意外情形。它更像是一个hook工具,效果跟使用者思路关系紧密,是地地道道的hook方案。在阿里有着良好的实践成果。

    此方案的确可以解决BUG的热修复问题,但有很大的弊端,就是系统兼容性问题:

    支持的系统

    也就是说对于Android5.0系统之后,我们的热修复还是失败的,那么有木有一种方案是,不需要root,而且平台范围支持广的方案呢?那就是我们今天要重点说的AndFix方案了。

    3、AndFix

    AndFix,全称是Android hot-fix。是阿里开源的一个热补丁框架,允许APP在不重新发布版本的情况下修复线上的bug。支持Android 2.3 到 6.0,并且支持arm 与 X86系统架构的设备。完美支持Dalvik与ART的Runtime,补丁文件是以 .apatch 结尾的文件。

    AndFix原理

    AndFix的原理就是方法的替换,把有bug的方法替换成补丁文件中的方法。

    注:在Native层使用指针替换的方式替换bug方法,已达到修复bug的目的。


    使用AndFix修复热修复的整体流程:


    方法替换过程:

    Android上如何使用

    1.在自定义Application中初始化,为了更早的修复应用中的bug。

    2.如果有新的补丁需要修复,下载完成后,进行以下操作:

    //添加patch,只需指定patch的路径即可,补丁会立即生效

    mPatchManager.addPatch(path);

    3.当apk版本升级,需要把之前patch文件的删除,需要以下操作:

    mPatchManager.removeAllPatch();

    使用工具:apkpatch-1.0.3

    它根据两个apk差别来生成apatch文件,不要将其完全理解成是一个差异文件。它是对比两个apk中的smali文件,找到不同的方法,增加方法annotation(供客户端修复逻辑识别并修复),保留此方法所在类的smali描述,修改类名、将其再打成dex,并与META-INF下的签名、证书、包含有patch信息的PATCH.MF一并打成一个压缩文件,文件格式命为apatch。

    对smali类方法修改的内容如下:

    .class public Lcom/open/andfixdemo/MainActivity_CF;

    .super Landroid/app/Activity;

    .source "MainActivity.java"

    .method public showResultAsTextView()V

    .locals 2

    .annotation runtime Lcom/alipay/euler/andfix/annotation/MethodReplace;

    clazz = "com.open.andfixdemo.MainActivity"

    method = "showResultAsTextView"

    .end annotation

    .prologue

    .line 42

    const v1, 0x7f080002

    invoke-virtual {p0, v1}, Lcom/open/andfixdemo/MainActivity_CF;->findViewById(I)Landroid/view/View;

    move-result-object v0

    check-cast v0, Landroid/widget/TextView;

    .line 43

    .local v0, "textView":Landroid/widget/TextView;

    const-string v1, "4"

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    .line 44

    return-void

    .end method

    .method public showResultAsToast()V

    .locals 2

    .annotation runtime Lcom/alipay/euler/andfix/annotation/MethodReplace;

    clazz = "com.open.andfixdemo.MainActivity"

    method = "showResultAsToast"

    .end annotation

    .prologue

    .line 38

    const-string v0, "2"

    const/4 v1, 0x1

    invoke-static {p0, v0, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v0

    invoke-virtual {v0}, Landroid/widget/Toast;->show()V

    .line 39

    return-void

    .end method

    请留意这些修改:

    类名由MainActivity被修改成为MainActivity_CF。

    被替换的方法showResultAsTextView、showResultAsToast被添加了一个MethodReplace注解。注解描述中说明了原类及原方法。

    由此,你应该了解到,对于客户端,这些信息已经足够。那么客户端的处理为:解析apatch->解析dex->加载类->识别含有MethodReplace注解的方法->根据原方法签名已经新方法smali描述进行hook并替换。

    命令:

    apkpatch.bat-f new.apk-t old.apk-o output-k debug.keystore-p android-a androiddebugkey-e android

    -f:新版本

    -t: 旧版本

    -o: 输出目录

    -k: 打包所用的keystore

    -p: keystore的密码

    -a: keystore 用户别名

    -e: keystore 用户别名密码

    注:debug.keystore我用的是.android目录下默认签名工具,需要先把debug.keystore拷到apkpatch-1.0.3根目录下

    执行完命令,就会在输出目录中输出.apatch文件

    .apatch文件根目录内容:

    META_INF文件下内容:

    PATCH.MF文件内容:

    diff.dex文件反编译后的结果:

    在Android Studio使用

    gradle dependency:

    dependencies{

         compile 'com.alipay.euler:andfix:0.3.1@aar'

    }

    在Eclipse使用

    把Java层的代码引入到你的工程,配置Ndk开发环境并把jni Native代码添加进来。

    代码混淆(ProGuard)

    -keep class *extendsjava.lang.annotation.Annotation

    -keep classeswithmembernamesclass* {

        native <methods>;

    }

    其他方案

    DexPosed和AndFix都属于修改Java类的C层对象来实现实现热修复,QQ空间的nuwa方案是通过修改BaseDexClassLoader中的pathList,来动态加载dex方式实现热修复。后者纯java实现,但需要hack类的优化流程,将打CLASS_ISPREVERIFIED标签的类,去除此标签,以解决类与类引用不在一个dex中的异常问题。这会放弃dex optimize对启动运行速度的优化。原则上,这对于方法数没有大到需要multidex的应用,损失更明显。

    问题:

    1、线上分次发布多patch

    2、拿不到签名工具

    参考资料:

    1、alibaba/AndFix · GitHub

    2、alibaba/dexposed · GitHub

    3、【新技能get】让App像Web一样发布新版本

    4、Alibaba-Dexposed框架在线热补丁修复的使用 - Coolspan - 博客频道 - CSDN.NET

    5、Android-FixBug热修复框架的使用及源码分析(不发版修复bug) - Coolspan - 博客频道 - CSDN.NET

    相关文章

      网友评论

          本文标题:Android热修复浅析

          本文链接:https://www.haomeiwen.com/subject/sluihttx.html