Android插件化1-插桩式-Activity插件化:https://blog.csdn.net/hongxue8888/article/details/98887680
Android插件化2-插桩式-Service插件化:https://blog.csdn.net/hongxue8888/article/details/99165077
Github :AndroidPlugin/HxPlugin3Broadcast/
文章目录
1 概述
BroadcastReceiver 中文翻译为“广播”,以下简称为 Receiver 。 Receiver 是 Android 四大组件中最简单的一个 。 它就是一个类 实现了观察者模式的类 。
Receiver分为动态广播和静态广播两种,相应的解决方案也有两种 。简单讨论一下它们的区别:
-
静态广播需要在 AndroidManifest 中注册 。 因为安装和 Android 系统重启时,PMS都会解析 App 中的 AndroidManifest 文件,所以静态广播的注册信息存在于 PMS 中 。
-
动态广播是通过写代码的方式进行注册,Context 的 registerReceiver 方法,最终调用 AMN.getDefault() .registerReceiver 方法,所以动态广播的注册信息存在于 AMS 中 。
静态广播和动态广播的区别仅在于上述注册方式的不同 。 之后,就都一样了,包括发送广播和接收广播 。
-
发送广播,也就是 Context 的 sendBroadcast 方法,最终会调用 AMN .getDefault().broadcastlntent ,把要发送的广播告诉 AMS 。
-
AMS 在收到上述信息后,搜索 AMS 和 PMS 中保存的广播,看哪些广播符合条件,然后通知 App进程启动这些广播,也就是调用这些广播的 onReceive 方法 。
Receiver 的生命周期非常简单,仅一个 onReceive 方法,相当于一个Callback回调函数 。
无论是发送广播,还是接收广播,都携带一个筛选条件:intent-filter。 发送广播时,要设置 intent-filter ,这样 AMS 才知道要通知哪些广播符合 intent-filter。 我们看下面的代码 。
2 代码实现
动态广播不需要和 AMS 打交道,所以,它就是一个类 。我们只需要确保宿主 App 能加载插件中的这个动态广播类 。
2.1 pluginstand
2.1.1 PayInterfaceBroadcast
定义接口,如下:
public interface PayInterfaceBroadcast {
void attach(Context context);
void onReceive(Context context, Intent intent);
}
2.2 taopiaopiao
2.2.1 MyReceiver
public class MyReceiver extends BroadcastReceiver implements PayInterfaceBroadcast {
@Override
public void attach(Context context) {
Toast.makeText(context, "-----绑定上下文成功-----", Toast.LENGTH_SHORT).show();
}
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "-----插件收到广播-----", Toast.LENGTH_SHORT).show();
}
}
2.2.2 BaseActivity
//重写广播注册
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return that.registerReceiver(receiver, filter);
}
//重写广播发送
@Override
public void sendBroadcast(Intent intent) {
that.sendBroadcast(intent);
}
2.2.3 TaoMainActivity
findViewById(R.id.registerBroad).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(that,"插件",Toast.LENGTH_SHORT).show();
//d动态注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.hongx.taopiaopiao.TaoMainActivity");
registerReceiver(new MyReceiver(), intentFilter);
}
});
findViewById(R.id.sendBroad).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.hongx.taopiaopiao.TaoMainActivity");
sendBroadcast(intent);
}
});
2.3 app
2.3.1 ProxyBroadCast
public class ProxyBroadCast extends BroadcastReceiver {
//需要加载插件的全类名
private String className;
private PayInterfaceBroadcast payInterfaceBroadcast;
public ProxyBroadCast(String className, Context context) {
this.className = className;
try {
Class<?> aClass = PluginManager.getInstance().getDexClassLoader().loadClass(className);
Constructor constructor = aClass.getConstructor(new Class[]{});
Object in = constructor.newInstance(new Object[]{});
payInterfaceBroadcast = (PayInterfaceBroadcast) in;
payInterfaceBroadcast.attach(context);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onReceive(Context context, Intent intent) {
payInterfaceBroadcast.onReceive(context, intent);
}
}
2.3.2 ProxyActivity
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
IntentFilter intentFilter = new IntentFilter();
for (int i = 0; i < filter.countActions(); i++) {
intentFilter.addAction(filter.getAction(i));
}
return super.registerReceiver(new ProxyBroadCast(receiver.getClass().getName(),
this), intentFilter);
}
3 流程总结
3.1 加载插件app
点击宿主app的加载按钮,加载插件,模拟插件app的下载和加载过程,获取到插件app的Resources、DexClassLoader和PackageInfo三个对象。
3.2 跳转到插件app
点击宿主app的跳转按钮,通过Activity的插件化,跳转到插件app,Activity插件化这里不再累述,参考Android插件化1-插桩式-Activity插件化
3.3 注册广播
点击插件app的注册广播按钮,通过代码我们再看下广播注册过程:
TaoMainActivity:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.hongx.taopiaopiao.TaoMainActivity");
registerReceiver(new MyReceiver(), intentFilter);
BaseActivity:
//重写广播注册
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return that.registerReceiver(receiver, filter);
}
ProxyActivity:
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
IntentFilter intentFilter = new IntentFilter();
for (int i = 0; i < filter.countActions(); i++) {
intentFilter.addAction(filter.getAction(i));
}
return super.registerReceiver(new ProxyBroadCast(receiver.getClass().getName(),
//receiver:com.hongx.taopiaopiao.MyReceiver
this), intentFilter);
}
TaoMainActivity的registerReceiver覆写的是BaseActivity的registerReceiver方法,而BaseActivity的registerReceiver方法中会调用that(ProxyActivity)的registerReceiver方法。
上面的代码的registerReceiver方法中实例化了ProxyBroadCast对象,ProxyBroadCast代码如下:
ProxyBroadCast:
public class ProxyBroadCast extends BroadcastReceiver {
//需要加载插件的全类名
private String className;
private PayInterfaceBroadcast payInterfaceBroadcast;
public ProxyBroadCast(String className, Context context) {
this.className = className;//com.hongx.taopiaopiao.MyReceiver
try {
Class<?> aClass = PluginManager.getInstance().getDexClassLoader().loadClass(className);
Constructor constructor = aClass.getConstructor(new Class[]{});
Object in = constructor.newInstance(new Object[]{});
payInterfaceBroadcast = (PayInterfaceBroadcast) in;//payInterfaceBroadcast: com.hongx.taopiaopiao.MyReceiver
payInterfaceBroadcast.attach(context);//context-ProxyActivity
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onReceive(Context context, Intent intent) {
payInterfaceBroadcast.onReceive(context, intent);
}
}
在ProxyBroadCast中传入的className也就是com.hongx.taopiaopiao.MyReceiver的类名了。然后通过反射将得到MyReceiver对象并将其转化为PayInterfaceBroadcast对象。调用attach方法,将ProxyActivity作为context传入到MyReceiver中。
MyReceiver:
public class MyReceiver extends BroadcastReceiver implements PayInterfaceBroadcast {
@Override
public void attach(Context context) {
Toast.makeText(context, "-----绑定上下文成功-----", Toast.LENGTH_SHORT).show();
}
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "-----插件收到广播-----", Toast.LENGTH_SHORT).show();
}
}
在ProxyBroadCast中执行payInterfaceBroadcast.attach(context),也就执行了MyReceiver的attach方法,此时将ProxyActivity作为context传入到MyReceiver中
3.4 发送广播
在插件app中点击发送广播按钮,代码如下:
TaoMainActivity:
findViewById(R.id.sendBroad).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.hongx.taopiaopiao.TaoMainActivity");
sendBroadcast(intent);
}
});
sendBroadcast调用了BaseActivity的sendBroadcast方法
BaseActivity:
//重写广播发送
@Override
public void sendBroadcast(Intent intent) {
that.sendBroadcast(intent);
}
也就是调用了ProxyActivity的sendBroadcast方法。
在ProxyActivity已经注册了广播接收者ProxyBroadCast,此时会调用ProxyBroadCast的onReceive方法,如下:
ProxyBroadCast:
@Override
public void onReceive(Context context, Intent intent) {
payInterfaceBroadcast.onReceive(context, intent);
}
payInterfaceBroadcast是一个MyReceiver对象,最终调用插件MyReceiver的onReceive方法。
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "-----插件收到广播-----", Toast.LENGTH_SHORT).show();context:ProxyActivity
}