最近要求利用插件化框架来开发项目,于是乎研究了一下,发现市面上已有的插件化框架大多数已经停止更新,甚至代码结构还是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]之间,具体数值可以用科学计算器来转换一下,不然打包会失败。
至此,框架引入完成
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项目即可。
奉上代码,有不当之处请各位大佬多多指教。