宿主模拟pms android,BroadcastReceiver插件化解决方案

--摘自《android插件化开发指南》

1.静态广播和动态广播仅区别于注册方式的不同。静态广播的注册信息保存在PMS中,动态广播的注册信息保存在AMS中

2.发送广播,也就是Context的sendBroadcast方法,最终会调用AMN.getDefault().broadcastIntent,把要发送的广播告诉AMS;

AMS在收到上述信息后,搜索AMS和PMS中保存的广播,看哪些广播符合条件,然后通知App进程启动这些广播,也就是调用这些广播的onReceive方法

3.无论发送广播还是接受广播,都携带一个筛选条件:intent-filter。

MyReceiver myReceiver = newMyReceiver();

IntentFilter intentFilter= newIntentFilter();

intentFilter.addAction("baobao2");

registerReceiver(myReceiver,intentFilter);

***动态广播的插件化解决方案***

使用前面介绍的dex合并技术,插件中的动态广播就可以被宿主App正常调用了

***静态广播的插件化解决方案***

1)PMS只能读取宿主App的AndroidManifest文件,读取其中的静态广播并注册。我们可以通过反射,手动控制PMS读取插件的AndroidManifest中声明的静态广播列表

2)遍历这个静态广播列表。使用插件的classLoader加载列表中的每个广播类,实例化成一个对象,然后作为动态广播注册到AMS中

public final classReceiverHelper {private static final String TAG = "ReceiverHelper";/*** 解析插件Apk文件中的 , 并存储起来

*

*@paramapkFile

*@throwsException*/

public static voidpreLoadReceiver(Context context, File apkFile) {//首先调用parsePackage获取到apk对象对应的Package对象

Object packageParser = RefInvoke.createObject("android.content.pm.PackageParser");

Class[] p1= {File.class, int.class};

Object[] v1={apkFile, PackageManager.GET_RECEIVERS};

Object packageObj= RefInvoke.invokeInstanceMethod(packageParser, "parsePackage", p1, v1);//读取Package对象里面的receivers字段,注意这是一个 List (没错,底层把当作处理)//接下来要做的就是根据这个List 获取到Receiver对应的 ActivityInfo (依然是把receiver信息用activity处理了)

List receivers = (List) RefInvoke.getFieldObject(packageObj, "receivers");for(Object receiver : receivers) {

registerDynamicReceiver(context, receiver);

}

}//解析出 receiver以及对应的 intentFilter//手动注册Receiver

public static voidregisterDynamicReceiver(Context context, Object receiver) {//取出receiver的intents字段

List extends IntentFilter> filters = (List extends IntentFilter>) RefInvoke.getFieldObject("android.content.pm.PackageParser$Component", receiver, "intents");try{//把解析出来的每一个静态Receiver都注册为动态的

for(IntentFilter intentFilter : filters) {

ActivityInfo receiverInfo= (ActivityInfo) RefInvoke.getFieldObject(receiver, "info");

BroadcastReceiver broadcastReceiver=(BroadcastReceiver) RefInvoke.createObject(receiverInfo.name);

context.registerReceiver(broadcastReceiver, intentFilter);

}

}catch(Exception e) {

e.printStackTrace();

}

}

}

***不启动App和插件中的静态广播通信***

在宿主的androidmanifest中注册占位StubReceiver

插件的androidmanifest中注册

具体流程是宿主清单文件中查找jianqiang1,然后到插件的清单文件中查找jianqiang1,最后找到jianqiang1对应的baobao,这才是真正要注册的广播

实现逻辑如下

public final classReceiverHelper {private static final String TAG = "ReceiverHelper";/*** 解析插件Apk文件中的 , 并存储起来

*

*@paramapkFile

*@throwsException*/

public static voidpreLoadReceiver(Context context, File apkFile) {//首先调用parsePackage获取到apk对象对应的Package对象

Object packageParser = RefInvoke.createObject("android.content.pm.PackageParser");

Class[] p1= {File.class, int.class};

Object[] v1={apkFile, PackageManager.GET_RECEIVERS};

Object packageObj= RefInvoke.invokeInstanceMethod(packageParser, "parsePackage", p1, v1);

String packageName= (String)RefInvoke.getFieldObject(packageObj, "packageName");//读取Package对象里面的receivers字段,注意这是一个 List (没错,底层把当作处理)//接下来要做的就是根据这个List 获取到Receiver对应的 ActivityInfo (依然是把receiver信息用activity处理了)

List receivers = (List) RefInvoke.getFieldObject(packageObj, "receivers");try{for(Object receiver : receivers) {

Bundle metadata=(Bundle)RefInvoke.getFieldObject("android.content.pm.PackageParser$Component", receiver, "metaData");

String oldAction= metadata.getString("oldAction");//解析出 receiver以及对应的 intentFilter

List extends IntentFilter> filters = (List extends IntentFilter>) RefInvoke.getFieldObject("android.content.pm.PackageParser$Component", receiver, "intents");//把解析出来的每一个静态Receiver都注册为动态的

for(IntentFilter intentFilter : filters) {

ActivityInfo receiverInfo= (ActivityInfo) RefInvoke.getFieldObject(receiver, "info");

BroadcastReceiver broadcastReceiver=(BroadcastReceiver) RefInvoke.createObject(receiverInfo.name);

context.registerReceiver(broadcastReceiver, intentFilter);

String newAction= intentFilter.getAction(0);

ReceiverManager.pluginReceiverMappings.put(oldAction, newAction);

}

}

}catch(Exception e) {

e.printStackTrace();

}

}

}

public class StubReceiver extendsBroadcastReceiver {publicStubReceiver() {

}

@Overridepublic voidonReceive(Context context, Intent intent) {

String newAction=intent.getAction();if(ReceiverManager.pluginReceiverMappings.containsKey(newAction)) {

String oldAction=ReceiverManager.pluginReceiverMappings.get(newAction);

context.sendBroadcast(newIntent(oldAction));

}

}

}

缺点是要为StubReceiver配置几百个Action,无法避免

欢迎关注我的微信公众号:安卓圈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值