03_系统广播与版本限制_修订版
03 系统广播与版本限制
基于原 PDF 修订、联网校对并补充缺失内容
1. 系统广播不是“永远都能收到”
原 PDF 列出了一批系统广播,但没有说明版本限制。现代 Android 为了省电、隐私和性能,对广播投递做了大量限制。学习系统广播时,一定要同时记住 targetSdkVersion、注册方式和广播是否豁免。
| Android 版本 | 关键变化 | 对开发的影响 |
|---|---|---|
| Android 7.0/API 24 | ACTION_NEW_PICTURE、ACTION_NEW_VIDEO 不再发送;target 24+ 的 CONNECTIVITY_ACTION 不能通过 manifest receiver 接收。 | 网络变化不要依赖静态注册;应动态注册或使用 NetworkCallback。 |
| Android 8.0/API 26 | target 26+ 不能在 manifest 中注册大多数隐式广播,除非广播显式发给该应用或属于豁免列表。 | 后台唤醒式广播大幅受限;多数场景改用 JobScheduler/WorkManager。 |
| Android 12/API 31 | 带 intent-filter 的 activity/service/receiver 必须显式声明 android:exported。 | Manifest receiver 不能省略 exported。 |
| Android 14/API 34 | 缓存状态下会延迟部分不重要系统广播;target 34+ 的动态 receiver 一般要指定导出 flag。 | 注册时要考虑 RECEIVER_EXPORTED/NOT_EXPORTED,并避免依赖低优先级广播即时到达。 |
2. 常见系统广播速查
| 场景 | Action | 建议 |
|---|---|---|
| 开机完成 | Intent.ACTION_BOOT_COMPLETED | 静态注册 + RECEIVE_BOOT_COMPLETED;onReceive 中转交 WorkManager。 |
| 飞行模式变化 | Intent.ACTION_AIRPLANE_MODE_CHANGED | 按需动态注册,注意不同版本和厂商策略。 |
| 电量变化 | Intent.ACTION_BATTERY_CHANGED | 通常动态查询/注册;不要把它当作后台保活手段。 |
| 电量低/恢复 | Intent.ACTION_BATTERY_LOW / ACTION_BATTERY_OKAY | 适合降低耗电任务、暂停非必要同步。 |
| 屏幕开关 | Intent.ACTION_SCREEN_ON / SCREEN_OFF | 现代版本后台投递可能被优化/延迟,谨慎依赖。 |
| 包安装/删除 | Intent.ACTION_PACKAGE_ADDED / PACKAGE_REMOVED | 需要 data scheme=package;注意包可见性与隐私限制。 |
| 耳机插拔 | Intent.ACTION_HEADSET_PLUG | 更现代的音频路由场景优先考虑 AudioManager 回调。 |
| 网络变化 | ConnectivityManager.CONNECTIVITY_ACTION | 不推荐作为核心方案;用 NetworkCallback/NetworkCapabilities。 |
3. 网络变化监听:旧写法与新写法
原 PDF 使用 ConnectivityManager.getActiveNetworkInfo() 与 NetworkInfo.isAvailable() 判断网络。这个方向已经过时:NetworkInfo 相关 API 已逐步废弃,现代代码应使用 NetworkCapabilities 或 NetworkCallback。
// Kotlin:一次性判断当前默认网络是否具备互联网能力
fun Context.isNetworkAvailable(): Boolean {
val cm = getSystemService(ConnectivityManager::class.java)
val network = cm.activeNetwork ?: return false
val caps = cm.getNetworkCapabilities(network) ?: return false
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
// Kotlin:监听网络变化
class NetworkMonitor(context: Context) {
private val cm = context.getSystemService(ConnectivityManager::class.java)
private val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
// 网络可用
}
override fun onLost(network: Network) {
// 网络丢失
}
}
fun start() {
cm.registerDefaultNetworkCallback(callback)
}
fun stop() {
cm.unregisterNetworkCallback(callback)
}
}
4. Manifest receiver 能唤起应用,但不是通用后台入口
文档中“静态注册的广播接收器可以在程序未启动时接收到广播”只在部分场景成立。更准确的说法是:Manifest receiver 是应用入口之一,系统可在合规场景下启动应用进程并调用 receiver;但从 Android 8.0 起,大多数隐式广播不能通过 manifest receiver 注册。
- 适合静态注册:开机、时区/语言等少数豁免广播,或明确发给本应用的显式广播。
- 不适合静态注册:频繁变化事件,例如网络变化、电量频繁变化、屏幕开关保活。
- 需要后台可靠执行:让广播只做触发入口,真正任务交给 WorkManager/JobScheduler。
5. 隐式广播豁免列表怎么用
Android 官方维护了“Implicit broadcast exceptions”列表。开发时不要背全部 action,而是确认你的 targetSdkVersion 和广播是否在豁免范围内;不在列表里时,manifest receiver 通常不能作为方案。
参考资料
- Android Developers - Broadcasts overview: https://developer.android.com/develop/background-work/background-tasks/broadcasts
- Android Developers - Implicit broadcast exceptions: https://developer.android.com/develop/background-work/background-tasks/broadcasts/broadcast-exceptions
- Android Developers - BroadcastReceiver API reference: https://developer.android.com/reference/android/content/BroadcastReceiver
- Android Developers - LocalBroadcastManager release notes: https://developer.android.com/jetpack/androidx/releases/localbroadcastmanager
- Android Developers - Android 14 behavior changes: https://developer.android.com/about/versions/14/behavior-changes-14
- Android Developers - Android 12 behavior changes: https://developer.android.com/about/versions/12/behavior-changes-12
- Android Developers - ConnectivityManager API reference: https://developer.android.com/reference/android/net/ConnectivityManager
- Android Developers - Sticky broadcasts risk: https://developer.android.com/privacy-and-security/risks/sticky-broadcast