1. 聚能聊>
  2. 话题详情

业界首部安卓热修复宝典出炉!你想知道的一切都在这里了

热修复技术,可以看做是Android平台发展成熟至一定阶段的必然产物。随着移动端业务的复杂性程度的增加,传统的发版更新流程显然无法满足业务和开发者的需求,热修复技术的推出很大程度上改善了这一局面。可以说,一个好的热修复技术,将为你的APP助力百倍。对于每一个想在 Android 开发领域有所造诣的开发者,掌握热修复技术更是必备的素质。

虽然方案很多,但是深入系统地讲解热修复技术细节的书籍基本没有。出于回馈业界的考虑,我们把阿里非侵入式移动热修复方案Sophix开发过程中的技术细节进行了整理归纳,推出了《深入探索Android热修复技术原理》这本书,我们从阿里Sophix方案开发过程入手权威解读,分享了阿里巴巴手淘技术团队对系统底层的原创性发现,是业界首部全方位完整介绍热修复原理的书籍。

7cd5e05c7c0be6cdef0e21dbeef3c291d90f900c_jpeg

本书推荐语:

自2014年至今,手淘定义和引领了业界Android组件化和热修复技术风潮,至于后来者 Instant App 或多或少也受了国内技术风气影响。今天看到团队同学将这块技术认真系统化整理成书,非常欣喜。在这本书里,既能看到对热修复技术风潮的发展历史系统深入总结,看到国内程序员在 Android 系统级技术持续突破上的不懈努力,更看到国内程序员坚持打造世界级优秀专业移动技术产品的雄心壮志!
——手机淘宝基础平台部负责人,阿里巴巴资深技术专家 吴志华(天施)

业内少有的讲解 Android 热修复的深度书籍,对于原理、代码讲解的非常的清晰和深入,值得 Android 工程师研读。
——手机淘宝基础架构团队负责人,阿里巴巴资深技术专家 倪生华(玄黎)

应用热修复是一项略带神秘而又颇具争议的技术,但是它的确赋予应用开发者“驾着飞机修引擎”的能力。本书从Android应用热修复技术的原理及代码实现、多种方案进行比较的角度,系统化地阐述了Android平台上的应用热修复技术。对Android应用热修复有好奇心的技术人员,这本专题书不容错过。
——计算机技术领域著名作家,阿里巴巴飞猪事业部首席架构师 潘爱民

阿里无线3年前在业界首次推出 Android 热修复技术 Dexposed,为 Android 底层技术服务于业务痛点需求点亮了一个崭新的技术方向,点燃了业界百花齐放的探索热潮。Sophix 的发布让我们再次看到了阿里无线在这个技术领域的自我迭代和锐意创新。这是一个技术改变格局的时代,同时也是一个能人辈出的时代!
——安卓绿色联盟发起人,手机淘宝前架构师 冯森林


掌握热修复技术是安卓开发者必备技能,那么一起来聊下:

你之前在实际开发项目中用过热修复吗?使用感受如何?

对于阿里非侵入式Sophix热修复,你有什么好的建议和意见?

你觉得热修复技术将给Android的生态带来怎样的变化?


《深入探索Android热修复技术原理》现在可以免费下载啦!

下载获取地址:免费下载!业界首部安卓热修复宝典出炉

当然,也非常欢迎大家把阅读过程中遇到的问题在这里进行交流,包括一些技术难点以及排版文字错误。如果能够亲身来体验一下我们的阿里非侵入式移动热修复方案Sophix方案来谈谈实际使用感受就更好了~

参与话题

奖品区域 活动规则 活动已结束,可继续参与讨论哦

  • 奖品一

    淘公仔 x 1

  • 奖品二

    阿里云代金券 x 2

23个回答

2

浮生递归 已获得阿里云代金券

你之前在实际开发项目中用过热修复吗?使用感受如何?
热修复也只是在C/S类项目中存在,像我们搞B/S项目,从来都是热修复的。最早体验C/S项目的热修复是暴雪的魔兽世界热更新。那时候暴雪刚推出不停机升级维护,大家都感觉屌炸天,直接进入了另一个时代啊。不过热修复确实需要很高的技术支持,特别是对于结构异常复杂的大系统。所以很多游戏运营商至今仍然处在停机维护的阶段。

对于阿里非侵入式Sophix热修复,你有什么好的建议和意见?
自动识别网络类型,自动下载更新,在用户不操作时,后台分析硬件使用资源后再选择性静默热修复。即用户在WIFI下时,自动下载需更新内容。等用户没有操作APP时,分析当前系统使用资源,只调用一部分资源进行更新操作。这样当用户需要操作时,并不会影响相应速度。

你觉得热修复技术将给Android的生态带来怎样的变化?
本来是很普通的事情。但是IOS禁了热修复,所以安卓的热修复技术直接甩了苹果几条街,终于咸鱼翻身了,终于可以吐槽苹果用户总是要下载才能更新APP了,动不动就是几百MB甚至一个G的流量,哈哈

PS:能来张代金券么?

南京五七三 回复

苹果一直防着开发者绕开AppStore自行更新破坏生态,相对封闭,但是封闭的好处也在于安全性有提高,不然Android APP开发者随意更新,说不定临时来点恶意代码偷点东西,谁又能发现呢。

张启露 回复

热修复是个很好的技术,提高了用户的体验,应用更稳定可靠。

万壑 回复

即使是正常发版也无法避免开发者隐藏的恶意代码,这个不应该由热修复背锅。热修复只是加快了发版更新流程。客观来说,审核机制是在每个用户心里的,你如果做了让用户失望的事,用户肯定不会再使用你的app了。所以从这点来说,iOS的安全性并不见得因此就更好了,而带来的不便确是实实在在的。

评论
0

1294900670004414 已获得淘公仔

自己做过一个伪热修复方案,接入广告sdk时候,因为某些应用市场希望我们接入它们的广告,上架前会检测广告sdk,发现含有广告,会直接降低评级,导致用户难以搜索到,所以将广告sdk插件化了,运行时加载其中的类,完成广告的显示,这里只有代码的热加载,不涉及资源和动态链接库

0

1853794906995000 已获得阿里云代金券

1.目前看了成功率统计在95%最右,还有就是针对root掉手机不是太高,目前接入也很方便,但是我们只是修复简单的,没有太大的包需要修复,希望后面的稳定性可以继续提高。已发了一个版本,目前没有太大问题

0

1124999757149470

感觉文章中很多地方表述有些问题,看得人很奇怪,不知道又没人有同感,不过还是给阿里一个赞~

万壑 回复

欢迎详细指出,我们会继续改进~

nickaa 回复

你好!很感谢你在android热修复方面给我提供了一些新思路,我有一些疑问一直困扰着我!

是这样的,我在看你 https://yq.aliyun.com/articles/96378?t=t1 这篇文章的时候,里面提到 优雅的替换AssetManager方式。是通过AssetManager隐藏API destroy(),init()来清空c++层的AssetManager对象及内部的资源表。

但我在现实的时候并不是这样,我直接清空后,再addAssetPath完整的新的APK资源包,会报找不到资源:
Failure getting entry for 0x7ff****** (t=,e=)(error = -75)

请问你在这里的直接替换原先的AssetManager方案上有遇到这个问题吗?如何解决,可以给个思路吗?

非常感谢!!!

评论
0

mr9527

从1.X版本就开始使用,傻瓜式接入,其他平台可以修复的Sophix都可以,技术客服回复很及时,还出了相关书籍,点赞,唯一遗憾的是现在加载率成功率还不是很理想,只有75%,希望越来越好

万壑 回复

成功率低可能是因为在7.0机型上遇到了jit问题,可以参照这个进行配置:https://help.aliyun.com/knowledge_detail/55422.html

评论
0

happycc

热修复说白了就是”打补丁”,比如你们公司上线一个app,用户反应有重大bug,需要紧急修复。如果按照通
常做法,那就是程序猿加班搞定bug,然后测试,重新打包并发布。这样带来的问题就是成本高,效率低。于是,热
修复就应运而生.一般通过事先设定的接口从网上下载无Bug的代码来替换有Bug的代码。这样就省事多了,用
户体验也好。

热修复的原理

1.Android的类加载机制

android的类加载器分为两种,PathClassLoader和DexClassLoader,两者都继承自BaseDexClassLoader

PathClassLoader代码位于libcore\dalvik\src\main\Java\dalvik\system\PathClassLoader.java
DexClassLoader代码位于libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java
BaseDexClassLoader代码位于libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java

PathClassLoader
用来加载系统类和应用类

DexClassLoader

用来加载jar、apk、dex文件.加载jar、apk也是最终抽取里面的Dex文件进行加载.

这里写图片描述

2.热修复机制

看下PathClassLoader代码

public class PathClassLoader extends BaseDexClassLoader {

public PathClassLoader(String dexPath, ClassLoader parent) {
    super(dexPath, null, null, parent);
}

public PathClassLoader(String dexPath, String libraryPath,
        ClassLoader parent) {
    super(dexPath, null, libraryPath, parent);
}

}

DexClassLoader代码

public class DexClassLoader extends BaseDexClassLoader {

public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
    super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}

}

两个ClassLoader就两三行代码,只是调用了父类的构造函数.

public class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList;

public BaseDexClassLoader(String dexPath, File optimizedDirectory,
        String libraryPath, ClassLoader parent) {
    super(parent);
    this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
    List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
    Class c = pathList.findClass(name, suppressedExceptions);
    if (c == null) {
        ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
        for (Throwable t : suppressedExceptions) {
            cnfe.addSuppressed(t);
        }
        throw cnfe;
    }
    return c;
}

在BaseDexClassLoader 构造函数中创建一个DexPathList类的实例,这个DexPathList的构造函数会创建一个dexElements 数组

public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory) {
...
this.definingContext = definingContext;
ArrayList suppressedExceptions = new ArrayList();
//创建一个数组
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
...
}
然后BaseDexClassLoader 重写了findClass方法,调用了pathList.findClass,跳到DexPathList类中.

/* package */final class DexPathList {
...
public Class findClass(String name, List suppressed) {
//遍历该数组
for (Element element : dexElements) {
//初始化DexFile
DexFile dex = element.dexFile;

        if (dex != null) {
            //调用DexFile类的loadClassBinaryName方法返回Class实例
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }       
    return null;
}
...

}

会遍历这个数组,然后初始化DexFile,如果DexFile不为空那么调用DexFile类的loadClassBinaryName方法返回Class实例.
归纳上面的话就是:ClassLoader会遍历这个数组,然后加载这个数组中的dex文件.
而ClassLoader在加载到正确的类之后,就不会再去加载有Bug的那个类了,我们把这个正确的类放在Dex文件中,让这个Dex文件排在dexElements数组前面即可.

这里有个问题,可参考QQ空间团队的 安卓App热补丁动态修复技术介绍
概括来讲:如果引用者和被引用者的类(直接引用关系)在同一个Dex时,那么在虚拟机启动时,被引用类就会被打上CLASS_ISPREVERIFIED标志,这样被引用的类就不能进行热修复操作了.
那么我们就要阻止被引用类打上CLASS_ISPREVERIFIED标志.QQ空间的方法是在所有引用到该类的构造函数中插入一段代码,代码引用到别的类.

万壑 回复

希望能根据话题来聊聊,不要狂贴文章

评论
1

hotboy_小辉

希望热修复灰度发布,可以支持指定某一个用户,或某一些用户的修复。

0

ysr_feng

HotFix提供可视化的管理后台,以及详细的集成文档,对于开发者减少了很多工作量。经过不懈的努力,处理了很多测试遇到的问题,在项目中慢慢探索优化!
PS:天要冷了,希望来件衬衫,没有衬衫就给我来本书吧!

0

xl+

看过那个技术文档。感觉NB到不行的样子。不过可以感觉到什么都是一步一步慢慢完善起来的,其中讲的替换过程就可以看出来

0

1557495926919554

热修复解决了线上bug,差量修复.可以在用户无感知的情况下,较小流量消耗下实现用户无感知修复bug,对提升产品大有帮助

0

点滴积累

热修复方案的提出是为了紧急修复线上严重BUG,无需重新打包、测试以及向各个市场和渠道上传新包、提示用户升级等一系列操作。同时热修复具备以下优势:(1)、用户无感知修复,无需下载新的应用,代价小;(2)修复成功率高,损失降到最低;
目前在业界比较著名的有阿里的AndFix、Dexposed,腾讯QQ空间的超级补丁技术和微信的Tinker,阿里百川推出的HotFix热修复服务就基于AndFix技术,定位于线上紧急BUG的即时修复;
腾讯QQ空间的超级补丁技术基于DEX分包方案,使用了多DEX加载的原理,大致的流程是:把Bug方法修复以后,放到一个单独的DEX里,插入到dexElements数组的最前面,让虚拟机去加载修复完后的方法。
微信针对QQ空间超级补丁技术的不足提出一个提供DEX差量包,整体替换DEX的方案,主要原理与QQ空间超级补丁技术基本相同,区别在于不再将patch.dex增加到elements数组中,而是以差量的方式给出patch.dex,然后将patch.dex与应用的classes.dex合并,然后整体替换掉旧的DEX,达到修复的目的。
阿里百川推出的热修复HotFix服务,相对于QQ空间超级补丁技术和微信Tinker来说,定位于紧急Bug修复的场景下,能够最及时的修复bug,下拉补丁立即生效无需等待。
AndFix实现过程
对于实现方法的替换,需要在Native层操作,经过三个步骤:打开链接库得到操作句柄,获取native层内部函数,得到classObject对象。修改访问权限属性为public。得到新旧方法的指针,新方法指向目标方法,实现方法的替换;
image

0

小谷xg

配置方便,成功率高,对机型覆盖率广,这些问题是一个好的热修复方案必备条件。

0

张启露

热修复方案现在已经比较成熟了,热修复方案的提出是为了解决线上应用严重BUG需要紧急修复时,无需重新发布版本实时高效热修复。同时热修复有如下优势:用户无感知修复,无需下载新的应用,代价小,修复成功率高,损失降到最低;

0

王忠辉

对于我这样的经常App经常会修复,然后迭代频繁的,感觉热修复是一个很好的选择,但是希望阿里会把sophix一直免费下去

0

1545298279376240

对于微信和饿了么热修复方案来说,该方案确实感觉成熟许多,包括操作流程可以说是一键傻瓜式操作,当然作为开发者搞懂原理是必须的,虽然我还在懵懂中😂😂🤣

0

1654699091375435

服务器端的热修复有无类似实现?

0

code_xzh

现在主流的热修复方案有 支付宝的Andfix,淘宝的Dexposed,携程的Nuwa和微信Tinker。热修复的方案是基于Android的ClassLoader加载来设计的,相对于ios的Jsparch等热修复方案来说,Android的热修复方案似乎是天生的优势。虽然Android热修复很强大,但是建议不要乱用。

0

lottehu

感觉很牛逼

有5个回复被折叠为什么?
9946
浏览
0
收藏
邀请他人互动
关注
0
粉丝
21
话题
1

简介:

就职于手机淘宝。Sophix热修复方案主要开发者。

著作:

2017年 7月 《深入探索Android热修复技术原理》
在云上签发Symantec、WoSign、CFCA证书,实现网站HTTPS化,使网站可信,防劫持、防篡改、防监听...

结合大数据能力帮助电商企业快速搭建平台、应对业务高并发,剖析秒杀、视频直播等场景

充分利用阿里云现有资源管理和服务体系,引入中间件成熟的整套分布式计算框架,以应用为中心,帮助企业级客户轻松构建并...

为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本...