Android插件化方案

    本文地址:http://tongxinmao.com/Article/Detail/id/467

    Android插件化方案

     

    插件化技术涉及得非常广泛,其中最核心的就是Android的类加载机制和反射机制。下图载自腾讯bugly:

    插件化发展历史

    插件化技术最初源于免安装运行apk的想法,这个免安装的apk可以理解为插件。支持插件化的app可以在运行时加载和运行插件,这样便可以将app中一些不常用的功能模块做成插件,一方面减小了安装包的大小,另一方面可以实现app功能的动态扩展。想要实现插件化,主要是解决下面三个问题:

    • 插件中代码的加载和主工程的互相调用

    • 插件中资源的加载和主工程的互相访问

    • 四大组件生命周期的管理

    下面是比较出名的几个开源的插件化框架,按照出现的时间排序。研究它们的实现原理,可以大致看出插件化技术的发展,根据实现原理可以将这几个框架划分成了三代。

    第一代:dynamic-load-apk最早使用ProxyActivity这种静态代理技术,由ProxyActivity去控制插件中PluginActivity的生命周期。该种方式缺点明显,插件中的activity必须继承PluginActivity,开发时要小心处理context。而DroidPlugin通过Hook系统服务的方式启动插件中的Activity,使得开发插件的过程和开发普通的app没有什么区别,但是由于hook过多系统服务,异常复杂且不够稳定。
    第二代:为了同时达到插件开发的低侵入性(像开发普通app一样开发插件)和框架的稳定性,在实现原理上都是趋近于选择尽量少的hook,并通过在manifest中预埋一些组件实现对四大组件的插件化。另外各个框架根据其设计思想都做了不同程度的扩展,其中Small更是做成了一个跨平台,组件化的开发框架。
    第三代:VirtualApp比较厉害,能够完全模拟app的运行环境,能够实现app的免安装运行和双开技术。Atlas是阿里开源出来的一个结合组件化和热修复技术的一个app基础框架,其广泛的应用阿里系的各个app,其号称是一个容器化框架。

    Atlas/VirtualApk/RePlugin对比

    Atlas是伴随着手机淘宝的不断发展而衍生出来的一个运行于Android系统上的一个容器化框架,我们也叫动态组件化(Dynamic Bundle)框架。它主要提供了解耦化、组件化、动态性的支持。覆盖了工程师的工程编码期、Apk运行期以及后续运维期的各种问题。

    VirtualAPK是滴滴出行自研的一款优秀的插件化框架,功能完备。支持几乎所有的Android特性;四大组件均不需要在宿主manifest中预注册,每个组件都有完整的生命周期,入侵性极低。

    RePlugin是一套完整的、稳定的、适合全面使用的,占坑类插件化方案,由360手机卫士的RePlugin Team研发,也是业内首个提出”全面插件化“(全面特性、全面兼容、全面使用)的方案。

    Atlas:https://github.com/alibaba/atlas/tree/master/atlas-docs
    VirtualAPK:https://github.com/didi/VirtualAPK/wiki
    RePlugin:https://github.com/Qihoo360/RePlugin/wiki

    一、定义

    从定义上说,Atlas定义为组件化,而VirtualAPK和RePlugin则定义为插件化。这两种还是有一点点不同的,组件化偏重于编译期,插件化偏重于运行期。换句话来说,Atlas在编译的时候是需要把bundle放在一起处理的,而后面两个则可以完全独立开,和开发新的一个apk一样,最后打包的时候配置一下就行。

    二、接入难度

    初次接入Atlas,那真的会有点懵逼,官方文档已经万年没更新的,GitHub上面的demo和文档上的好多都不一样,就算接入了,也会出现一堆问题,简直想死。VirtualAPK,滴滴这个,接入还算简单的了,文档也比较完善。RePlugin,360这个也挺简单的,宿主和插件分得很清楚。所以接入难度:RePlugin最快,VirtualAPK其次,Atlas最麻烦。

    三、功能

    三者都有的功能是远程bundle,按需加载。意思是项目中某个模块,打包的时候不打进apk,等你安装了,需要用到的时候再下载那个模块进行加载显示,从而减少apk的安装体积。Atlas会把插件打成so的形式,而VirtualAPK和RePlugin会打成apk的形式,都是放在内存卡,然后调用各自的安装加载方法就行。Atlas安装后,可以把so删掉,但VirtualAPK的apk需要一直在内存卡,否则是打不开的,而RePlugin安装后会自动备份一个apk到缓存目录。除了远程bundle功能,Atlas还有热修复的功能,可以不升级apk就实现宿主和组件的更新。

    四、更新插件方式

    Atlas更新插件的话,必须要和宿主一起,打差异补丁才能更新,而VirtualAPK和RePlugin是可以直接通过下载一个新的插件apk,然后调安装方法就能实现插件的更新。

    五、插件独立性

    Atlas和宿主的依赖还是挺多,毕竟官方也强调是组件化,不是插件化。而VirtualAPK,它可以是一个独立的app,但插件里面也定义和宿主的关联,就是说这个插件apk并不能给其他宿主用,只能给插件里面声明的那个宿主使用。RePlugin呢,就比较独立了,里面不用声明和宿主的联系,所以你生成一个插件后,这个插件可以给其他宿主调用。

    六、宿主和插件的公共库

    如果宿主和插件都用到一些公共依赖库,比如http库,图片加载库,这个时候怎么处理?Atlas处理就简单了,毕竟是组件化,和宿主的项目都是在一起。可以在项目里面定义一个middleLibrary,这个库里面依赖一些公共的库或者资源,然后宿主和插件都依赖他就行了。VirtualAPK呢,由于插件里面要声明和宿主的关联,所以他会自动检测,如果插件中依赖的库,在宿主里面也有的话,他会自动去掉一个,不会重复。RePlugin是比较独立的,没有和宿主太多联系,所以目前大家的做法是宿主compile,插件 provided的形式,而共用资源的话,RePlugin是不提倡的了。

    总结

    如果你的app需要热更新和插件的功能,推荐使用Atlas;如果你的app仅用到插件,在需要的时候才下载加载的话,你可以选择VirtualAPK和RePlugin;如果你的插件希望其他宿主也能用的话,那就只能RePlugin了,RePlugin就像一个应用市场,你的宿主仅仅是一个壳,然后把需要的插件下载加载使用就行,更新的话也无需更新宿主,直接更新插件就行。

    Atlas

    Atlas是伴随着手机淘宝的不断发展而衍生出来的一个运行于Android系统上的一个容器化框架,我们也叫动态组件化(Dynamic Bundle)框架。它主要提供了解耦化、组件化、动态性的支持。覆盖了工程师的工程编码期、Apk运行期以及后续运维期的各种问题。

    包结构

    其整体包结构和正常Apk包结构类似。区别在于armeabi中存放大量的so,每个so都是APK转过来的,作为一个单独的bundle。

    架构

    这一块是Atlas的整体设计,分为五层:

    • 第一层我们称之为Hack层,包括OS Hack toolkit & verifier,这里我们对系统能力做一些扩展,然后做一些安全校验。

    • 第二层是Bundle Franework,就是我们的容器基础框架,提供Bundle管理、加载、生命周期、安全等一些最基本的能力。

    • 第三层是运行期管理层,包括清单,我们会把所有的Bundle和它们的能力列在一个清单上,在调用时方便查找;另外是版本管理,会对所有Bundle的版本进行管理;再就是代理,这里就是和业界一些插件化框架机制类似的地方,我们会代理系统的运行环境,让Bundle运行在我们的容器框架上;然后还有调试和监控工具,是为了方便工程期开发调试。

    • 第四层是业务层了,这里我们向业务方暴露了一些接口,如框架生命周期、配置文件、工具库等等。

    • 最上面一层是应用接入层,就是我们的业务代码了。

    技术细节

    1、Manifest依赖
    Bundle的Manifest在编译期会进行Merge,Bundle的依赖会单独Merge,因为涉及依赖仲裁最终输出BundleInfoList

    2、多ClassLoader
    为什么要用多ClassLoader,我的猜想是,类卸载。
    JVM提供的类加载器始终不会释放,因此根据可达性,其加载出来的类,也始终不会释放,但是用户自定义的就可以。
    这保证了一个组件在使用完以后,不存在任何实例化对象,任何类对象,保证了性能稳定。

    DelegateClassLoader先查找宿主Bundle的PathClassLoader,然后根据BundleInfoList,查找对应Bundle的BundleClassLoader

    3、资源

    用DelegeteResources替换系统的Resource,Bundle的资源在运行期会添加到AssertsPath中
    并且进行分区,防止资源错乱
    并且根据ART、Dalvik适配以及机型适配
    为了防止资源名冲突,在资源名前后添加bundle独有id

    4、按需加载

    在想用一个组件的时候,到BundleInfoList中查找对应的Bundle,进行加载
    每个组件都有生命周期管理,这样保证组件在不用的时候资源可以释放

    5、动态化

    主Bundle基于ClassLoader实现,业务Bundle基于差量Merge
    可以结合Andfix,它基于Native Hook实现,用于方法的动态修改

    问题

    为什么atlas这么好,支付宝却开始弃用了呢?诱因是android p的发布,大家可以看看这篇了解下 https://blog.csdn.net/tyro_smallnew/article/details/80468034 (Android P阻止调用非sdk api后,Atlas该何去何从)。

    android p开始android开始禁止开发者使用非官方api,也就是禁止反射使用android不想让开发者使用的类和属性,但是atlas的工作原理就是反射这些不让用的api。

    然而android p并不是主要原因,主要原因是 Atlas并不是刚需而且有些限制:
    1、基于动态化加载的方案有许多,前端技术已经开始应用到app开发中,weex rn性能也已经达到开发者预期,前端方案明显是比atlas更有优势,而在支付宝中你会发现大部分都是前端页面
    2、插件更新其实并不常用,一般大厂的应用都通过严谨的测试,出问题的概率比较小,大部分逻辑都是服务端来实现,可控性很强,所以插件更新在一些公司没有用武之地
    3、Atlas依赖管理比较复杂,插件之间存在依赖也可能是多级依赖,如果要跨插件依赖需要整理好依赖树,但需求常改,之前的依赖树可能不符合需求需要重整,这个时候非常耗时耗力,而原生开发的依赖管理就方便得多
    4、兼容问题,Atlas经历了好几代android的兼容:5.0时代的art虚拟机兼容、7.0浏览器资源加载兼容、各个版本的api兼容。。。你会在atlas核心代码中发现很多if else来判断android版本,不过atlas做的不错兼容的也很好,但每次android出版本都要兼容一次确实费时费力

    Atlas support android Q

    Atlas 5.1.0.9-rc26 已发布,此次更新较为重大,官方提醒升级请慎重。

    主要更新内容如下:

    • 支持 Android Q,弃用 atlasupdate 项目

    • bundle 需要在运行时打包在 maindex 中

    • 未来将不再支持动态部署

    • dexpatch 仅在 Android P 以下的版本受支持,并且 Atlas 不会在 Android P 及更高版本上加载补丁(新补丁将在稍后提供)

    • 弃用 DelegateClassloader、DelegateResources、BundleClassloader、InstrumentationHook 等

    • 如果想要在使用这个 bundle 之前初始化一个 bundle,可以使用:BundleIniter.initBundle(String bundleName,null)

    • 不支持 bundle 依赖项,因为所有 bundle 都在运行时使用 PathClassloader

    • 之后将不支持远程视图和远程片段,因为所有 bundle 都在运行时使用 PathClassloader

    • AtlasDemo 已更新

    参考资料

    https://www.jianshu.com/p/ceded2da7847
    《Android插件化技术——原理篇》

    atlas:
    1.https://github.com/alibaba/atlas
    2.https://blog.csdn.net/qq_36523667/article/details/99178542
    3.https://mp.weixin.qq.com/s/G0dsrVYytT8WdJ6U90NPiA
    4.https://www.jianshu.com/p/d3d881a59561
    5.开源Android容器化框架Atlas开发者指南


    上一篇:爱思助手功能原理 libimobiledevice
    下一篇:USB编程入门必知的8个问题