You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 14无障碍服务自动授予权限失效问题求助

Android 14无障碍服务自动授权失效问题排查与解决

可能的原因

  • 权限弹窗交互逻辑变更:Android 14对系统权限控制器的弹窗做了底层优化,即便按钮resource-id未变,弹窗的渲染时机、节点层级或可交互状态的判定逻辑已调整,导致无障碍服务触发点击时按钮还未处于可点击状态。
  • 无障碍事件监听不完整:Android 14可能新增了权限弹窗的窗口事件类型,你的无障碍服务未配置对应的事件监听,导致错过弹窗出现的时机。
  • 权限请求分组影响:Android 14中READ_CONTACTS和WRITE_CONTACTS属于同一权限组,若应用分开请求这两个权限,弹窗结构可能和Android 13不同,导致节点查找失效。
  • 节点状态判断误差:代码中isClickable的判定在Android 14下可能存在延迟,或者节点回收时机过早,导致点击动作未被正确执行。

解决方案

1. 更新无障碍服务的事件配置

在无障碍服务对应的accessibility_service_config.xml中,添加完整的事件类型,确保捕获权限弹窗的所有状态变化:

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:accessibilityEventTypes="typeWindowStateChanged|typeViewClicked|typeViewFocused|typeWindowContentChanged"
    android:packageNames="com.android.permissioncontroller" />

2. 优化节点查找与点击时机

增加弹窗等待逻辑

在触发点击前,添加循环检查机制,确保按钮完全渲染并处于可点击状态:

fun clickOnButton(selector: String, findByText: Boolean): Boolean {
    var success = false
    // 循环检查3次,每次间隔500ms
    repeat(3) { attempt ->
        val nodes = if (findByText) {
            eventRootInActiveWindow?.findAccessibilityNodeInfosByText(selector)
        } else {
            eventRootInActiveWindow?.findAccessibilityNodeInfosByViewId(selector)
        }
        success = nodes?.firstOrNull { it.isClickable && it.isVisibleToUser }?.let { node ->
            Log.v(TAG, "Found clickable node on attempt $attempt: $node")
            click(node, clickOnlyIfVisible = true).also { node.recycle() }
        } ?: false
        if (success) return@repeat
        Thread.sleep(500)
    }
    return success
}

修复点击函数的异常处理

完善click函数的异常捕获与状态判断,添加错误日志便于排查:

private fun AccessibilityServiceQ.click(it: AccessibilityNodeInfo, clickOnlyIfVisible: Boolean = false): Boolean {
    return runCatching {
        val canClick = if (clickOnlyIfVisible) it.isVisibleToUser && it.isClickable else it.isClickable
        if (canClick) {
            Log.v(TAG, "ACC::onAccessibilityEvent: click - $it")
            it.performAction(AccessibilityNodeInfo.ACTION_CLICK)
        } else {
            Log.v(TAG, "ACC::onAccessibilityEvent: cannot click - visible:${it.isVisibleToUser}, clickable:${it.isClickable}")
            false
        }
    }.onFailure { e ->
        Log.e(TAG, "Failed to click node", e)
        false
    }.getOrDefault(false)
}

3. 调整权限请求方式

Android 14中通讯录权限属于同一组,合并请求可减少弹窗数量并适配新结构:

val PERMISSIONS = arrayOf(
    Manifest.permission.ACCESS_COARSE_LOCATION,
    Manifest.permission.READ_CONTACTS // 请求该权限会自动包含WRITE_CONTACTS权限
)

注:Android 13及以上版本中,请求READ_CONTACTS时,系统会同时弹出包含写入权限的弹窗,无需单独请求WRITE_CONTACTS。

4. 验证节点层级与属性

再次使用uiautomatorviewer检查Android 14的权限弹窗:

  • 确认按钮的isClickable属性为true,且无其他视图遮挡
  • 检查弹窗的根节点是否变化,确保eventRootInActiveWindow获取的是权限弹窗的根节点

5. 增加调试日志

在节点查找过程中添加详细日志,确认是否找到目标节点:

val nodes = if (findByText) {
    eventRootInActiveWindow?.findAccessibilityNodeInfosByText(selector)
} else {
    eventRootInActiveWindow?.findAccessibilityNodeInfosByViewId(selector)
}
Log.v(TAG, "Found ${nodes?.size ?: 0} nodes for selector: $selector")
nodes?.forEach { node ->
    Log.v(TAG, "Node info: id=${node.viewIdResourceName}, clickable=${node.isClickable}, visible=${node.isVisibleToUser}")
}

内容的提问来源于stack exchange,提问作者Kris Tall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:06:04