Android 14+ 运行时指定权限变更监听的广播接收器注册/注销代码需求
Android 14+ 运行时指定权限变更监听的广播接收器注册/注销代码需求
我明白你需要监听一系列权限和系统状态变更的场景,包括电池优化、各类定位权限、通知权限、读取电话状态、应用闲置暂停、附近WiFi设备这些。之前的代码没能完全覆盖你的需求,下面是适配Android 14+的完整实现,包含注册和注销逻辑,可直接在Activity或Service中使用:
核心实现代码
@file:Suppress("DEPRECATION") package com.mobeetest.worker.utilities.permissions import android.app.AppOpsManager import android.content.* import android.location.LocationManager import android.os.Build import android.util.Log import androidx.annotation.RequiresApi class RuntimePermissionWatcher( private val context: Context, // 自定义判断逻辑:当前是否需要监听某个权限/状态 private val shouldWatch: (String) -> Boolean, // 权限/状态变更时的回调通知 private val onPermissionChanged: (String) -> Unit ) { private val tag = "RuntimePermissionWatcher" private val appOps by lazy { context.getSystemService(AppOpsManager::class.java) } // 映射AppOp操作码到对应的权限名称,方便后续回调识别 private fun opToPermissionName(op: String?): String? = when (op) { AppOpsManager.OPSTR_FINE_LOCATION, AppOpsManager.OPSTR_COARSE_LOCATION, AppOpsManager.OPSTR_ACCESS_BACKGROUND_LOCATION -> "Location" AppOpsManager.OPSTR_READ_PHONE_STATE -> "PhoneState" AppOpsManager.OPSTR_POST_NOTIFICATION -> "Notifications" AppOpsManager.OPSTR_NEARBY_WIFI_DEVICES -> "NearbyWifi" AppOpsManager.OPSTR_RUN_IN_BACKGROUND -> "BackgroundActivity" AppOpsManager.OPSTR_PAUSE_APP_WHILE_UNUSED -> "AppIdlePause" else -> null } // AppOps权限变更监听:覆盖大部分权限的变更场景 private val opChangedListener = AppOpsManager.OnOpChangedListener { op, pkg -> // 只处理当前应用的权限变更 if (pkg != context.packageName) return@OnOpChangedListener val permissionName = opToPermissionName(op) ?: return@OnOpChangedListener // 按自定义逻辑过滤需要监听的项 if (!shouldWatch(permissionName)) return@OnOpChangedListener onPermissionChanged(permissionName) } // 定位服务状态变更的广播接收器(补充AppOps覆盖不到的服务开关场景) private val locationReceiver = object : BroadcastReceiver() { override fun onReceive(ctx: Context?, intent: Intent?) { val action = intent?.action ?: return if (action == LocationManager.MODE_CHANGED_ACTION || action == LocationManager.PROVIDERS_CHANGED_ACTION) { if (shouldWatch("Location")) { onPermissionChanged("Location") } } } } // 电池优化/省电模式变更的广播接收器 private val batteryReceiver = object : BroadcastReceiver() { override fun onReceive(ctx: Context?, intent: Intent?) { val action = intent?.action ?: return if (action == android.os.PowerManager.ACTION_POWER_SAVE_MODE_CHANGED || action == android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED) { if (shouldWatch("BatteryOptimization")) { onPermissionChanged("BatteryOptimization") } } } } // 初始化广播过滤器 private val locationFilter by lazy { IntentFilter().apply { addAction(LocationManager.MODE_CHANGED_ACTION) addAction(LocationManager.PROVIDERS_CHANGED_ACTION) } } private val batteryFilter by lazy { IntentFilter().apply { addAction(android.os.PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) addAction(android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED) } } @RequiresApi(Build.VERSION_CODES.Q) fun startWatching() { try { // 注册系统广播接收器 context.registerReceiver(batteryReceiver, batteryFilter) context.registerReceiver(locationReceiver, locationFilter) // 批量监听所有需要的AppOps权限 val opsToWatch = listOf( AppOpsManager.OPSTR_FINE_LOCATION, AppOpsManager.OPSTR_COARSE_LOCATION, AppOpsManager.OPSTR_ACCESS_BACKGROUND_LOCATION, AppOpsManager.OPSTR_READ_PHONE_STATE, AppOpsManager.OPSTR_POST_NOTIFICATION, AppOpsManager.OPSTR_NEARBY_WIFI_DEVICES, AppOpsManager.OPSTR_RUN_IN_BACKGROUND, AppOpsManager.OPSTR_PAUSE_APP_WHILE_UNUSED ) opsToWatch.forEach { op -> runCatching { appOps.startWatchingMode(op, context.packageName, opChangedListener) }.onFailure { Log.w(tag, "监听权限$op失败: ${it.message}") } } } catch (t: Throwable) { Log.w(tag, "启动监听失败: ${t.message}") } } fun stopWatching() { // 安全注销广播接收器 runCatching { context.unregisterReceiver(locationReceiver) } runCatching { context.unregisterReceiver(batteryReceiver) } // 停止AppOps权限监听 runCatching { appOps.stopWatchingMode(opChangedListener) } } }
使用说明(以Activity为例)
class MainActivity : AppCompatActivity() { private lateinit var permissionWatcher: RuntimePermissionWatcher override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化监听器 permissionWatcher = RuntimePermissionWatcher( context = this, shouldWatch = { permissionName -> // 这里可以自定义需要监听的权限,比如只监听定位和电池优化 permissionName == "Location" || permissionName == "BatteryOptimization" }, onPermissionChanged = { permissionName -> // 权限变更后的业务处理逻辑 when(permissionName) { "Location" -> checkAndHandleLocationPermission() "BatteryOptimization" -> checkBatteryOptimizationStatus() "Notifications" -> checkNotificationPermission() // 其他权限的处理逻辑 } } ) } override fun onResume() { super.onResume() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { permissionWatcher.startWatching() } } override fun onPause() { super.onPause() permissionWatcher.stopWatching() } // 示例:定位权限检查逻辑 private fun checkAndHandleLocationPermission() { // 这里写你的权限检查和业务处理代码 } // 示例:电池优化状态检查逻辑 private fun checkBatteryOptimizationStatus() { // 这里写你的电池优化状态检查代码 } }
关键注意点
- 覆盖所有需求场景:包含你提到的电池优化、各类定位权限、通知权限、读取电话状态、应用闲置暂停、附近WiFi设备所有场景
- 兼容性处理:用
runCatching包裹可能抛出异常的监听注册逻辑,适配不同OEM系统的兼容性问题 - 资源安全:在
onPause/onDestroy中务必调用stopWatching,避免广播接收器泄漏 - 权限前置:确保你的应用已经在Manifest中声明了对应权限,并且完成了动态权限申请(比如定位权限需要先申请才能监听变更)




