【一、前言】
插件化技术最初源于免安装运行apk的想法,支持插件化的app可以在运行时加载和运行插件,这样便可以将app中一些不常用的功能模块做成插件,一方面减小了安装包的大小,另一方面可以实现app功能的动态扩展。小编所在项目,近期有插件相关测试需求,为了更深入的进行测试,进行了学习。
【二、插件化简介、原理】
1、简介
Android中插件化,顾名思义,就是把一些核心复杂依赖度高的业务模块封装成独立的插件,然后根据不同业务需求进行不同组合,动态进行替换,可对插件进行管理、更新,后期对插件也可进行版本管理等操作。插件化,有两个重要概念:
宿主
所谓宿主,就是需要能提供运行环境,给资源调用提供上下文环境,一般也就是我们主 apk,要运行的应用,它作为应用的主工程所在,实现了一套插件的加载和管理的框架,插件都是依托于宿主的apk而存在的。
插件
插件可以想象成每个独立的功能模块封装为一个小apk,可以通过在线配置和更新实现插件apk在宿主apk中的上线和下线,以及动态更新等功能。
2、插件化技术优势
(1). 用户不用重新安装 apk 就能升级应用功能,减少发版本频率,增加用户体验。
(2). 提供一种快速修复线上BUG和更新的能力。
(3). 按需加载不同的模块,实现灵活的功能配置,减少服务器对旧版本接口兼容压力。
(4). 模块化、解耦合、并行开发、65535问题。
3、插件化原理
在Android中应用插件化技术,也就是动态加载的过程,分为以下几步:
(1). 把可执行文件(.so/dex/jar/apk 等)拷贝到应用 APP 内部。
(2). 加载可执行文件,更换静态资源。
(3). 调用具体的方法执行业务逻辑。
Android 项目中,动态加载技术按照加载的可执行文件的不同大致可以分为两种:
(1). 动态加载 .so 库
(2). 动态加载 dex/jar/apk文件(现在动态加载普遍说的是这种)
4、Android的类加载
插件化技术涉及得非常广泛,其中最核心的就是Android的类加载机制和反射机制。
ClassLoader又叫类加载器,是专门处理类加载,一个APP可以存在多个ClassLoader。
“基于 ClassLoader的动态加载dex/jar/apk 文件”,就是我们指在 Android中动态加载由Java代码编译而来的dex包并执行其中的代码逻辑,目前说的动态加载,指的就是这种。(Android 中的ClassLoader 机制主要用来加载dex文件)
Android 项目中,所有Java代码都会被编译成dex文件,Android 应用运行时,就是通过执行dex文件里的业务代码逻辑来工作的。使用动态加载技术可以在 Android 应用运行时加载外部的dex文件,而通过网络下载新的dex文件并替换原有的dex文件就可以达到不安装新apk文件就升级应用(改变代码逻辑)的目的。
Android中的类加载系统的ClassLoader可以大致划分为BaseDexClassLoader,SecureClassLoader。继承BaseDexClassLoader,常用的有两种类加载器,DexClassLoader和PathClassLoader。
android类加载继承关系图
(1). PathClassLoader:
提供一个简单的类加载器实现,该实现对本地文件系统中的文件和目录列表进行操作,但不尝试从网络加载类。
Android将该类用于其系统类加载器和应用程序类加载器(简单讲只能加载已经安装到 Android 系统中的 apk 文件)。
(2). DexClassLoader:
支持加
载外部的 apk、Jar 或者 dex 文件(简单讲可加载未安装的apk),符合插件化需求。
5、资源加载
Android系统加载资源都是通过Resource资源对象来进行加载的,因此只需要添加资源(即apk文件)所在路径到AssetManager中,即可实现对插件资源的访问。由于AssetManager并不是一个public的类,需要通过反射去创建,并且部分Rom对创建的Resource类进行了修改,所以需要考虑不同Rom的兼容性。
6、组件的加载
Android拥有四大组件,Activity、Service、ContentProvider、BoradCastRecevier,每个组件的属性及生命周期也不一样,所以关于插件中加载的组件就需要分别研究每个组件是如何加载的,其中以Activity最为复杂,不同框架采用的方法也不尽相同。
【三、插件化框架】
1、插件化框架
下面是比较出名的几个开源的插件化框架,按照出现的时间排序。根据实现原理可以将这几个框架划分成了三代。
第一代:dynamic-load-apk最早使用ProxyActivity这种静态代理技术,由ProxyActivity去控制插件中PluginActivity的生命周期。该种方式缺点明显,插件中的activity必须继承PluginActivity,开发时要小心处理context。而DroidPlugin通过Hook系统服务的方式启动插件中的Activity,使得开发插件的过程和开发普通的app没有什么区别,但是由于hook过多系统服务,异常复杂且不够稳定。
第二代:为了同时达到插件开发的低侵入性(像开发普通app一样开发插件)和框架的稳定性,在实现原理上都是趋近于选择尽量少的hook,并通过在manifest中预埋一些组件实现对四大组件的插件化。另外各个框架根据其设计思想都做了不同程度的扩展,其中Small更是做成了一个跨平台,组件化的开发框架。
第三代:VirtualApp能够完全模拟app的运行环境,能够实现app的免安装运行和双开技术。Atlas是阿里开源出来的一个结合组件化和热修复技术的一个app基础框架。
2、RePlugin 插件化框架
RePlugin,是360开源的完整的、稳定的、适合全面使用插件化框架。RePlugin是一种占坑类插件化方案,也是业内首个提出“全面插件化”(全面特性、全面兼容、全面使用)的方案。小编所在项目,采用了该框架。
主要优势
(1). 灵活:
主程序无需升级(无需在Manifest中预埋组件),即可支持新增的四大组件,甚至全新的插件。
(2). 稳定:
Hook 点仅有一处(ClassLoader),无任何 Binder Hook。
崩溃率仅为“万分之一”,并完美兼容市面上各种的 Android ROM。
(3). 特性丰富:
支持
静态 Receiver、 Task-Affinity 坑位、自定义 Theme、进程坑位、AppCompat、DataBinding等特性。
(4). 易于集成:
无论插件还是主程序,易于集成。
(5). 管理成熟:
拥有成熟稳定的“插件管理方案”,支持插件安装、升级、卸载、版本管理,甚至包括进程通讯、协议版本、安全校验等。
RePlugin对比其他插件化,它的优点在于它只Hook住了ClassLoader,最大程度保证了稳定性、兼容性和可维护。对多进程的支持,也是亮点,整体使用反射的地方也比较少。
RePlugin中存在两个主要ClassLoaer:
(1). RePluginClassLoader:
宿主App中的Loader,继承PathClassLoader,也是唯一Hook住系统的Loader。
(2). PluginDexClassLoader:
加载插件的Loader,继承DexClassLoader。
用来做一些“更高级”的特性。
【四、如何测试?】
(1)apk安装包是否有问题
外置插件apk,要做到既可以“安装到设备”,又可以“作为插件”使用。要注意是可以独立安装到手机上的,本身就是一个完整的应用。将“插件apk”直接安装到设备上(而非作为插件)试试。如果在设备中安装失败,则插件安装也一定是失败的。
(2)SD卡的读写权限
如果您的插件apk放到了SD卡上,请务必确保主程序中拥有SD卡权限(主程序Manifest要声明,且ROM允许),否则会出现权限问题,当然,放入应用的files目录则不受影响。
(3)设备内部存储空间是否不足。
通常出现此问题时其Logcat会出现“copyOrMoveApk: Copy/Move Failed”的警告。如果出现,则需要告知用户去清理手机。
(4)插件的下发和插件的更新
通常我们下发插件是把插件放在服务器上通过网络请求下发,开启服务下载apk到sdcard。插件更新除了要测试下发,还要测试同名旧插件的删除。
(5)主程序调起插件
RePlugin.install安装插件、RePlugin.startActivity启动
(6)在Application中配置签名信息
没有签名的apk可能会携带病毒,一旦不做校验,不排除有人会恶意劫持DNS或网络,并通过网络来下发恶意插件,造成不好的影响。所以我们要打开签名校验setVerifySign(true) ,对于debug包的不进行签名校验,最后把需要release包的签名加入白名单。
(7)插件权限相关(以小编所在项目为例)
插件应用所需要的权限,都通过宿主app进行申请;
(8)插件的进程相关(以小编所在项目为例)
插件是独立进程运行,退出插件应用部分,杀掉进程;
插件有独立入口,每次进入插件入口,都会新开辟一个进程,初始化,重新加载;
(9)兼容性测试
(10)稳定性测试
【五、参考】
http://www.apkbus.com/blog-945851-78342.html
https://www.xttblog.com/?p=1716
https://www.jianshu.com/p/42d35abff2d4
https://zhuanlan.zhihu.com/p/33017826
https://www.jianshu.com/p/18530be5dcdd