当前位置: 首页 > 工具软件 > VirtualAPK > 使用案例 >

VirtualAPK 详解和使用,真牛

张高澹
2023-12-01

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的整体架构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0QiMH5DA-1630587542054)(https://user-gold-cdn.xitu.io/2017/10/19/303e5cfd242442fee27eb48da71fe5a5?imageView2/0/w/1280/h/960/ignore-error/1)]

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.gradlecompile 添加
dependencies {
 compile 'com.didi.virtualapk:core:0.9.0'
}
  • 编写MyApp继承Application重写attachBaseContext方法中初始化插件引擎(别忘了在AndroidManifest.xml配置Application)
 @Override
    protected 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) {
                e.printStackTrace();
            }
        }
  • AndroidManifest.xml添加读写SD卡的权限,如果插件apk是从网上获得的,还需要添加上网权限(我只是简单的测试,直接把插件apk放到sd卡中)
 <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

4.3 插件工程

  • 在工程根目录下build.gradle中添加
dependencies {
 classpath 'com.didi.virtualapk:gradle:0.9.0'
}
  • 在App的build.gradle中顶部添加依赖以及插件配置信息
 apply plugin: 'com.didi.virtualapk.plugin'//注意这个是plugin结尾,宿主是以host结尾的 

// 插件配置信息,放在文件最下面
virtualApk {
// 插件资源表中的packageId,需要确保不同插件有不同的packageId.
packageId = 0x6f

// 宿主工程application模块的路径,插件的构建需要依赖这个路径,我这个宿主工程和插件工程在同一级目录下,所以下面这样写
targetHost = '../VirtualAPKHostDemo/app' 

//默认为true,如果插件有引用宿主的类,那么这个选项可以使得插件和宿主保持混淆一致
applyHostMapping = true 

[]( )4.5 Gradle版本推荐
------------------------------------------------------------

目前VirtualAPK构建器还在持续完善之中,因此插件构建推荐使用Gradle 2.14.1版本,3.x版本可能有适配问题,我们正在努力去兼容各种Gradle版本。同时,待VirtualAPK构建器完善之后,其代码也将开源,敬请期待。
----------------------------

目前VirtualAPK构建器还在持续完善之中,因此插件构建推荐使用Gradle 2.14.1版本,3.x版本可能有适配问题,我们正在努力去兼容各种Gradle版本。同时,待VirtualAPK构建器完善之后,其代码也将开源,敬请期待。
 
 类似资料: