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 组件的树形结构的顶层节点,可以从它开始递归地遍历整个界面元素。
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="${node.text}" ")
xmlContent.append("description="${node.contentDescription}" ")
xmlContent.append("viewId="${node.viewIdResourceName}" ")
xmlContent.append("packageName="${node.packageName}" ")
xmlContent.append("bounds="${bounds.flattenToString()}" ")
xmlContent.append("clickable="${node.isClickable}" ")
xmlContent.append("enabled="${node.isEnabled}" ")
xmlContent.append("focusable="${node.isFocusable}" ")
xmlContent.append("focused="${node.isFocused}" ")
xmlContent.append("scrollable="${node.isScrollable}" ")
xmlContent.append("selected="${node.isSelected}" ")
xmlContent.append("checkable="${node.isCheckable}" ")
xmlContent.append("checked="${node.isChecked}" ")
// 如果有子节点,则保留内部层次
if (node.childCount > 0) {
xmlContent.append(">\n")
for (i in 0 until node.childCount) {
buildXml(node.getChild(i), xmlContent, depth + 1)
}
xmlContent.append("$indent</View>\n")
} else {
// 无子节点直接闭合标签
xmlContent.append("/>\n")
}
}
private fun saveToFile(fileName: String, content: String) {
try {
val file = File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName)
file.writeText(content)
Log.d("MyAccessibilityService", "XML 文件已保存: ${file.absolutePath}")
} catch (e: Exception) {
Log.e("MyAccessibilityService", "保存文件时出错: ${e.message}")
}
}
}
复制代码
2、Service注册
AccessbilityService本质还是Service,所以需要在
AndroidManifest.xml
中进行注册:
<service
android:name=".MyAccessibilityService"
android:exported="false"
android:label="BasicsCodelab"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
复制代码
android:name=".MyAccessibilityService"
:
该属性指定无障碍服务的类名称,MyAccessibilityService 是一个继承自 AccessibilityService 的类。这个类负责处置惩罚无障碍相关的变乱。
android:exported="false"
:
用于明确标识该服务是否可以被其他应用启动或绑定。设置为 false 表现该服务不会被外部应用访问,只能由系统或该应用内访问。对于无障碍服务,通常设置为 false。
android:label="BasicsCodelab"
:
该属性为无障碍服务指定了一个用户友好的名称。在设备的设置界面中,用户可以看到该服务的名称。BasicsCodelab 是你的服务显示的名称,可以根据需要更改为你的应用或服务的名称。
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
:
这个权限声明白该服务需要一个特定的权限才气绑定到无障碍服务。BIND_ACCESSIBILITY_SERVICE 权限是系统权限,通常只能由系统或具有相应权限的应用绑定,确保只有合适的应用能够访问这个服务。
<intent-filter>
:
在这个 intent-filter 中,<action android:name="android.accessibilityservice.AccessibilityService" /> 使系统知道该服务是一个无障碍服务。
这告诉 Android 系统,该服务的 action 是 android.accessibilityservice.AccessibilityService,它是系统辨认无障碍服务的尺度动作。
<meta-data>
:
meta-data 元素用于指示系统该服务的配置文件位置。它的 android:name="android.accessibilityservice" 属性是系统所需的标识符。
android:resource="@xml/accessible_service_config" 指定了该服务的配置文件 accessible_service_config.xml,该文件位于 res/xml/ 目录中。
accessible_service_config.xml 是一个 XML 配置文件,其中界说了无障碍服务的具体配置,如服务接收的变乱类型、反馈类型、设置页面等。
3、监听相关配置
在
res
文件夹下
xml
文件夹 (没有的话新建),然后新建一个配置xml文件
在里面写入如下代码:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:notificationTimeout="100"
android:description="@string/app_name"
android:packageNames="com.codelab.basics"/>
复制代码
android:accessibilityEventTypes="typeAllMask"
界说服务接收的无障碍变乱类型。
typeAllMask 表现接收所有类型的无障碍变乱。
其他常用变乱类型:
typeViewClicked: 视图被点击变乱。
typeViewFocused: 视图得到焦点变乱。
typeWindowStateChanged: 窗口状态变化变乱。
android:accessibilityFeedbackType="feedbackGeneric"
指定服务提供的反馈类型。
feedbackGeneric 是通用的反馈类型,实用于多种无障碍服务场景。
其他反馈类型:
feedbackSpoken: 语音反馈。
feedbackHaptic: 触觉反馈(振动)。
feedbackAudible: 音频反馈。
feedbackVisual: 视觉反馈。
android:accessibilityFlags="flagDefault"
配置无障碍服务的行为标志。
flagDefault 是默认标志,通常用于尺度无障碍服务。
其他标志:
flagIncludeNotImportantViews: 包罗非紧张视图(例如装饰性视图)。
flagRequestTouchExplorationMode: 哀求触摸探索模式(用于支持触摸屏的服务)。
android:canRetrieveWindowContent="true"
指定服务是否可以检索窗口内容。
假如设置为 true,服务可以访问窗口的内容(例如视图层次结构)。
对于需要操纵或查询视图节点的无障碍服务,这个属性必须设置为 true。
android:notificationTimeout="100"
设置无障碍变乱的关照超时时间,单位为毫秒。
用于合并频繁的变乱,避免服务处置惩罚过多的变乱关照。
android:description="@string/app_name"
提供无障碍服务的形貌信息,通常显示在设备的无障碍设置页面中。
@string/app_name 指向 strings.xml 中界说的字符串资源。可以修改为更具体的形貌,例如 "This service provides additional accessibility features."。
android:packageNames="com.codelab.basics"
指定服务监听的目的应用的包名。
假如留空,则表现服务可以接收所有应用的无障碍变乱。
当仅需要监听特定应用的无障碍变乱时,可以通过此属性限定服务的范围。
4、启用无障碍服务
运行APP,
设置
→
无障碍
→
找到我们的APP
→
若显示关闭说明无障碍服务没启动
→
点开
→
同意
运行结果
当前页面:
Android Studio日志系统Logcat:
将存储于android的xml文件导出至PC:
进入adb.exe的文件夹,在文件管理器地点栏输入cmd进入命令行。然后输入以下命令:
adb pull /手机存储路径/文件名 本地路径
复制代码
命令行界面如下:
xml文件如下:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4