滴滴VirtualAPK插件化框架接入流程及宿主与插件间通信的实现

        最近要求利用插件化框架来开发项目,于是乎研究了一下,发现市面上已有的插件化框架大多数已经停止更新,甚至代码结构还是eclipse样式的...只有滴滴出品的VirtualAPK还比较新,经过一段时间的摸索,把接入过程及遇到的问题分享一下,如有不妥之处,欢迎各位大佬拍砖。

 项目结构

app为宿主module,plugindemo和plugindemo2为两个插件module,communication为通信module

1  框架引入

在项目根目录的build.gradle里添加 

      classpath 'com.didi.virtualapk:gradle:0.9.8.4'

dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'
        classpath 'com.didi.virtualapk:gradle:0.9.8.4'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

在宿主(app)的build.gradle的顶端添加

  apply plugin: 'com.didi.virtualapk.host'
apply plugin: 'com.android.application'
apply plugin: 'com.didi.virtualapk.host'

在dependencies中添加依赖

 implementation 'com.didi.virtualapk:core:0.9.6'

在插件module的build.gradle的dependencies中添加

implementation 'com.didi.virtualapk:core:0.9.6'

在插件module的build.gradle的最底部添加

apply plugin: 'com.didi.virtualapk.plugin'
virtualApk {
    // 插件资源表中的packageId,需要确保不同插件有不同的packageId.
    packageId = 0x6f             // The package id of Resources.
    // 宿主工程application模块的路径,插件的构建需要依赖这个路径
    targetHost = 'F:/AsTest/VirtualAPKTest/app' // The path of application module in host project.
    //默认为true,如果插件有引用宿主的类,那么这个选项可以使得插件和宿主保持混淆一致
    applyHostMapping = true      // [Optional] Default value is true.
}

每个插件module都要添加,参数的注释都标出来了,注意第一个参数,在确保每个插件的packageId不同的同时,保证packageId在[0x02, 0x7E]之间,具体数值可以用科学计算器来转换一下,不然打包会失败。

扫描二维码关注公众号,回复: 4483971 查看本文章

至此,框架引入完成

2  添加跳转动作

如果想跳转的话,首先要加载插件,加载插件的代码如下

PluginManager pluginManager = PluginManager.getInstance(this);
       
File apk = new File(Environment.getExternalStorageDirectory(), "plugin-release1.apk");
// 此处需要先手动移动.apk到手机的根目录,并命名为plugin-release1.apk
if (apk.exists()) {
   try {
       pluginManager.loadPlugin(apk);
       Toast.makeText(this, "插件加载成功", Toast.LENGTH_SHORT).show();
   } catch (Exception e) {
       e.printStackTrace();
       Toast.makeText(this, "插件加载异常!", Toast.LENGTH_SHORT).show();
   }
} 

接下来是加载插件,首先要先打包出插件的apk文件

官方方法是通过命令./gradlew clean assemblePlugin来生成,不过运行这个命令不是那么的方便,也可以直接通过gradle来生成

如果module正确的话,插件module的apk会生成在plugindemo/build/outputs/apk/release路径下。如果报这样的错误

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':plugindemo'.
> Failed to notify project evaluation listener.
   > Can't find F:\AsTest\VirtualAPKTest\app\build\VAHost\versions.txt, please check up your host application
       need apply com.didi.virtualapk.host in build.gradle of host application 

   > Cannot invoke method onProjectAfterEvaluate() on null object

选中app,点击Build/Make Module 'app'即可

如此,即可加载插件,跳转时即为普通的不同包间的activity的跳转

tv_jump.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClassName("com.aroutertest.virtualapktest", "com.aroutertest.plugindemo.PluginActivity");
                startActivity(intent);
            }
        });

跳转时注意加载的apk名和手机中的apk名字一致,以及读写存储的权限设置。

3 宿主与插件之间的传值

由于宿主与插件之间并无直接的引用关系,所以常规的一些传值方法均不生效,参考官方的传值方法,通过引用相同的aar来实现,即aar作为一个三方中转,来进行相关值的传导。

3.1 生成aar

 新建一个module,将modle下的gradle文件最上边一行改为:apply plugin: ‘com.android.library’,并把applicationId删掉,意味着这个modle是作为library来创建使用的。这里有个地方应注意:library的sdkVersion应和项目保持一致,同时,要把项目AndroidManifest.xml里的启动页面的<intent-filter>删掉,把android:icon="@mipmap/ic_launcher"也删掉。

新建一个类,类中变量即为要传导的值,具体根据项目需要自行编辑

public class UserInfo {
    private String userAge;

    public String getUserAge() {
        return userAge;
    }

    public void setUserAge(String userAge) {
        this.userAge = userAge;
    }
}

新建Manager类,来管理需要传导的值的实体

public class Manager {

    private static UserInfo info;

    public static void initUserInfo(UserInfo info) {
        BeanManager.info = info;
    }

    public static UserInfo getUserInfo() {
        return info;
    }
}

然后,点击Build/Rebuild Project,就可以生成aar文件了,在communication/build/outputs/aar路径下

3.2 在所有module中添加依赖

把生成的aar文件改名为library.aar,置于各个module的libs文件夹下,在build.gradle中添加

repositories {
    flatDir {
        dirs 'libs'
    }
}
dependencies {
    implementation(name: 'library', ext: 'aar')
}

3.3 进行传值

很简单,执行aar中的相关方法即可

在宿主中:

UserInfo info = new UserInfo();
        info.setUserAge("18");
        BeanManager.initUserInfo(info);

在插件中:

String age= BeanManager.getUserInfo().getUserAge();

至此,接入及传值功能完成。

如果需要更改传值的类型,则需要修改communication重新生成aar,更新aar的方法为找到项目根目录下的.idea/libraries路径下的Gradle__xxx__aar.xml文件(xxx为生成的aar文件的名字)删掉,rebuild项目即可。

奉上代码,有不当之处请各位大佬多多指教。

https://download.csdn.net/download/a494153985/10846902

猜你喜欢

转载自blog.csdn.net/a494153985/article/details/84974819