使用场景1:插件的xml布局中有以宿主的全类名作为节点的时候
在application配置RePluginConfig时,有一行代码是:
// 允许“插件使用宿主类”。默认为“关闭”
c.setUseHostClassIfNotFound(true);
这行代码设置为true时,插件项目中找不到该类,会在宿主项目中查找。
使用场景2:插件代码中用到宿主项目的类及类中的字段、内部类等的时候
宿主项目类
/**
* Created by qby on 2018/2/23 0023.
* 演示“插件”使用“宿主”类
*/
class SpUtil {
companion object {
fun builder(): SpBuilder {
return SpBuilder()
}
}
class SpBuilder {
var sp: SharedPreferences? = null
var str: String? = null
fun getSp(context: Context): SpBuilder {
if (sp == null) {
synchronized(SpUtil::class.java) {
if (sp == null) {
sp = context.applicationContext.getSharedPreferences("testReplugin", Context.MODE_PRIVATE)
}
}
}
return this
}
fun putString(key: String, value: String): SpBuilder {
sp!!.edit().putString(key, value).apply()
return this
}
fun getString(key: String, defValue: String): SpBuilder {
str = sp!!.getString(key, defValue)
return this
}
}
}
在跳转到插件页面之前存储:
SpUtil.builder().getSp(this).putString("first","测试")
在跳转到插件页面之后取值,插件代码(使用反射)
//获取宿主类加载器
val hostClassLoader = RePlugin.getHostClassLoader()
//获取SpUtil类
val clazz = hostClassLoader.loadClass("com.test.qby.myapplication.utils.SpUtil")
//取得内部类,只有一个SpBuilder
val declaredClass = clazz.declaredClasses[0]
//初始化SpBuilder 对象
val newInstance = declaredClass.newInstance()
//得到getSp方法
val method0 = declaredClass.getDeclaredMethod(
"getSp",
Context::class.java)
//调用getSp方法,将值赋给sp
method0.invoke(newInstance, RePlugin.getHostContext())
//得到getString方法
val method1 = declaredClass.getDeclaredMethod(
"getString",
String::class.java,
String::class.java)
//调用getString方法,将值赋给str
method1.invoke(newInstance, "first", "默认")
//得到getStr方法
val method2 = declaredClass.getDeclaredMethod("getStr")
//调用getStr方法,获取str值
val get = method2.invoke(newInstance)
//弹出提示
Toast.makeText(this, get.toString(), Toast.LENGTH_SHORT).show()
使用场景3:插件调用宿主类中的方法
其实这个应该算是通信方式,通过场景2中的反射可以实现,还可以通过aidl进程中通信方式在宿主项目中暴露一些方法,供插件调用。
以在宿主中存储,在插件中通过aidl取值为例。
宿主项目在main下新建包,在包下新建aidl文件,结构如下图:
如图所示,新建ISpImpl类继承ISp.Stub,代码如下:
/**
* Created by qby on 2018/2/24 0024.
* AIDL 实现类
*/
class ISpImpl : ISp.Stub() {
@Throws(RemoteException::class)
override fun getString(key: String, defValue: String): String? {
return SpUtil.builder().getSp(SampleApplication.getContext()).getString(key, defValue).str
}
}
暴露出getString方法,在SampleApplication中注册全局的IBinder,在其他地方注册也行,但要在你调用aidl前注册:
//注册全局IBinder,host为自定义注册的名字
RePlugin.registerGlobalBinder("host", ISpImpl())
代码中调用:
//根据名字获取注册的IBinder
val globalBinder = RePlugin.getGlobalBinder("host")
//获取ISp实现类
val asInterface = ISp.Stub.asInterface(globalBinder)
try {
//调用方法,获取返回值
val string = asInterface.getString("first", "尝试")
//弹出提示
Toast.makeText(this, string.toString(), Toast.LENGTH_SHORT).show()
} catch (e: RemoteException) {
//捕获异常
e.printStackTrace()
}
用到反射的地方写起来代码比较多,真正用的时候还是要抽取放到工具类里,优化一下代码。
以上仅个人学习记录,如有疏漏或谬误,欢迎留言交流!