VirtualAPK 详解和使用,网易云的朋友给我这份 339 页的 Android 面经
[](
)1 介绍
Android
插件化技术是比较热门领域,[VirtualAPK](
) 是滴滴 2017 年 6 月 3 号开源,框架功能完备,支持 Android
四大组件,良好的兼容性,且入侵性较低,作为加载耦合插件方案是较好选择。兼容市面上几乎所有的 Android
手机,这一点已经在滴滴出行客户端中得到验证; 资源方面适配小米、Vivo
、Nubia
等,对未知机型采用自适应适配方案;极少的 Binder Hook
,目前仅仅hook
了两个 Binder
: AMS
和 IContentProvider
,hook
过程做了充分的兼容性适配;插件运行逻辑和宿主隔离,确保框架的任何问题都不会影响宿主的
[](
)2 VirtualAPK 和主流开源框架的对比
[](
)3 原理
[](
)3.1 基本原理
合并宿主和插件的 ClassLoader
需要注意的是,插件中的类不可以和宿主重复
合并插件和宿主的资源
重设插件资源的 packageId,将插件资源和宿主资源合并
去除插件包对宿主的引用
构建时通过 Gradle 插件去除插件对宿主的代码以及资源的引用
[](
)3.2 四大组件的实现原理
Activity
采用宿主 manifest 中占坑的方式来绕过系统校验,然后再加载真正的 activity;
Service
动态代理 AMS,拦截 service 相关的请求,将其中转给
Service Runtime
去处理,Service Runtime
会接管系统的所有操作;Receiver
将插件中静态注册的 receiver 重新注册一遍;
ContentProvider
动态代理 IContentProvider,拦截 provider 相关的请求,将其中转给
Provider Runtime
去处理,Provider Runtime
会接管系统的所有操作。VirtualAPK 的整体架构图,更详细的内容请大家阅读源码。
[](
)3.3 VirtualAPK 的整体架构图
[](
)3.4 原理分析源码
鸿洋大神写的源码分析(滴滴官网都推荐看鸿洋大神写的)
[滴滴插件化方案 VirtualApk 源码解析](
)
下面这位大神就不知道是谁了(滴滴官网推荐看的)
[VirtualAPK 资源加载机制分析](
)
[](
)4 使用
[](
)4.1 插件和宿主必须 compile 相同的 aar
比如宿主 compile 了如下 aar
compile 'com.didi.virtualapk:core:0.9.0'//滴滴 VirtualAPK 的依赖 compile 'com.alibaba:fastjson:1.2.39'compile'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
插件工程需要访问宿主 sdk 中的类和资源,那么可以在插件工程中同样 compile sdk 的 aar,如下:
compile 'com.didi.virtualapk:core:0.9.0'//滴滴 VirtualAPK 的依赖 compile 'com.alibaba:fastjson:1.2.39'compile'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
这样一来,插件工程就可以正常地引用 sdk 了。并且,插件构建的时候会自动将这个 aar 从 apk 中剔除
[](
)4.2 宿主工程
在工程根目录下
build.gradle
中添加
dependencies {classpath 'com.didi.virtualapk:gradle:0.9.0'}
在 App 的
build.gradle
中顶部添加
apply plugin: 'com.didi.virtualapk.host'
在 App 的
build.gradle
中compile
添加
dependencies {compile 'com.didi.virtualapk:core:0.9.0'}
编写 MyApp 继承 Application 重写 attachBaseContext 方法中初始化插件引擎(别忘了在 AndroidManifest.xml 配置 Application)
@Overrideprotected void attachBaseContext(Context context) {super.attachBaseContext(context);PluginManager.getInstance(context).init();}
推荐大家在 Application 启动的时候去加载插件,不然的话,请注意插件的加载时机。 考虑一种情况,如果在一个较晚的时机去加载插件并且去访问插件中的资源,请注意当前的 Context。比如在宿主 Activity(MainActivity)中去加载插件,接着在 MainActivity 去访问插件中的资源(比如 Fragment),需要做一下显示的 hook,否则部分 4.x 的手机会出现资源找不到的情况。
PluginManager pluginManager = PluginManager.getInstance(this);//此处是当查看插件 apk 是否存在,如果存在就去加载(比如修改线上的 bug,把插件 apk 下载到 sdcard 的根目录下取名为 Demo.apk)File apk = new File(Environment.getExternalStorageDirectory(), "Demo.apk");if (apk.exists()) {try {pluginManager.loadPlugin(apk);} catch (Exception e) {
评论