动态加载的类型

现在网络上有许多关于动态加载的介绍的文章,谈及的关键词汇有动态加载插件化热部署热修复等,对于一些刚接触这方面开发技术的人来说,可能容易混淆。

动态加载的类型

无论是插件化、热部署还是热修复,这些技术的根源都可是说是动态加载,这也是我把 “动态加载” 作为这个系列文章主题的原因。

动态加载,就是在程序运行时,加载外部的可执行文件并运行。这里的运行时就是指应用冷启动并开始工作后;外部可以是可以是 SD 卡,可以是 data 目录,也可以是 jniLib 目录,这些可执行文件是没有随着应用一起编译的。

Android 的动态加载按照工作机制的不同,可以分为虚拟机层动态加载Native 层动态加载两大类。

运行在虚拟机

简单来说就是只用 JAVA 代码搞定的类型。

基于虚拟机的动态加载技术的核心是类加载器 ClassLoader,通过它我们能够加载一些新的类,这种方式也是目前大部分技术文章谈到的加载方式。其中,根据 ClassLoader 使用方式的不同,又演变出 “热部署”、“插件化”、“热修复” 等技术。

热部署

加载外部可执行文件的 ClassLoader 实例与原 APP 的 ClassLoader 实例是互相独立的(不在同一棵代理树上),加载进来的新的类与原 APP(宿主)里存在的类互相独立,根据 Java 对类的定义,因为这些类的 ClassLoader 不同,所以他们即便包名和类名一致,或者有继承关系,他们也属于不懂的类。所以以这种方式加载进来的类与原有的类不能互通,不能污染宿主原有的类,适合用来动态加载一些独立的业务,比如一些推广的游戏,在宿主上提供一个入口,用户不需要安装游戏就能运行。因为这种方式起到不用安装就能部署游戏的作用,所以称为热部署。

插件化

加载外部可执行文件的 ClassLoader 实例与宿主的 ClassLoader 实例不是互相独立的,用宿主的 ClassLoader 加载过的类就无法从外部可执行文件中再次加载,它们可以共用一个公共库,习惯上把外部可执行文件称为插件。插件里可以存放公共库里一些借口的实现类,可以有一些新的 Activity 或者 Service 等组件,可以把一些宿主里的业务挪到插件中,插件可以自主升级,不用随着宿主 APP 发版。

热修复

在使用插件化技术的同时,也可以使用插件中的新的类来替换宿主同名的类,这样就能修复宿主中原有的类存在的 BUG。相比插件化,热修复因为不需要考虑组件和 res 资源的问题,所以相对简单得许多,要保证插件种新的类的加载要在加载宿主中原有类的之前。

拆分 DEX

相信大家都知道打包 DEX 时 65536 方法数超标问题,也就是一个 DEX 只能有 65536 个方法,因此有了 multi-dex 的解决方案,把本来只有一个的 DEX,拆分成复数以上的 DEX,运行时挨个加载进来,这其实也算是一种动态加载,只不过实现过程对开发者是透明的。

除此之外,还有另一种拆分 DEX 是用于减少冷启动的时间的。冷启动是指应用第一次从用户点击到完成初始化工作的全部过程。随着现在 APP 的体积不断增长,一些 APP 的 DEX 文件十分庞大,APP 在启动的时候,单单加载所有的 DEX 文件就需要非常多的耗时,所以用户点击 APP 的时候会有一个明显的卡顿过程。因此有一种拆分 DEX 的方案是 “拆分一个启动闪屏用的 DEX,里面只存放启动闪屏界面需要用到的类,因此非常小,其他类放到其他 DEX 里面”,启动的时候因为只需要加载闪屏的 DEX,所以非常快,APP 进入闪屏后,通过异步任务去完成其他 DEX 的加载,就能消除卡顿的过程。

第一种拆分 DEX 是官方支持的,开发者只需要打开 multi-dex 功能即可;第二种拆分 DEX 则需要开发者自己设计。

基于 ClassLoader 的动态加载都有个共同的特点,就是新的类一旦加载进内存了,就无法再次替换了,所以无法在运行时候升级功能,需要重启 APP 才能生效。

运行在 Native

有另一种动态加载方式是工作在 Native 层的,相比于 ClassLoader,在 Native 层的动态加载不需要重新启动 APP 就能生效,这类的加载有 加载 SO 库 和 基于 JNI HOOK 的热修复。

加载 SO 库

加载 SO 库是最常见的 Native 动态加载,我们项目经常中使用 SO 库,编译 APP 的时候,SO 并不会参与编译,会原封不动被拷贝到 APK 包里的 lib 目录下,安装 APK 的时候,系统会扫描 lib 文件夹下支持当前设备 CPU 类型(比如 arm 或 x86)的 SO 库(APK 包会带有多种 CPU 类型对应的 SO 库,安装的时候只需要对应类型的)并拷贝到系统安装目录,APP 在运行时可以调用 System#loadLibrary方法动态加载对应的 SO 库,此外还可以调用System#load加载指定路径上的 SO 库。

现在的 APK 里面往往带有非常多的 SO 库,而 APP 运行时只需要用到对应 CPU 类型的 SO 库,因此把 SO 库从 APK 包里剥离出来也是 APK 瘦身的有效手段。

JNI HOOK

基于 JNI HOOK 的热修复技术的代表框架有阿里巴巴的 AndFix。Android 中,修复 BUG 的方式就是更新类的方法,和 ClassLoader 通过加载新的类来更换方法的实现的想法一样,AndFix 也是通过更换方法的做法来实现热修复,不过做法比较取巧。Android 中执行 Native 方法的时候,会去 SO 库中查找对应的 C/C++ 方法,而 AndFix 先把普通 Java 方法用 Native 方法代替,再通过更换不同 SO 库还更换 Native 方法的实现。

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

推荐阅读更多精彩内容

  • 动态加载技术 介绍 在程序运行的时候,加载一些程序自身原本不存在的可执行文件并运行这些文件里的代码逻辑。 动态调用...
    冰点k阅读 3,950评论 1 11
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,085评论 25 707
  • Android博客周刊专题之#插件化开发# 本期专栏目讨论插件化开发。插件化涉及的东西很多,所以我们需要多个维度去...
    sufun_wu阅读 6,768评论 2 58
  • 最近几年移动开发业界兴起了「 插件化技术 」的旋风,各个大厂都推出了自己的插件化框架,各种开源框架都评价自身功能优...
    斜杠时光阅读 3,947评论 1 36
  • 黑夜来临 我蜷缩在阴暗的角落 像极度惊恐的猫 拼命拱起嶙峋的背脊 那双萤绿色的 神秘、哀怨、而又凄凉的眼 望着这无...
    姀萧阅读 168评论 0 8