event.getSource 在辅助功能服务中返回 null。(捕获第 3 方应用程序的源代码)

Pse*_*der 1 java android accessibility accessibilityservice

我需要使用其资源 ID(我知道)读取 3rd 方应用程序的资源。我参考了这个链接: 如何阅读窗口内容(使用accessibilityService)并使用draw over other app permission in Android? 为了实现这个功能。

问题:使用 event.getSource() 创建的 AccessibilityNodeInfo 对象源为 null。

鉴于我知道 Source 类,我想创建一个 AccessibilityNodeInfo 对象

Chr*_*sCM 5

并非所有事件都与“源”节点相关联。事实上,大多数超级频繁发生的事件都没有。(触摸交互、窗口变化等)。您需要确保按具有源节点的事件进行过滤。话虽如此,我怀疑这是否是您想要的,具有源节点的事件很少会包含您正在寻找的节点。您可能希望在响应某些辅助功能事件子集后,探索从根节点开始的 AccessibilityNodeInfo 层次结构。

首先,确保您的服务配置正确。我认为看起来像这样的 service_config.xml 就足够了。

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:accessibilityEventTypes="typeWindowsChanged|typeWindowContentChanged|typeViewScrolled"
    android:accessibilityFlags="flagReportViewIds"
    android:canRetrieveWindowContent="true"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="1000"
    android:settingsActivity="com.moba11y.basicaccessibilityservice.SettingsActivity"
    />
Run Code Online (Sandbox Code Playgroud)

一些亮点:

android:accessibilityEventTypes="typeWindowsChanged|typeWindowContentChanged|typeViewScrolled"
Run Code Online (Sandbox Code Playgroud)

此行旨在捕获在窗口上绘制了任何新内容的事件类型。注意:这些事件都没有自己的 event.getSource() 节点。每次都是空的!(恕我直言:这些事件的 event.getSource() 应该是根节点,但这只是我,问谷歌!!!)。

android:notificationTimeout="1000"
Run Code Online (Sandbox Code Playgroud)

每秒仅获取一次特定类型的事件。非常适合节流频繁抛出的事件,如滚动事件。

android:canRetrieveWindowContent="true"
Run Code Online (Sandbox Code Playgroud)

当我调用时不要抛出异常getRootInActiveWindow()

android:accessibilityFlags="flagReportViewIds"
Run Code Online (Sandbox Code Playgroud)

确保使用 AccessibilityNodeInfo 报告 viewID。

有了适当的无障碍服务配置,剩下的就很简单了。在可访问性事件的子集之后(上面的配置旨在捕获新的屏幕内容),在视图层次结构中搜索您的视图 ID。

public static void exploreNodeHierarchy(final AccessibilityNodeInfo nodeInfo, final int depth) {

    //Super important check! AccessibilityNodes can get invalidated at ANY time.
    if (nodeInfo == null) return;

    //Log the nodeINfo to string, with some tabs for visible parent/child relationships.
    Log.d(BasicAccessibilityService.class.getName(), new String(new char[depth]).replace("\0", "\t") + nodeInfo.toString());

    if (nodeInfo.getViewIdResourceName() == "the view id you have") {
        //Do work here.
    }

    for (int i = 0; i < nodeInfo.getChildCount(); ++i) {
        logNodeHierarchy(nodeInfo.getChild(i), depth + 1);
    }
}

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

    exploreNodeHierarchy(getRootInActiveWindow(), 0);
}
Run Code Online (Sandbox Code Playgroud)