You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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() {
        // 这里写你的电池优化状态检查代码
    }
}

关键注意点

  1. 覆盖所有需求场景:包含你提到的电池优化、各类定位权限、通知权限、读取电话状态、应用闲置暂停、附近WiFi设备所有场景
  2. 兼容性处理:用runCatching包裹可能抛出异常的监听注册逻辑,适配不同OEM系统的兼容性问题
  3. 资源安全:在onPause/onDestroy中务必调用stopWatching,避免广播接收器泄漏
  4. 权限前置:确保你的应用已经在Manifest中声明了对应权限,并且完成了动态权限申请(比如定位权限需要先申请才能监听变更)

火山引擎 最新活动