Android 插件化与组件化

一、组件化

组件化,就是把APP拆分成不同功能模块,形成独立组件,让宿主调用。
组件化不一定是插件化,组件化是一个更大的概念:把模块解耦,组件之间代码不依赖,宿主可以依赖组件;而插件化则具体到了技术点上,宿主通过 动态加载 来调用组件,宿主不依赖组件,达到 完全解耦 的目的(比如图片缓存就可以看成一个组件被多个 App 共用)。

二、插件化

Android程序每次更新都要下载一个完整的apk,而很多时候软件只是更新了一个小功能而已,这样的话,就显得很麻烦。如果把android程序做成主程序+插件化的形式呢,这样才利于小功能的扩展(比如一般 App 的皮肤样式就可以看成一个插件)。

通过 gradle 配置的方式,将打 debug 包和 release 包分开。这样会有一个好处,开发一个模块,在 debug 的时候,可以打成一个 apk ,独立运行测试,可以完全独立于整个宿主 APP 的其他所有组件;待到要打 release 包的时候,再把这个模块作为一个 library ,打成 aar ,作为整个宿主 APP 的一部分。而 debug 和 release 的切换都是通过 gradle 配置,可以做到无缝切换。至于模块之间的跳转,可以用别名的方式,而不是用 Activity 和 Fragment 类名。这样所有的模块和宿主 APP 都是完全解耦的,彻底解决了并行开发的可能造成的交叉依赖等问题。

主要原理是:主要利用 Java ClassLoader 的原理,如 Android 的 DexClassLoader,可动态加载的内容包括 apk、dex、jar 等。如下

DexClassLoader pluginClassLoader = 
    new DexClassLoader(dexPath, optimizedDirectory, libraryPath, parentClassLoader);
插件化的优势:
  • 适应并行开发,解耦各个模块,避免模块之间的交叉依赖,加快编译速度,从而提高并行开发效率。
  • 满足产品随时上线的需求
  • 修复因为我们对自己要求不严格而写出来的 bug。
  • 插件化的结果:分为稳定的 release 版本和不稳定的 snapshot 版本,每个模块都高度解耦,没有交叉依赖,不会出现一个模块依赖了另一个模块,其中一个人改了这个模块的代码,对另一个模块造成影响。

淘宝的框架是用了osgi的bundle概念,整个应用框架生命周期完整。

插件化弊端:

每一个插件都是一个apk,插件多的时候管理起来也麻烦。

三、Android 动态加载机制

我们知道,apk必须安装才能运行,apk未安装是不能被直接调起来的,但是我们可以采用一个程序(称之为宿主程序)去动态加载apk文件并将其放在自己的进程中执行。

四、Android 动态升级、增量更新

Google I/O 上提及的 Smart App update,即应用增量升级,或者叫做差分升级的做法,并在新版本的Google Play中得到支持。

原理

其实增量升级的原理很简单,即首先将应用的旧版本Apk与新版本Apk做差分,得到更新的部分的补丁。 在用户下载了差分包之后,需要在手机端将他们组合起来。可以参考的做法是先将手机端的旧版本软件(多半在/data/下),复制到SD卡或者cache中,将它们和之前的差分patch进行组合,得到一个新版本的apk应用。如果做过android手机OTA升级的同学应该注意到,在update.zip中的patch文件夹中有需要与系统文件同名但是以xxx.p 为后缀的文件,他们就是生成的差分patch文件。

前提

增量升级成功的前提是,用户手机端必须有能够让你拷贝出来且与你服务器用于差分的版本一致的apk,这样就存在,例如,系统内置的apk无法获取到,无法进行增量升级;对于某些与你差分版本一致,但是内容有过修改的(比如破解版apk),这样也是无法进行增量升级的,为了防止合成补丁错误,最好在补丁合成前对旧版本的apk进行sha1sum校验,保证基础包的一致性。

弊端:
  • 增量更新对于更新频繁的软件来说,版本越多,需要做的差分包就越多,这样每次更新验证的工作量会非常大

增量升级是以两个应用版本之间的差异来生成补丁的,你无法保证用户每次的及时升级到最新,所以你必须对你所发布的每一个版本都和最新的版本作差分,以便使所有版本的用户都可以差分升级,这样操作相对于原来的整包升级较为繁琐,不过可以通过自动化的脚本批量生成。

五、Class Loader类加载的方式:DexClassLoader 、 PathClassLoader与URLClassLoader
什么样的Class可以Load?

Java 里面直接把 .class 文件打包到 .jar 文件里面就可以了,但是 Android 的 Dalvik VM 是不认 Java 的 byte code 的,所以不能直接这么打包,而要用 dx 工具转成 Dalvik byte code 才可以。当然,dx 工具转了之后,jar 包里面就不是 .class 文件了,而是 .dex 文件。

Class Loader 的选择主要包括DexClassLoaderPathClassLoaderURLClassLoader
  • DexClassLoader
    可以加载文件系统上的jar、dex、apk
File dexOutputDir = context.getDir("dex", 0);   
DexClassLoader cl = 
    new DexClassLoader(jarFile.toString(), "/sdcard/test", null, ClassLoader.getSystemClassLoader()); 
  • PathClassLoader
    可以加载/data/app目录下的apk,这也意味着,它只能加载已经安装的apk。其它位置的文件加载的时候都会出现 ClassNotFoundException
 PathClassLoader cl =
     new PathClassLoader(jarFile.toString(), "/data/app/", ClassLoader.getSystemClassLoader()); 
  • URLClassLoader
    可以加载java中的jar,但是由于dalvik不能直接识别jar,所以此方法在android中无法使用,尽管还有这个类。
    dex和apk是可以直接加载的,因为它们都是或者内部有dex文件,而原始的jar是不行的,必须转换成dalvik所能识别的字节码文件,转换工具可以使用android sdk中platform-tools目录下的dx。
//转换命令 :
dx --dex --output=dest.jar src.jar

六、热门Android插件化框架

Small、Dynamic-load-apk、ACDD、DroidPlugin(360手机助手的开源框架)

(一)、Small官网

官网
Small插件化方案适用于将一个APK拆分为多个公共库插件、业务模块插件的场景(如:插件化加载dex、资源拆分、hook)。

(二)、Dynamic-load-apk

这个项目实现了一部分的动态加载,原理是 DexClassLoader 加 Activity 代理,可以看看。即在容器中注册几个代理的 Activity,启动插件的 Activity 时实际启动的都是代理的 Activity,这样就解决了 Activity 必须注册的问题。当然这个项目里也有不少问题没解决,有兴趣可以加入他们。

(三)、AndroidDynamicLoader)

这是点评一个工程师介绍的方式,和上面不同的是:他不是用代理 Activity 的方式实现而是用 Fragment 以及 schema 的方式实现

(四)、360 的 DroidPlugin

参考

Android apk动态加载机制的研究

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,098评论 25 707
  • 最近几年移动开发业界兴起了「 插件化技术 」的旋风,各个大厂都推出了自己的插件化框架,各种开源框架都评价自身功能优...
    斜杠时光阅读 3,947评论 1 36
  • 昨天上科学课的时候,老师在黑板上出题让我们在纸上写答案,我没有认真做题,交了空白卷,科学老师特别生气把卷子发到班主...
    戚正阅读 143评论 0 1
  • 文/蔭成 昨晚六時半,蔭城古鎮降粒粒雪。雪敲竹葉沙沙響,潵衣也作聲。一夜雪落無止歇。零時出屋外,站立庭院,看簷雪滾...
    蔭成阅读 295评论 0 1
  • 村口迎客柏,崖壁四季青。 南山柏犹盛,片片动春晴。
    鸿怡轩阅读 577评论 1 2