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
相关产品推荐
相关产品推荐

