此文翻译自GOOGLE中国官网关于广播的最佳实践。以下为翻译原文:
下面是关于广播发送和接收的安全及其他最佳实践案例:
如果你不需要发送广播给其他app的组件,那么你应该通过LocalBroadcastManager去发送和接收广播。使用LocalBroadcastManager会更加地有效率并且可以不用考虑有其他app接收或发送你的广播的安全问题。本地广播可以作为一个事件总线工具在app内使用而无需任何系统范围的广播开销。
如果很多app都已经在清单文件(AndroidManifest.xml)中注册了相同Action的广播接收者,这将会造成系统去启动这些app,对手机和用户体验造成严重的不良影响。为了避免这种情况出现,我们建议用动态注册广播接收者,不过某些情况下Android系统已经强制开发者使用动态注册广播接收者。比如CONNECTIVITY_ACTION广播已经强制在7.0以上系统使用动态注册,静态注册将不会响应。
不要通过广播的隐式intent发送敏感信息。这些信息可能会被其他注册了这个接收者的app所接收。下面有三种方式去控制哪些广播接收者可以接收你的广播:
- 在发送广播时定义permission属性
- 在Android 4.0 及以上,你可以通过setPackage(String)方法定义package信息去发送一个广播。系统会发送该广播给有该package信息的广播接收者。
- 你可以通过LocalBroadcastManager发送本地广播。
当注册了一个广播接收者时,任意一个app都可能发送潜在的恶意广播给你的app中的广播接收者。这里有三种方式去限制你所注册的广播接收者去接收哪些信息:
- 你可以给你的广播接收者定义permission属性
- 静态广播接收者可以通过在清单文件中定义
`android:exported
属性为false
限制其他app发送广播到本app的广播接收者。 - 通过LocalBroadcastManager注册本地广播。
广播定义的action变量可被全局接收,所以要为自己的广播定义一个特殊的action变量,避免和其他app的action变量产生冲突。
因为广播接收者的
onReceive(Context, Intent)
方法在主线程中运行,所以该方法应该在段时间内执行并返回,避免造成ANR。如果你需要在该方法中执行长时间的工作,就要小心使用子线程或开启一个service去运行,因为系统可能会在onReceive方法返回之后回收掉该app的进程。更多的信息请查看Effect on process state 。对于耗时较长的工作,我们有如下建议:- 在onReceive方法中调用
goAsync()
方法并发送BroadcastReceiver.PendingResult
给子线程。这能让你的广播接收者在onReceive方法中返回时保持其活跃。虽然系统希望你在10s内就结束掉这个广播,但是通过这方法能够让你的耗时工作在子线程中运行在避免造成ANR的同时避免该进程被系统回收。更多详细请看goAsync()方法的API - 通过JonScheduler去执行耗时工作。
- 在onReceive方法中调用
不要在广播接收者中启动activity,而是考虑使用notification。