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 通常不能作为方案。

参考资料