BroadcastReceiver基础知识
同样地,在讲解BroadcastReceiver插件化之前,我们先来回顾一下BroadcastReceiver的基础知识。
发送一个广播比较简单。
val intent=Intent("com.example.example")//实际使用过程中将action名传入Intent构造方法
sendBroadcast(intent)
广播按照不同标准可以分为几类。
-
根据注册方式进行划分
-
静态注册。
该方法是指在AndroidManifest文件进行注册。
<receiver android:name=".ExampleBroadCastReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BATTERY_LOW"> </action> </intent-filter> </receiver>- name属性。对应该BroadCastReceiver的名字。
- enabled属性。代表该BroadCastReceiver是否启动。
- exported属性。代表该BroadCastReceiver是否接收其它应用的广播。
- intent-filter属性。代表该BroadCastReceiver想要接受的广播。
-
动态注册。
动态注册的步骤有两步。
-
新建类继承于BroadCastReceiver并复写onReceive()方法。
-
实例化BroadCastReceiver并进行注册。
val exampleBroadCastReceiver=ExampleBroadCastReceiver() val intentFilter=IntentFilter() intentFilter.addAction("android.intent.action.BATTERY_LOW") registerReceiver(exampleBroadCastReceiver,intentFilter)
-
二者使用方式看起来其实区别不大,那么在实际开发过程中我们应该如何选择呢?
静态注册更常见的应用场景是应用未启动时接收系统广播,比如说手机开机完成的系统广播,手机刚开完机时,应用肯定还没有启动,这时候应用就可以通过静态广播来接收手机已经开机的系统广播,并执行相应的操作。
动态注册相比于静态注册的优势就在于一个动字,它可以动态改变它感兴趣,也就是它响接收的广播。
-
-
根据指不指定接收对象来进行划分。
- 显式广播。该类广播需要指定接收对象,发送显式广播比较简单,只需要在发送广播时调用IntentFilter::setPackageName()方法,然后传入接收应用的包名即可。
- 隐式广播。该类广播不需要指定接收对象,属于是广播界的老海王了,发给所有应用,需要注意的是,自安卓8.0以来,为了防止极个别恶意软件自启动,除了极少数个别系统广播之外,系统并不允许静态BroadcastReceiver接收隐式广播,
-
根据是否有序来进行划分
-
标准广播。这类广播又称为无序广播,标准广播发出后,所有感兴趣的BroadcastReceiver几乎会在同一时间收到该广播。
-
有序广播。这类广播发出后,所有感兴趣BroadcastReceiver会按照优先级先后收到该广播,需要注意的是,收到有序广播的BroadcastReceiver可以选择继续往下传,也可以选择中断该广播,也就是说优先级比它低的BroadcastReceiver都不会收到广播,有序广播发送比较简单。
sendBroadcast(intent)//标准广播 sendOrderedBroadcast(intent)//有序广播同样地,优先级可以静态设置,也可以动态设置。
/*静态设置*/ <receiver android:name=".ExampleBroadCastReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <action android:name="android.intent.action.BATTERY_LOW"> </action> </intent-filter> </receiver>//动态设置 val intentFilter=IntentFilter() intentFilter.addAction("android.intent.action.BATTERY_LOW") intentFilter.priority=100中断有序广播只需要在onReceive()方法中添加一行代码。
abortBroadcast();
-
BroadcastReceiver插件化原理
BroadcastReceiver插件化原理比较简单,一言以蔽之,就是将静态注册的BroadcastReceiver转化为动态注册。
同样地,我们会分析VirtualApk第三方库中的BroadcastReceiver插件化第三方实现方案,VirtualApk的初始化和常用类详情可见我上一篇文章ContentProvider插件化。
在该库中有一个类LoadedPlugin,其构造方法就会将静态注册的BroadcastReceiver转化为动态注册。
public LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws Exception {
this.mPackage = PackageParserCompat.parsePackage(context, apk, PackageParser.PARSE_MUST_BE_APK);
...
// Register broadcast receivers dynamically
//1
Map<ComponentName, ActivityInfo> receivers = new HashMap<ComponentName, ActivityInfo>();
for (PackageParser.Activity receiver : this.mPackage.receivers) {
receivers.put(receiver.getComponentName(), receiver.info);
BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
this.mHostContext.registerReceiver(br, aii);
}
}
this.mReceiverInfos = Collections.unmodifiableMap(receivers);
this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]);
...
}
代码核心思想是利用PackageParse::parsePackage()解析Apk中的AndroidManifest.xml文件,获取各个BroadcastReceiver的信息,并进行动态注册。
需要注意的是,1处代码之所以键值对的value为ActivityInfo,是因为PackageParse在解析AndroidManifest.xml文件时会把标签当作标签进行解析。
本文首先介绍了BroadcastReceiver的基础知识,包括静态和动态注册、显式与隐式广播、有序与无序广播的区分。然后重点讨论了BroadcastReceiver的插件化原理,即如何将静态注册转换为动态注册,通过分析VirtualApk库中的实现方式,揭示了将AndroidManifest.xml中的BroadcastReceiver动态注册的过程。
2340

被折叠的 条评论
为什么被折叠?



