IT评测·应用市场-qidao123.com

标题: Android利用Accessibility Service获取当前页面的组件信息 [打印本页]

作者: 诗林    时间: 2025-1-7 21:20
标题: Android利用Accessibility Service获取当前页面的组件信息
1、自界说AccessibilityService

继承 AccessibilityService,重写 onInterrupt() 和 onAccessibilityEvent() 方法(这两个方法是 必须重写 的)。在onAccessibilityEvent() 方法中,val rootNode = rootInActiveWindow 获取当前活动窗口的根节点。rootInActiveWindow 是 AccessibilityNodeInfo 类型的一个属性,它代表了当前活动窗口的根节点。这个根节点是一个包含所有 UI 组件的树形结构的顶层节点,可以从它开始递归地遍历整个界面元素。
  1. package com.codelab.basics
  2. import android.accessibilityservice.AccessibilityService
  3. import android.graphics.Rect
  4. import android.os.Environment
  5. import android.util.Log
  6. import android.view.accessibility.AccessibilityEvent
  7. import android.view.accessibility.AccessibilityNodeInfo
  8. import java.io.File
  9. class MyAccessibilityService : AccessibilityService() {
  10.     override fun onAccessibilityEvent(event: AccessibilityEvent?) {
  11.         val rootNode = rootInActiveWindow//用于获取当前活动窗口的根节点
  12.         if (rootNode != null) {
  13.             val xmlContent = StringBuilder()
  14.             xmlContent.append("<?xml version="1.0" encoding="UTF-8"?>\n")
  15.             xmlContent.append("<ViewHierarchy>\n")
  16.             buildXml(rootNode, xmlContent, 1)
  17.             xmlContent.append("</ViewHierarchy>")
  18.             //将生成的 XML 内容先打印到日志中
  19.             Log.d("GeneratedXML", xmlContent.toString())
  20.             // 保存到文件
  21.             saveToFile("view_hierarchy_full.xml", xmlContent.toString())
  22.         }
  23.     }
  24.     override fun onInterrupt() {
  25.         // 无障碍服务被中断时的回调
  26.     }
  27.     private fun buildXml(node: AccessibilityNodeInfo?, xmlContent: StringBuilder, depth: Int) {
  28.         if (node == null) return
  29.         // 添加缩进
  30.         val indent = "    ".repeat(depth)
  31.         // 开始标签
  32.         xmlContent.append("$indent<View ")
  33.         // 获取所有公开属性
  34.         val bounds = Rect()
  35.         node.getBoundsInScreen(bounds) // 获取节点在屏幕上的边界
  36.         xmlContent.append("class="${node.className}" ")
  37.         xmlContent.append("text="${node.text}" ")
  38.         xmlContent.append("description="${node.contentDescription}" ")
  39.         xmlContent.append("viewId="${node.viewIdResourceName}" ")
  40.         xmlContent.append("packageName="${node.packageName}" ")
  41.         xmlContent.append("bounds="${bounds.flattenToString()}" ")
  42.         xmlContent.append("clickable="${node.isClickable}" ")
  43.         xmlContent.append("enabled="${node.isEnabled}" ")
  44.         xmlContent.append("focusable="${node.isFocusable}" ")
  45.         xmlContent.append("focused="${node.isFocused}" ")
  46.         xmlContent.append("scrollable="${node.isScrollable}" ")
  47.         xmlContent.append("selected="${node.isSelected}" ")
  48.         xmlContent.append("checkable="${node.isCheckable}" ")
  49.         xmlContent.append("checked="${node.isChecked}" ")
  50.         // 如果有子节点,则保留内部层次
  51.         if (node.childCount > 0) {
  52.             xmlContent.append(">\n")
  53.             for (i in 0 until node.childCount) {
  54.                 buildXml(node.getChild(i), xmlContent, depth + 1)
  55.             }
  56.             xmlContent.append("$indent</View>\n")
  57.         } else {
  58.             // 无子节点直接闭合标签
  59.             xmlContent.append("/>\n")
  60.         }
  61.     }
  62.     private fun saveToFile(fileName: String, content: String) {
  63.         try {
  64.             val file = File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName)
  65.             file.writeText(content)
  66.             Log.d("MyAccessibilityService", "XML 文件已保存: ${file.absolutePath}")
  67.         } catch (e: Exception) {
  68.             Log.e("MyAccessibilityService", "保存文件时出错: ${e.message}")
  69.         }
  70.     }
  71. }
复制代码
2、Service注册

AccessbilityService本质还是Service,所以需要在 AndroidManifest.xml 中进行注册:
  1. <service
  2.             android:name=".MyAccessibilityService"
  3.             android:exported="false"
  4.             android:label="BasicsCodelab"
  5.             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
  6.             <intent-filter>
  7.                 <action android:name="android.accessibilityservice.AccessibilityService" />
  8.             </intent-filter>
  9. </service>
复制代码

3、监听相关配置

在 res 文件夹下xml文件夹 (没有的话新建),然后新建一个配置xml文件

在里面写入如下代码:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:accessibilityEventTypes="typeAllMask"
  4.     android:accessibilityFeedbackType="feedbackGeneric"
  5.     android:accessibilityFlags="flagDefault"
  6.     android:canRetrieveWindowContent="true"
  7.     android:notificationTimeout="100"
  8.     android:description="@string/app_name"
  9.     android:packageNames="com.codelab.basics"/>
复制代码

4、启用无障碍服务

运行APP,设置 → 无障碍 → 找到我们的APP → 若显示关闭说明无障碍服务没启动点开同意

运行结果

当前页面:

Android Studio日志系统Logcat:

将存储于android的xml文件导出至PC:
        进入adb.exe的文件夹,在文件管理器地点栏输入cmd进入命令行。然后输入以下命令:
  1. adb pull /手机存储路径/文件名 本地路径
复制代码
        命令行界面如下:

xml文件如下:




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4