App像Web一样发布新版本,安卓App热补丁动态修复技术介绍 转

背景

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

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

解决方案

该方案基于的是android dex分包方案的,关于dex分包方案,网上有几篇解释了,所以这里就不再赘述,具体可以看这里https://m.oschina.net/blog/308583。

简单的概括一下,就是把多个dex文件塞入到app的classloader之中,但是android dex拆包方案中的类是没有重复的,如果classes.dex和classes1.dex中有重复的类,当用到这个重复的类的时候,系统会选择哪个类进行加载呢?

让我们来看看类加载的代码:

public Class findClass(String name, List<Throwable> suppressed) {

for (Element element : dexElements) {  //每个Element就是一个dex文件

DexFile dex = element.dexFile;

if (dex != null) {

Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);

if (clazz != null) {

return clazz;

}

}

}

if (dexElementsSuppressedExceptions != null) {

suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));

}

return null;

}

一个ClassLoader可以包含多个dex文件,每个dex文件是一个Element,多个dex文件排列成一个有序的数组dexElements,当找类的时候,会按顺序遍历dex文件,然后从当前遍历的dex文件中找类,如果找类则返回,如果找不到从下一个dex文件继续查找。

理论上,如果在不同的dex中有相同的类存在,那么会优先选择排在前面的dex文件的类,如下图:

<ignore_js_op>

在此基础上,我们构想了热补丁的方案,把有问题的类打包到一个dex(patch.dex)中去,然后把这个dex插入到Elements的最前面,如下图

<ignore_js_op>

好,该方案基于第二个拆分dex的方案,方案实现如果懂拆分dex的原理的话,大家应该很快就会实现该方案,如果没有拆分dex的项目的话,可以参考一下谷歌的multidex方案实现。然后在插入数组的时候,把补丁包插入到最前面去。

好,看似问题很简单,轻松的搞定了,让我们来试验一下,修改某个类,然后打包成dex,插入到classloader,当加载类的时候出现了(本例中是ActivityManager要被替换):

<ignore_js_op>

为什么会出现以上问题呢?

从log的意思上来讲,ModuleManager引用了ActivityManager,但是发现这这两个类所在的dex不在一起,其中:

1. ModuleManager在classes.dex中

2. ActivityManager在patch.dex中

结果发生了错误。

这里有个问题,拆分dex的很多类都不是在同一个dex内的,怎么没有问题?

让我们搜索一下抛出错误的代码所在,嘿咻嘿咻,找到了一下代码:

<ignore_js_op>

从代码上来看,如果两个相关联的类在不同的dex中就会报错,但是拆分dex没有报错这是为什么,原来这个校验的前提是:

<ignore_js_op>

如果引用者(也就是ModuleManager)这个类被打上了CLASS_ISPREVERIFIED标志,那么就会进行dex的校验。那么这个标志是什么时候被打上去的?

让我们在继续搜索一下代码,嘿咻嘿咻~~,在DexPrepare.cpp找到了一下代码:

<ignore_js_op>

这段代码是dex转化成odex(dexopt)的代码中的一段,我们知道当一个apk在安装的时候,apk中的classes.dex会被虚拟机(dexopt)优化成odex文件,然后才会拿去执行.

虚拟机在启动的时候,会有许多的启动参数,其中一项就是verify选项,当verify选项被打开的时候,上面doVerify变量为true,那么就会执行dvmVerifyClass进行类的校验,如果dvmVerifyClass校验类成功,那么这个类会被打上CLASS_ISPREVERIFIED的标志,那么具体的校验过程是什么样子的呢?

此代码在DexVerify.cpp中,如下:

<ignore_js_op>

1. 验证clazz->directMethods方法,directMethods包含了以下方法:

1. static方法

2. private方法

3. 构造函数

2. clazz->virtualMethods

1. 虚函数=override方法?

概括一下就是如果以上方法中直接引用到的类(第一层级关系,不会进行递归搜索)和clazz都在同一个dex中的话,那么这个类就会被打上CLASS_ISPREVERIFIED标志

所以为了实现补丁方案,所以必须从这些方法中入手,防止类被打上CLASS_ISPREVERIFIED标志。

<ignore_js_op>

最终空间的方案是往所有类的构造函数里面插入了一段代码,代码如下:

if (ClassVerifier.PREVENT_VERIFY) {

System.out.println(AntilazyLoad.class);

}

<ignore_js_op>

其中AntilazyLoad类会被打包成单独的hack.dex,这样当安装apk的时候,classes.dex内的类都会引用一个在不相同dex中的AntilazyLoad类,这样就防止了类被打上CLASS_ISPREVERIFIED的标志了.只要没被打上这个标志的类都可以进行打补丁操作.

然后在应用启动的时候加载进来.AntilazyLoad类所在的dex包必须被先加载进来,不然AntilazyLoad类会被标记为不存在,即使后续加载了hack.dex包,那么他也是不存在的,这样屏幕就会出现茫茫多的类AntilazyLoad找不到的log.

所以Application作为应用的入口不能插入这段代码.(因为载入hack.dex的代码是在Application中onCreate中执行的,,如果在Application的构造函数里面插入了这段代码,那么就是在hack.dex加载之前就使用该类,该类一次找不到,会被永远的打上找不到的标志)

其中:

class ClassVerifier {

public static boolean PREVENT_VERIFY = false;//false防止代码被执行,提高性能

}

之所以选择构造函数是因为他不增加方法数,一个类即使没有显式的构造函数,也会有一个隐式的默认构造函数。

空间使用的是在字节码插入代码,而不是源代码插入,使用的是javaassist库来进行字节码插入的.

隐患:

虚拟机在安装期间为类打上CLASS_ISPREVERIFIED标志是为了提高性能的,我们强制防止类被打上标志是否会影响性能?这里我们会做一下更加详细的性能测试.

但是在大项目中拆分dex的问题已经比较严重,很多类都没有被打上这个标志.

如何打包补丁包:

1.空间在正式版本发布的时候,会生成一份缓存文件,里面记录了所有class文件的md5.还有一份mapping混淆文件.

2.在后续的版本中使用-applymapping选项,应用正式版本的mapping文件,然后计算编译完成后的class文件的md5和正式版本进行比较,把不相同的class文件打包成补丁包.

备注:该方案现在也应用到我们的编译过程当中,编译不需要重新打包dex,只需要把修改过的类的class文件打包成patch dex,然后放到sdcard下,那么就会让改变的代码生效.

Bugly是腾讯内部产品质量监控平台的外发版本,其主要功能是App发布以后,对用户侧发生的crash以及卡顿现象进行监控并上报,让开发同学可以第一时间了解到app的质量情况,及时机型修改。目前腾讯内部所有的产品,均在使用其进行线上产品的崩溃监控。

时间: 2024-11-17 21:08:41

App像Web一样发布新版本,安卓App热补丁动态修复技术介绍 转的相关文章

iOS、安卓app还有web框架ui_framework轻松实现app自动化测试以及web自动化测试

一.功能介绍 Ui_framework类似于interface_framework 提供一个gem包,安装后即可使用. 1.实现了Android以及iOS app自动化测试底层基本方法封装以及测试执行报告: 2.实现了web自动化测试框架封装,实现了web标签操作予以动态方法达到元素操作目的,无需因为标签种类增加或者操作变动而增加变动底层方法 二.框架架构说明 架构图: 三.使用说明 1.  安装gem包ui_framework: 2.  脚本中require 'ui_framework' 3.

安卓app设计规范整理和Android APP设计篇(转)

随着安卓智能手机不停的更新换代.安卓手机系统越来越完美,屏幕尺寸也越来越大啦!比如最近小米的miui 6的发布和魅族手机系统的更新等等. 以小米MIUI6的安卓手机来说,MIUI6进行了全新设计,坚持“内容才是本质”的设计哲学,重新提炼内容,简化图标设计. 所以,我们在进行安卓APP设计时,需要好好调整之前的设计规范和设计细节.根据目前流行的安卓手机的系统体验来完成我们的安卓APP设计规范.应该说这是整理出最全面的安卓app设计规范. 25学堂站在不断更新和完善安卓app设计规范为宗旨!利用周末

让你在PC上调试Web App,UC浏览器发布开发者版

目前,在手机上使用浏览器访问网页,无法便捷地进行网页语言调试.手机屏幕相对较小且操作不便,直接在手机上进行网页数据调试不太现实. 因此,UC使用技术将手机网页调试信息分离,实现一种能在大屏幕.高配置PC上来调试小屏幕.低配置的手机浏览器访问的网页的开发工具--Remote Inspector(简称RI). 主要功能 Android平台UC浏览器开发者版,主要支持以下功能: DOM查看和修改 JavaScript调试.CSS调试 网络状态查看 资源文件查看 Console控制台 准备工作 手机端

Global Web Index发布社交网络现状调查,Snapchat增速领跑移动端所有App,四分之一Facebook用户年龄在45岁以上【转载+整理】

原文地址 有次上班做公交,期间听到一个老太太说:"我加你微信啊--",还有一次去看老中医,并交换了电话,可当我回去后发现这个大夫竟然加了我微信--这些都令我有点吃惊,连60.70岁老人都在用微信和QQ,尤其是微信,微信和QQ 越来越成为一种必备工具,像银行卡,像背包--像人手一部手机,而手机必须按 QQ 和微信一样. 但接下来的问题是,既然微信和QQ已经蔓延到老人,你的微信里几乎全是生活中认识的人,包括朋友.亲戚.同事,甚至是爷爷奶奶(我微信有我姑和四奶),无论是微信还是QQ它们都是熟

[转帖]银河麒麟Kydroid 2.0全新发布:原生支持海量安卓APP

银河麒麟Kydroid 2.0全新发布:原生支持海量安卓APP https://news.cnblogs.com/n/652299/将手机操作系统 转移到 桌面 跟chromebook 类似的策略吧 近些年,国产芯片不断迅猛发展,CPU 处理器有龙芯.飞腾等竞技,而有了硬件,更要有系统和软件生态,这方面的进展也值得肯定. Kydroid 是麒麟团队和技德系统为“银河麒麟操作系统”打造的一款完全原生.高兼容性的安卓运行环境,2018 年 6 月发布 1.0 正式版,现在全新的 kydroid 2.

银河麒麟Kydroid 2.0全新发布:原生支持海量安卓APP

近些年,国产芯片不断迅猛发展,CPU 处理器有龙芯.飞腾等竞技,而有了硬件,更要有系统和软件生态,这方面的进展也值得肯定. <strong>Kydroid 是麒麟团队和技德系统为"银河麒麟操作系统"打造的一款完全原生.高兼容性的安卓运行环境,2018 年 6 月发布 1.0 正式版,现在全新的 kydroid 2.0 正式版来了!</strong> 国产系统内核基本都基于 Linux,好处是开源灵活,但缺陷就是应用生态不足,特别是原本习惯的 Windows 办公

【开源】开发者新闻聚合APP 2.0.3发布(第二个稳定版本)

聚合了博客园新闻.infoq新闻.36kr新闻.oschina新闻.51cto新闻.csdn新闻: 争取做到随时刷随时有开发者的新闻! 目前还只支持安卓APP 但用的人多了,我会发布苹果版的APP 最新版本的下载地址:http://shumanu.com/DeveloperNews.apk 开源代码的地址(包含采集程序.守护程序.APP客户端和WEB服务端):https://github.com/xland/DeveloperNews 扫码下载: 来看看系统截图: 这次更新的主要内容有: 一个屏

Native APP ,Web APP,Hybrid APP三者对比

Native APP Native APP 指的是原生程序(Android.iOS.WP),一般依托于操作系统,有很强的交互,可拓展性强,需要用户下载安装使用,是一个完整的App. 原生应用程序是某一个移动平台(比如iOS或安卓)所特有的,使用相应平台支持的开发工具和语言(比如iOS平台支持Xcode和Objective-C,安卓平台支持Eclipse和Java).原生应用程序看起来(外观)和运行起来(性能)是最佳的 Native app优势: 1.速度快,性能高,用户体验更好2.可以调用手机终

hybrid app、web app与native app工具

1.使用过哪些工具? Webapp:ThinkPHP Mobile(TPM).Ionic Framework.JingleUI Hybridapp:Apicloud.Phonegap(稍了解Hbuilder.Appcan.Wex5) Nativeapp:CrossApp.React-Native.Xcode.Eclipse-ADT/Android Studio 2. 以上工具各自的编程语言是? Webapp:主要使用H5(html5.css3.js)语言规范来编写,对JS语言掌握要求较高 Hyb