如何在android中使用无障碍服务获取视图ID

Rag*_*ghu 3 android accessibilityservice

我是安卓的初学者。我想获取用户当前正在查看的视图的视图 ID。我让我的问题更清楚一点。假设用户打开 MakeMyTrip 并导航到航班预订页面。现在我想获取该特定布局的视图 ID。下面是我的服务类和 xml 配置文件。

public class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {

    AccessibilityNodeInfo source = event.getSource();

    Log.d("ViewID",source.getViewIdResourceName());


}

@Override
public void onInterrupt() {

}



<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeWindowContentChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagReportViewIds"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_service_description"
android:packageNames="com.makemytrip" />
Run Code Online (Sandbox Code Playgroud)

Chr*_*sCM 5

我的猜测是你打电话给

Log.d("ViewID",source.getViewIdResourceName());
Run Code Online (Sandbox Code Playgroud)

是这样做的:

Log.d("ViewID", null)
Run Code Online (Sandbox Code Playgroud)

window_content_changed事件的源节点将是其内容更新的布局的根节点。这极不可能有 viewIDResourceName。大多数视图没有资源名称,可通过直接访问视图访问的视图 ID 只是自动生成的哈希值,没有任何意义。只有具有实际 viewResourceNames 的视图才会将其名称报告给无障碍服务。因此,如果元素没有R.id.viewResourceName可访问性服务将报告null该值。Android Log 实用程序无法记录空值,您至少必须给它一个空字符串。

你应该这样做。

String viewIdName = source.getViewIdResourceName();
Log.d("ViewID", (viewIdName != null) ? viewIdName : "NO VIEW ID");
Run Code Online (Sandbox Code Playgroud)

值得注意的是,对于打印出来的地方,您总是会得到“NO VIEW ID”。您将不得不向下爬取视图层次结构以找到具有资源名称的视图。找到一些按钮或您分配了 ID 的东西!或者潜在地侦听不同类型的可访问性事件。不过要小心!并非所有事件都有源节点!所以,如果你听

android:accessibilityEventTypes="typeAllMask"
Run Code Online (Sandbox Code Playgroud)

您还需要检查空源节点。或者你会得到不同类型的空指针异常。

编辑:用于记录整个可访问性节点视图层次结构的基本递归函数。

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

    if (nodeInfo == null) return;

    String spacerString = "";

    for (int i = 0; i < depth; ++i) {
        spacerString += '-';
    }
    //Log the info you care about here... I choce classname and view resource name, because they are simple, but interesting.
    Log.d("TAG", spacerString + nodeInfo.getClassName() + " " + nodeInfo.getViewIdResourceName());

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

//Then call it like this from anywhere in your service, don't necessarily have to use the root node.  
logViewHierarchy(getRootInActiveWindow(), 0);
Run Code Online (Sandbox Code Playgroud)