Android热修复浅析

背景

当一个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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容