Android--›360全面插件化RePlugin框架交互通信使用概述
官网的wiki文档, 把RePlugin
的接入, 插件的使用, 组件的调用介绍的很清楚.
但是关于宿主
和插件
的交互,介绍的比较少.
本文主要介绍关于Binder
交互方式的使用.
点击直接跳转Binder
相关
文章目录
- 1.宿主接入指南
- 1.1 在项目根目录的 build.gradle
- 1.2 在 app/build.gradle 中
- 1.3 让工程的 Application 直接继承自 RePluginApplication。
- 2.插件接入指南
- 2.1 在项目根目录的 build.gradle
- 2.2 在 app/build.gradle 中
- 3.内置插件
- 3.1.使用插件中的组件
- 3.2.使用插件外的组件
- 3.3.插件获取主程序Context
- 3.4.主程序调用插件组件
- 4.Binder使用
- 4.1.1 插件中声明实现aidl类
- 4.1.2 宿主/插件中使用aidl类
- 4.2.1 宿主中声明实现aidl
- 4.2.2 插件中使用aidl
- 4.3.1 Global Binder使用
- 5.代码互通
- 5.1 宿主使用插件中的类
- 5.2 直接调用代码
- 5.3 通过反射调用 **推荐方式**
- 插件信息
- 别名
- 协议版本号
- 框架版本号
- 插件信息的获取
- 联系作者
官方开原地址RePlugin
1.宿主接入指南
https://github.com/Qihoo360/RePlugin/wiki/主程序接入指南
1.1 在项目根目录的 build.gradle
https://github.com/Qihoo360/RePlugin/wiki/主程序接入指南#第-1-步添加-replugin-host-gradle-依赖
(注意:不是 app/build.gradle) 中添加 replugin-host-gradle 依赖:
buildscript {dependencies {classpath 'com.qihoo360.replugin:replugin-host-gradle:2.2.4'...}
}
1.2 在 app/build.gradle 中
https://github.com/Qihoo360/RePlugin/wiki/主程序接入指南#第-2-步添加-replugin-host-library-依赖
应用 replugin-host-gradle 插件,并添加 replugin-host-lib 依赖:
android {// ATTENTION!!! Must CONFIG this to accord with Gradle's standard, and avoid some errordefaultConfig {applicationId "com.qihoo360.replugin.sample.host"...}...
}// ATTENTION!!! Must be PLACED AFTER "android{}" to read the applicationId
apply plugin: 'replugin-host-gradle'/*** 配置项均为可选配置,默认无需添加* 更多可选配置项参见replugin-host-gradle的RepluginConfig类* 可更改配置项参见 自动生成RePluginHostConfig.java*/
repluginHostConfig {/*** 是否使用 AppCompat 库* 不需要个性化配置时,无需添加*/useAppCompat = true/*** 背景不透明的坑的数量* 不需要个性化配置时,无需添加*/countNotTranslucentStandard = 6countNotTranslucentSingleTop = 2countNotTranslucentSingleTask = 3countNotTranslucentSingleInstance = 2
}dependencies {compile 'com.qihoo360.replugin:replugin-host-lib:2.2.4'...
}
1.3 让工程的 Application 直接继承自 RePluginApplication。
https://github.com/Qihoo360/RePlugin/wiki/主程序接入指南#第-3-步配置-application-类
如果您的工程已有Application类,则可以将基类切换到RePluginApplication即可。或者您也可以用“非继承式”接入。
public class MainApplication extends RePluginApplication {}
既然声明了Application,自然还需要在AndroidManifest中配置这个Application。
<applicationandroid:name=".MainApplication"... />
2.插件接入指南
https://github.com/Qihoo360/RePlugin/wiki/插件接入指南
2.1 在项目根目录的 build.gradle
https://github.com/Qihoo360/RePlugin/wiki/插件接入指南#第-1-步添加-replugin-plugin-gradle-依赖
(注意:不是 app/build.gradle) 中添加 replugin-plugin-gradle 依赖:
buildscript {dependencies {classpath 'com.qihoo360.replugin:replugin-plugin-gradle:2.2.4'...}
}
2.2 在 app/build.gradle 中
https://github.com/Qihoo360/RePlugin/wiki/插件接入指南#第-2-步添加-replugin-plugin-library-依赖
应用 replugin-plugin-gradle 插件,并添加 replugin-plugin-lib 依赖:
apply plugin: 'replugin-plugin-gradle'dependencies {compile 'com.qihoo360.replugin:replugin-plugin-lib:2.2.4'...
}
3.内置插件
https://github.com/Qihoo360/RePlugin/wiki/插件的管理#内置插件
添加内置插件
- 将APK改名为:
插件名.jar
- 放入主程序的
assets/plugins
目录 - 如果更改了
assets/plugins
目录下的插件, 需要卸载重装宿主才能生效
3.1.使用插件中的组件
https://github.com/Qihoo360/RePlugin/wiki/插件的组件#如何使用组件
例如您要打开一个Activity,则可以这么玩:
Intent intent = new Intent(v.getContext(), ThemeDialogActivity.class);
context.startActivity(intent);
打开服务呢?当然,如法炮制:
Intent intent = new Intent(v.getContext(), PluginDemoService1.class);
intent.setAction("action1");
context.startService(intent);
使用Content-Provider也是如此:
Uri uri = Uri.parse("content://com.qihoo360.replugin.sample.demo1.provider2/test");ContentValues cv = new ContentValues();
cv.put("address", "beijing");Uri urii = context.getContentResolver().insert(uri, cv);
当然了,还有大名鼎鼎的BroadcastReceiver:
Intent intent = new Intent();
intent.setAction("com.qihoo360.repluginapp.replugin.receiver.ACTION1");
intent.putExtra("name", "jerry");
context.sendBroadcast(intent);
和在APP中保持一致
.
3.2.使用插件外的组件
https://github.com/Qihoo360/RePlugin/wiki/插件的组件#插件外组件
// 方法1(最“单品”)
Intent intent = new Intent();
intent.setComponent(new ComponentName("demo2", "com.qihoo360.replugin.sample.demo2.databinding.DataBindingActivity"));
context.startActivity(intent);// 方法2(快速创建Intent)
Intent intent = RePlugin.createIntent("demo2", "com.qihoo360.replugin.sample.demo2.databinding.DataBindingActivity");
context.startActivity(intent);// 方法3(一行搞定)
RePlugin.startActivity(v.getContext(), new Intent(), "demo2", "com.qihoo360.replugin.sample.demo2.databinding.DataBindingActivity");// 方法4 (action)
Intent intent = new Intent("com.qihoo360.replugin.sample.demo2.action.theme_fullscreen_2");
RePlugin.startActivity(v.getContext(), intent, "demo2", null);
3.3.插件获取主程序Context
https://github.com/Qihoo360/RePlugin/wiki/插件的组件#插件获取主程序context
要获取主程序的Context,需要调用 RePlugin.getHostContext() 方法即可。例如:
Context hostContext = RePlugin.getHostContext();
...
当然,获取其它内容(如ClassLoader等)也如法炮制,可直接调用RePlugin类中的相应方法即可。
3.4.主程序调用插件组件
https://github.com/Qihoo360/RePlugin/wiki/插件的组件#主程序调用插件组件
打开插件的Activity
要打开一个插件的Activity,您需要调用 RePlugin.startActivity() 方法。例如:
RePlugin.startActivity(MainActivity.this, RePlugin.createIntent("demo1", "com.qihoo360.replugin.sample.demo1.MainActivity"));
获取插件的Context
要获取插件的Context,可以调用 RePlugin.fetchContext() 方法。例如:
Context examContext = RePlugin.fetchContext("exam");
...
当然,获取其它内容(如ClassLoader等)也如法炮制,可直接调用RePlugin类中的相应方法即可。
启动、绑定插件的Service
可以使用我们的 PluginServiceClient 类中的相应方法来操作。例如,若您想“绑定”一个服务,则可以:
PluginServiceClient.bindService(RePlugin.createIntent("exam", "AbcService"), mServiceConn);
其它方法都在 PluginServiceClient 里,和系统参数完全一致,这里不赘述。
请参见 JavaDoc 文档了解更多。
使用插件的Content-Provider
同样的,使用 PluginProviderClient 类中的方法即可操作Provider,具体做法如下:
PluginProviderClient.query(xxx);
4.Binder使用
4.1.1 插件中声明实现aidl类
plugin-demo2
工程
声明aidl com.qihoo360.replugin.sample.demo2.IDemo2.aidl
package com.qihoo360.replugin.sample.demo2;interface IDemo2 {void hello(String str);
}
实现 com.qihoo360.replugin.sample.demo2.Demo2Impl
public class Demo2Impl extends IDemo2.Stub {@Overridepublic void hello(String str) throws RemoteException {Toast.makeText(RePlugin.getPluginContext(), str, Toast.LENGTH_SHORT).show();}
}
注册Binder
RePlugin.registerPluginBinder("demo2test", new Demo2Impl());
4.1.2 宿主/插件中使用aidl类
需要在工程中,声明相同的aidl文件 com.qihoo360.replugin.sample.demo2.IDemo2.aidl
package com.qihoo360.replugin.sample.demo2;interface IDemo2 {void hello(String str);
}
然后,在需要使用的插件中调用:
IBinder b = RePlugin.fetchBinder("demo2", "demo2test");
if (b == null) {return;
}
IDemo2 demo2 = IDemo2.Stub.asInterface(b);
try {demo2.hello("helloooooooooooo");
} catch (RemoteException e) {e.printStackTrace();
}
4.2.1 宿主中声明实现aidl
宿主中声明aidl,并实现
//声明 IMyAidlInterface.aidl
package com.qihoo360.replugin.sample.host;// Declare any non-default types here with import statementsinterface IMyAidlInterface {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/String test(String str);
}
//实现
public class IMyAidlInterfaceImpl extends IMyAidlInterface.Stub {@Overridepublic String test(String str) throws RemoteException {Toast.makeText(RePluginInternal.getAppContext(), str, Toast.LENGTH_SHORT).show();return str;}
}
注册Binder
在宿主中注册
Binder
需要使用registerHostBinder
.
在插件中注册
Binder
需要使用registerPluginBinder
.
RePlugin.registerHostBinder(new IHostBinderFetcher() {@Overridepublic IBinder query(String module) {if (TextUtils.equals(module, "IMyAidlInterfaceImpl")) {return new IMyAidlInterfaceImpl();}return null;}
});
4.2.2 插件中使用aidl
插件中获取宿主的Binder, 并使用
IBinder binder = RePlugin.fetchBinder("main", "IMyAidlInterfaceImpl");
if (binder != null) {IMyAidlInterface aidlInterface = IMyAidlInterface.Stub.asInterface(binder);try {appendText("aidl返回:" + aidlInterface.test("by plugin"));} catch (RemoteException e) {e.printStackTrace();}
} else {appendText("binder is null");
}
需要注意的就是, fetchBinder
方法的第一个参数必须是main
,其他和插件中使用Binder
一致.
4.3.1 Global Binder使用
宿主和插件, 方法通用.
aidl
的声明和实现, 与前2种方法一致.
区别在于注册/获取 Binder
的方式
注册Binder
RePlugin.registerGlobalBinder("global", new GlobalInterfaceImpl());
获取Binder
IBinder global = RePlugin.getGlobalBinder("global");
if (global != null) {GlobalInterface globalInterface = GlobalInterface.Stub.asInterface(global);try {appendText("global aidl返回:" + globalInterface.testGlobal("by plugin"));} catch (RemoteException e) {e.printStackTrace();}
} else {appendText("global binder is null");
}
5.代码互通
5.1 宿主使用插件中的类
com.qihoo360.replugin.sample.host.PluginFragmentActivity
/*** 注意:** 如果一个插件是内置插件,那么这个插件的名字就是文件的前缀,比如:demo1.jar插件的名字就是demo1(host-gradle插件自动生成),可以执行诸如RePlugin.fetchClassLoader("demo1")的操作;* 如果一个插件是外置插件,通过RePlugin.install("/sdcard/demo1.apk")安装的,则必须动态获取这个插件的名字来使用:* PluginInfo pluginInfo = RePlugin.install("/sdcard/demo1.apk");* RePlugin.preload(pluginInfo);//耗时* String name = pluginInfo != null ? pluginInfo.getName() : null;* ClassLoader classLoader = RePlugin.fetchClassLoader(name);*/boolean isBuiltIn = true;String pluginName = isBuiltIn ? "demo1" : "com.qihoo360.replugin.sample.demo1";//注册相关Fragment的类//注册一个全局Hook用于拦截系统对XX类的寻找定向到Demo1中的XX类主要是用于在xml中可以直接使用插件中的类RePlugin.registerHookingClass("com.qihoo360.replugin.sample.demo1.fragment.DemoFragment",RePlugin.createComponentName(pluginName, "com.qihoo360.replugin.sample.demo1.fragment.DemoFragment"), null);setContentView(R.layout.activity_plugin_fragment);//代码使用插件FragmentClassLoader d1ClassLoader = RePlugin.fetchClassLoader(pluginName);//获取插件的ClassLoadertry {Fragment fragment = d1ClassLoader.loadClass("com.qihoo360.replugin.sample.demo1.fragment.DemoCodeFragment").asSubclass(Fragment.class).newInstance();//使用插件的Classloader获取指定Fragment实例getSupportFragmentManager().beginTransaction().add(R.id.container2, fragment).commit();//添加Fragment到UI} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}
需要添加依赖
provided files('libs/fragment.jar')//这个jar就是从Support-fragment中提取出来的并非特制包目的是为了骗过编译期
com.qihoo360.replugin.sample.demo1.MainActivity
5.2 直接调用代码
// 此为RePlugin的另一种做法,可直接调用宿主的Utils
// 虽然不是很推荐(版本控制问题,见FAQ),但毕竟需求较大,且我们是“相对安全的共享代码”方案,故可以使用
final String curTime = TimeUtils.getNowString();
if (!TextUtils.isEmpty(curTime)) {Toast.makeText(v.getContext(), "current time: " + TimeUtils.getNowString(), Toast.LENGTH_SHORT).show();// 打印其ClassLoaderLog.d("MainActivity", "Use Host Method: cl=" + TimeUtils.class.getClassLoader());
} else {Toast.makeText(v.getContext(), "Failed to obtain current time(from host)", Toast.LENGTH_SHORT).show();
}
需要添加依赖:
provided files('libs/common-utils-lib-1.0.0.jar')//这个jar就是从Host的utils中编译生成的,其目的是为了骗过编译期
5.3 通过反射调用 推荐方式
// 这是RePlugin的推荐玩法:反射调用Demo2,这样"天然的"做好了"版本控制"
// 避免出现我们当年2013年的各种问题
ClassLoader cl = RePlugin.fetchClassLoader("demo2");
if (cl == null) {Toast.makeText(v.getContext(), "Not install Demo2", Toast.LENGTH_SHORT).show();return;
}try {Class clz = cl.loadClass("com.qihoo360.replugin.sample.demo2.MainApp");Method m = clz.getDeclaredMethod("helloFromDemo1", Context.class, String.class);m.invoke(null, v.getContext(), "Demo1");
} catch (Exception e) {// 有可能Demo2根本没有这个类,也有可能没有相应方法(通常出现在"插件版本升级"的情况)Toast.makeText(v.getContext(), "", Toast.LENGTH_SHORT).show();e.printStackTrace();
}
插件信息
https://github.com/Qihoo360/RePlugin/wiki/插件的信息
别名
https://github.com/Qihoo360/RePlugin/wiki/插件的信息#插件别名
协议版本号
https://github.com/Qihoo360/RePlugin/wiki/插件的信息#插件协议版本号
框架版本号
https://github.com/Qihoo360/RePlugin/wiki/插件的信息#插件框架版本号
<meta-dataandroid:name="com.qihoo360.plugin.name"android:value="[你的插件别名]" />
<meta-dataandroid:name="com.qihoo360.plugin.version.low"android:value="[你的插件协议版本号]" />
<meta-dataandroid:name="com.qihoo360.plugin.version.high"android:value="[你的插件协议版本号]" />
<meta-dataandroid:name="com.qihoo360.framework.ver"android:value="[你的框架版本号]" />
插件信息的获取
插件信息的类是 PluginInfo,无论是宿主还是插件均可使用。而要获取插件信息还是非常简单的:
- 调用
RePlugin.getPlugin()
方法,可获取任意插件的信息,也可以借此判断插件是否安装(若为null则表示没有安装) - 调用
RePlugin.getPluginInfoList()
方法可获取所有已安装(包括内置插件)的信息 - 调用
RePlugin.install()
方法,其返回值是“安装成功后”的PluginInfo。若返回Null则表示“安装失败”
相关源码
群内有各(pian)种(ni)各(jin)样(qun)
的大佬,等你来撩.
联系作者
点此快速加群
请使用QQ扫码加群, 小伙伴们都在等着你哦!
关注我的公众号, 每天都能一起玩耍哦!
Android--›360全面插件化RePlugin框架交互通信使用概述相关推荐
- 58同城Android端-最小插件化框架实战和原理分析
目录 背景 插件化需要了解的知识 2.1 类加载过程和类加载器 2.2 ClassLoader 的 findClass.findLibrary.findResource 2.3 DexClassLoa ...
- 唯一插件化Replugin源码及原理深度剖析--插件的安装、加载原理
上一篇 唯一插件化Replugin源码及原理深度剖析–唯一Hook点原理 在Replugin的初始化过程中,我将他们分成了比较重要3个模块,整体框架的初始化.hook系统ClassLoader.插件的 ...
- 蘑菇街Android组件与插件化
插件化的基石 -- apk动态加载 随着我街业务的蓬勃发展,产品和运营随时上新功能新活动的需求越来越强烈,经常可以听到"有个功能我想周x上,行不行".行么?当然是不行啦,上新功能得 ...
- Winform开发框架之插件化应用框架实现
支持插件化应用的开发框架能给程序带来无穷的生命力,也是目前很多系统.程序追求的重要方向之一,插件化的模块,在遵循一定的接口标准的基础上,可以实现快速集成,也就是所谓的热插拔操作,可以无限对已经开发好系 ...
- Android应用程序插件化研究之DexClassLoader
文章首发:[Android应用程序插件化研究之DexClassLoader|大利猫](http://www.liuguangli.win/archives/366) 最近在研究Android应用的插件 ...
- Android Hook式插件化教程(一)Hook从入门到精通
Android Hook式插件化教程(一)Hook从入门到精通 1.hook的定义 hook,顾名思义就是钩子.而在我们开发中通俗来讲就是劫持,就是某段SDK源码逻辑执行的过程中,通过代码手段劫持拦截 ...
- 360手机卫士插件化RePlugin今日开源,官方全面解读
作者:张炅轩,360手机卫士·客户端技术专家 写在前面 "RePlugin将在6月底开源,这将是我们献给安卓世界最好的礼物."当我们宣布这一消息时,心中的激动,无以言表.是的,三年 ...
- android插件化-apkplug框架基本结构-01
2019独角兽企业重金招聘Python工程师标准>>> 由于框架开发更新频繁的原因一直都没有时间写出框架的基本架构让大家云里雾里的,现在框架已基本稳定和完善,我就抽出时间写写关于ap ...
- 2020 Android 大厂面试-插件化、模块化、组件化,移动开发工程师的岗位职责
替换了主工程context中LoadedApk的mResource对象 将新的Resource添加到主工程ActivityThread的mResourceManager中,并且根据Android版本做 ...
最新文章
- EMC设计中电缆屏蔽使用方法
- c/c++基础 输入函数/流
- VirtWire 向客服发ticket
- 关于纯cs3动画的五个原创实例分享
- No MyBatis mapper was found in ‘[xx.mapper]‘ package. Please check your configuration
- Object-c学习之路三(@class与#import的区别)
- IOS-awakeFromNib和viewDidLoad
- 边缘节点服务ENS > 产品简介 > 什么是边缘节点服务ENS
- C#学习之ObjectOriented、Record
- 数据链路层点到点通讯和PPP协议
- 正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)
- 那些不得不提的坑(持续添加中)
- c语言 常量整数,C语言的整型常量
- FortiClient VPN连接至98%时报错:Unable to establish the VPN connection.(E=98,T-981011001,M99,R10)
- 股权模板:72套股权分配方案
- mac键盘上符号的快捷键_Mac键盘符号实际上是什么意思?
- 一文看懂 Theorem Theory Proposition Lemma Corollary Claim 的区别
- 云服务器-ubuntu系统
- FLink聚合性能优化--MiniBatch分析
- mysqld_multi关闭不了mysql