一、技术背景

Android的插件化技术,目前已经比较成熟,微信、淘宝、携程、360手机助手中都应用到了插件化。插件化技术的特点是无需单独安装apk,即可运行,即插即用,无需升级宿主应用,减少app的更新频率,

除此之外他还可以降低模块耦合,按需加载,节省流量等特点。

二、已有框架技术对比

表1从是否支持四大组件、是否须在主manifest预注册等多个维度对主流开源框架进行对比,从而筛选出比较符合项目的框架有VirtualAPK、RePlugin。

表1主流开源框架的对比

特性

DynamicLoadApk

DynamicAPK

Small

DroidPlugin

VirtualAPK

RePlugin

ACDD/Atlas

支持四大组件

只支持Activity

只支持Activity

只支持Activity

全支持

全支持

全支持

全支持

组件无需在宿主manifest中预注册

×

×

插件可以依赖宿主

×

轻度依赖

支持PendingIntent

×

×

×

未明确

Android特性支持

大部分

大部分

大部分

几乎全部

几乎全部

几乎全部

未明确

兼容性适配

一般

一般

中等

未明确

插件构建

部署aapt

Gradle插件

Gradle插件

Gradle插件

部署aapt

框架轻重

相对轻量

相对轻量

相对轻量

重量

支持安卓版本

API Level 15+

API Level 9+

接入难度

侧重阶段

运行期

运行期

运行期

编译期

热修复能力

插件安装后可否删除

不能

不能

可以

插件更新方式

插件独立更新

插件独立更新

插件及宿主须同时更新

对表1各插件化框架进行筛选,最后可得出VirtualAPK为最优候选框架。

以下对重点对VirtualAPK做详细调研。

三、VirtualAPK

3.1 VirtualAPK主要优势

如下是VirtualAPK的整体架构图。

详情参见:

https://github.com/didi/VirtualAPK/wiki

3.2 VirtualAPK主要工作原理

VirtualAPK 对于插件没有额外的约束,原生的 apk 即可作为一个插件。插件工程编译生成 apk 后,通过宿主 App 加载,每个插件 apk 被加载后,都会在宿主中创建一个单独的 LoadedPlugin 对象。如上图所示,通过这些 LoadedPlugin 对象,VirtualAPK 就可以管理插件并赋予插件新的意义,使其可以像手机中安装过的App一样运行。

图2 插件开发及加载过程

      图3描述了LoadedPlugin的结构,LoadedPlugin包含有插件apk中定义的activities、services、

      broadcast receivers、providers、classloader、resources等资源,LoadedPlugin实例化及加载时机如图2所示,由PluginManager执行其loadPlugin方法将插件apk加载进dalvik。

3 LoadedPlugin结构

3.2.1基本原理

  • 动态代理

基于JDK Proxy、InvocationHandler实现对任意java类的AOP控制。

  • Hook AMS\Instrumentation\IContentProvider

    Hook技术基于反射和动态代理技术。

    VirtualAPK通过Hook技术,从而实现对Activity、Service、ContentProvider的控制。

    • Hook AMS

      Hook要点为基于动态代理技术实现ActivityManagerProxy,以实现拦截ActivityManagerService的方法调用,然后利用反射将ActivityManagerNative实例替换掉ActivityManagerNative的gDefault成员。

图4 AMS Hook代码

  • Hook Instrumentation

Hook要点为扩展Instrumentation以实现对Activity启动过程的控制,然后使用反射将扩展

Instrumentation实例替换ActivityThread对象原来的Instrumentation对象。

图5 Instrumentation Hook代码

  • Hook IContentProvider

图6 IContentProvider Hook代码

  • 合并宿主和插件的ClassLoader

    dalvik.system.BaseDexClassLoader内部定义了DexPathList,用于记录去哪里加载指定的类,而DexPathList内部定义了dexElements,专门记录已加载的dex。

    对于宿主工程来说,在加载插件工程后,将插件dex插入到宿主工程的dexElements集合后面即可,在之后的运行中就可以按需加载插件中的class。

    需要注意的是,插件中的类不可以和宿主重复 。

图 7宿主和插件Dex合并示意图

  • 合并插件和宿主的资源 重设插件资源的packageId,将插件资源和宿主资源合并

  • 去除插件包对宿主的引用 构建时通过Gradle插件去除插件对宿主的代码以及资源的引用

3.2.2四大组件的实现原理

  • Activity

    采用宿主manifest中占坑的方式来绕过系统校验,然后再加载真正的activity;

    图8描述了VirtualAPK根据launchMode定义了2(standard) + 8(singleTop) + 8(singleTask) + 8(singleInstance) = 26个SubActivity坑.

图 8 CoreLibrary工程的AndoidManifest

       图9描述了启动插件apk中activity的主要过程,也是VirtualAPK插件无需在AndroidManifest预注册的原理。该原理是VirtualAPK预先在AndroidManifest注册一些StubActivity,这些StubActivity并没有实际的代码实现,在之后启动插件Activity时,VirtualAPK将插件Activity改名为StubActivity,在绕过Android对启动插件Activity的合法校验后,再将StubActivity改回原来的Activity名称。

       该过程有两个关键点:

       1) 将插件Activity转换为StubActivity;

           该阶段的作用是绕过Android对启动Activity的限制:Activity必须先在AndroidManifest注册,否则不能被startActivity。具体实现为利用hook的VAInstrumentation拦截Instrumentation的execStartActivity方法,并在该方法内将待启动的插件Activity名称改 为StubActivity。

       2) 将StubActivity还原为插件Activity。

           此阶段的作用是继1)阶段绕过系统对插件Activity的合法校验后,将StubActivity名称改回原来的名称,以使得在Instrumentation.newActivity时实例并启动正确的目标Activity。

图9插件Activity启动过程

  • Service 动态代理AMS,拦截service相关的请求,将其中转给Service Runtime去处理,Service Runtime会接管系统的所有操作;

          插件Service的启动/关闭基于被Hook的AMS,VirtualAPK在拦截到start/bind/stop/unbind Service的调用后,会执行ActivityManagerProxy的invoke方法,之后控制流程和数据会转交给ServiceDelegate对象,之后ServiceDeletegate会判断待启动的Service是本地服务还是远程服务,如果是本地服务,VirtualAPK会反射调用Service相应生命周期的方法;如果是远程服务,VirtualAPK先将目标插件apk加载进来,然后再反射调用目标Service的生命周期方法。

图10插件Service启动过程

  • Receiver 将插件中静态注册的receiver重新注册一遍;

  • ContentProvider 动态代理IContentProvider,拦截provider相关的请求,将其中转给Provider Runtime去处理,Provider Runtime会接管系统的所有操作。

四、VirtualApk框架主要问题调研

4.1 VirtualApk是否支持混淆
结论:VirtualApk主工程支持混淆,子工程也支持混淆

4.2、调研以下问题
4.2.1 插件下载后,需不需要重启app才能完成加载?
结论:插件下载后不需要App重启即可生效,但插件升级后需重启app.
1) VirtualApk

github项目描述原话:

VirtualApk can dynamically load and run an APK file(we call it LoadedPlugin) seamless as an installed application.
说明插件下载后不需重启app即可生效运行;

2) 反证法思路:VirtualApk是当下最流行的插件化框架,如果其在插件下载后需要app重启,那么该框架肯定不会被业界认可;

3) 实践证实插件下载后不需app重启即可生效,但插件更新后需app重启方可生效。

尝试PluginManager卸载再装载组件的思路,实验结果未能成功自动更新升级后的组件。

4.3插件中和主app如果包含同样的库,执行中会不会遇到问题?
结论:所查阅文献明确说明 插件不能包含有主工程的代码,但插件工程在编译时应该可以使用主工程代码协助编译,只是编译完成后就不能有主工程代码。

经实际编码验证,如果插件和主app包含同样的代码,以主app代码为准。

参考文献:

https://blog.csdn.net/u012439416/article/details/76595643

https://juejin.im/entry/59e8618cf265da43143fcf68

4.4不用反射的方法,能不能让宿主直接调用插件中的类和方法?
结论:Java类经ClassLoader加载到JVM后,有反射和接口调用两种方式
Class A = Class.forName("com.some.class.A");
//反射方式
Method method = A.getDeclaredMethod(...);
method.invoke(null, ...);

//接口方式
InterfaceA objA = (InterfaceA) A.newInstance(...);
objA.interfaceMethod();
InterfaceA定义: 
interface InterfaceA {
void interfaceMethod();
}

五、VirtualAPK验证

5.1 宿主工程直接调用插件工程的四大组件宿主工程调用插件工程的Activity/Service, 插件工程内部再调用自己或其他插件的四大组件表2 VirtualAPK实验结果

方式

Activity

Service

BroadcastReceiver

ContentProvider

宿主工程直接调用插件工程

×

宿主工程间接调用插件工程

×

5.2 反射并使用插件工程的 ✓在插件工程定义一工具类,然后在宿主工程Class.forName加载并使用该工具类,最后编译并打包运行验证效果,经实际验证该feature功能正常。5.3 混淆验证 ✓验证插件工程对宿主工程有单向依赖的情形。
                   表3 VirtualAPK实验结果

序号

宿主工程是否混淆
插件工程是否混淆

运行效果

1

混淆

混淆

2

混淆

未混淆

×

3

未混淆

混淆

4

未混淆

未混淆

6、总结

根据是否支持四大组件、是否需在宿主工程manifest预注册、插件工程是否可依赖宿主工程等指标,对表1各插件化框架进行筛选,最后可得出VirtualAPK为最优候选框架。但经过实际编码验证,四大组件除Service外都可被VirtualAPK支持。

7、参考文章

  • Android 360开源全面插件化框架RePlugin实战
      https://blog.csdn.net/qiyei2009/article/details/78236520工程github地址:https://github.com/Qihoo360/RePlugin
  • ACDD使用教程
      http://www.jksoftcn.com/acddshi-yong-jiao-cheng.html
  • Android插件化框架
      https://www.cnblogs.com/yoyohong/p/7599981.html
  • OpenAtlas之4四 资源分布结构解析
      http://www.lxway.com/28562.htm
  • Android OpenAtlas初识 
     https://www.aliyun.com/jiaocheng/90603.html
  • Android插件化开发之OpenAtlas初体验

https://www.aliyun.com/jiaocheng/47101.html?spm=5176.100033.2.10.LuYTOz

  • Android插件化开发之OpenAtlas中四大组件与Application功能的验证https://blog.csdn.net/sbsujjbcy/article/details/47952269

  • Atlas、VirtualAPK、RePlugin三者的体验感受

https://www.jianshu.com/p/ceded2da7847

  • Android插件化:从入门到放弃

http://www.infoq.com/cn/articles/android-plug-ins-from-entry-to-give-up

转载于:https://www.cnblogs.com/tgltt/p/9542193.html

Android插件化技术调研相关推荐

  1. Android插件化技术

    一.Android插件化技术 我们在平时的开发过程中,会经常遇到产品需求的变更或者出现bug,在传统的模式中,我们需要首先需要修改代码,然后重新打包Apk,再交给公司的运营去官网或者应用商店上线,用户 ...

  2. 《Android插件化技术——原理篇》

    | 导语 插件化技术最早从2012年诞生至今,已经走过了5个年头.从最初只支持Activity的动态加载发展到可以完全模拟app运行时的沙箱系统,各种开源项目层出不穷,在此挑选了几个代表性的框架,总结 ...

  3. class加载原理和Dex加载的原理-----android插件化技术

    2019独角兽企业重金招聘Python工程师标准>>> class加载原理和Dex加载的原理 转载于:https://my.oschina.net/quguangle/blog/15 ...

  4. Android插件化开发指南——插件化技术简介

    文章目录 1. 为什么需要插件化技术 2. 插件化技术的历史 3. 插件化实现思路 3.1 InfoQ:您在 GMTC 中的议题叫做<Android 插件化:从入门到放弃>,请问这个标题代 ...

  5. Android 插件化总结

    2019独角兽企业重金招聘Python工程师标准>>> 1.Android中插件开发篇总结和概述 2.Android组件化和插件化开发 3.携程Android App插件化和动态加载 ...

  6. VirtualAPK:滴滴 Android 插件化的实践之路

    一.前言 在 Android 插件化技术日新月异的今天,开发并落地一款插件化框架到底是简单还是困难,这个问题不同人会有不同的答案.但是我相信,完成一个插件化框架的 Demo 并不是多难的事儿,然而要开 ...

  7. Android插件化原理解析——概要

    2015年是Android插件化技术突飞猛进的一年,随着业务的发展各大厂商都碰到了Android Native平台的瓶颈: 从技术上讲,业务逻辑的复杂导致代码量急剧膨胀,各大厂商陆续出到65535方法 ...

  8. Android插件化开发之动态加载三个关键问题详解

    本文摘选自任玉刚著<Android开发艺术探索>,介绍了Android插件化技术的原理和三个关键问题,并给出了作者自己发起的开源插件化框架. 动态加载技术(也叫插件化技术)在技术驱动型的公 ...

  9. Android插件化:从入门到放弃

    喜欢 | 作者 包建强 发布于 2016年7月14日. 估计阅读时间: 1 分钟 | 道AI风控.Serverless架构.EB级存储引擎,尽在ArchSummit!讨论 分享到:微博微信Facebo ...

最新文章

  1. suse 12sp1 oracle 11g r2 时出现错误 调用/sysman/lib/ins_emagent.mk的目标nmo时出错
  2. oracle中的NVL,NVL2,NULLIF,COALESCE函数使用
  3. UA MATH524 复变函数9 柯西公式与幂级数展开
  4. linux g++ gcc编译c++哪个好,linux g++编译c++
  5. Kafka消息模拟器
  6. 模态对话框和全选反选
  7. 将datatable导出为excel的三种方式(转)
  8. php数组o m n mn,O(m + n)和O(mn)之间的区别?
  9. 6000字说透,如何做好产品「适老化」!
  10. 仅一年,近半加密货币的“ICO”项目已死
  11. 基于DTW和HMM算法的语音识别系统对比研究-毕业小结
  12. UVa1584 - Circular Sequence
  13. EL属性范围用法sessionScope等(转)
  14. 联想Y7000安装双系统(Windows10与Ubuntu16.04)
  15. VTuber拍摄幕后:操作员、动捕设备、软件支撑
  16. oracle 建同义词语句,Oracle 同义词的创建
  17. 电脑维修常用检修软件技术
  18. elastic APM针对java应用的高阶用法(java agent)
  19. 单条件求和和多条件求和以及条件求平均
  20. iOS - 微信分享无法显示好友列表

热门文章

  1. 使用report PRC_SHOW_PRICING_DOCUMENT查看SAP CRM订单的pricing数据
  2. 深入理解Java的整型类型:如何实现2+2=5?
  3. 易语言https服务器,E2EE应用服务器套件 - 文档 - [基础教程] 使用HTTPS(SSL) - E2EE易语言网站敏捷开发框架...
  4. astype函数_从Excel到Python:最常用的36个Pandas函数!最完整的Pandas教程!
  5. 力扣(简单+中等)50题整理总结
  6. html5求6的阶乘,.net 求数的阶乘
  7. 如何使用facenet详解_如何使用冰箱更节能 使用冰箱节能技巧介绍【详解】
  8. xampp mysql创建表_xampp怎样创建数据表和删除数据表 来学习吧
  9. swt 键盘事件ctrl+c_跑Python的键盘可以很强大
  10. 天津大学计算机图形学_考研大数据|2020天津大学计算机类分数统计