1、自定义AccessibilityService
继承 AccessibilityService
,重写 onInterrupt()
和 onAccessibilityEvent()
方法(这两个方法是 必须重写 的)。在onAccessibilityEvent()
方法中,val rootNode = rootInActiveWindow
获取当前活动窗口的根节点。rootInActiveWindow
是 AccessibilityNodeInfo
类型的一个属性,它代表了当前活动窗口的根节点。这个根节点是一个包含所有 UI 组件的树形结构的顶层节点,可以从它开始递归地遍历整个界面元素。
package com.codelab.basics
import android.accessibilityservice.AccessibilityService
import android.graphics.Rect
import android.os.Environment
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import java.io.File
class MyAccessibilityService : AccessibilityService() {
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
val rootNode = rootInActiveWindow//用于获取当前活动窗口的根节点
if (rootNode != null) {
val xmlContent = StringBuilder()
xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
xmlContent.append("<ViewHierarchy>\n")
buildXml(rootNode, xmlContent, 1)
xmlContent.append("</ViewHierarchy>")
//将生成的 XML 内容先打印到日志中
Log.d("GeneratedXML", xmlContent.toString())
// 保存到文件
saveToFile("view_hierarchy_full.xml", xmlContent.toString())
}
}
override fun onInterrupt() {
// 无障碍服务被中断时的回调
}
private fun buildXml(node: AccessibilityNodeInfo?, xmlContent: StringBuilder, depth: Int) {
if (node == null) return
// 添加缩进
val indent = " ".repeat(depth)
// 开始标签
xmlContent.append("$indent<View ")
// 获取所有公开属性
val bounds = Rect()
node.getBoundsInScreen(bounds) // 获取节点在屏幕上的边界
xmlContent.append("class=\"${node.className}\" ")
xmlContent.append("text=\"