1. 程式人生 > >AccessibilityService 獲取WebView內容

AccessibilityService 獲取WebView內容

相信很多人使用AccessibilityService獲取WebView內容的時候是為空的,使用AccessibilityNodeInfo的findAccessibilityNodeInfosByText方法是獲取不到WebView裡面的內容的。

解決方法:
給AccessibilityService服務新增一個Flag,下面的所有程式碼是Kotlin的寫法

// 設定標誌位,讀取webView內容
serviceInfo.flags = serviceInfo.flags or AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY

serviceInfo 是AccessibilityService服務的配置資訊,可以使用AccessibilityService的getServiceInfo()方法獲取,因為Kotlin寫法簡化了。

如果想獲取WebView的子控制元件資訊的封裝類AccessibilityNodeInfo,使用findAccessibilityNodeInfosByText是不行的,只能先找出WebView控制元件的AccessibilityNodeInfo再遍歷它的子控制元件來獲取。

下面是查詢頁面的WebView控制元件的程式碼:


/**
 * 遞迴遍歷出WebView節點
 */
private var accessibilityNodeInfoWebView: AccessibilityNodeInfo? = null
private fun findWebViewNode(rootNode: AccessibilityNodeInfo) {
    for (i in 0 until rootNode.childCount) {
        val child = rootNode.getChild(i)
        if ("android.webkit.WebView" == child.className) {
            accessibilityNodeInfoWebView = child
            Log.d("findWebViewNode--", "找到webView")
            return
        }
        if (child.childCount > 0) {
            findWebViewNode(child)
        }
    }
}

傳入的rootNode 是AccessibilityService的rootInActiveWindow,就是頁面檢視的根

現在找出了WebView的AccessibilityNodeInfo資訊accessibilityNodeInfoWebView,然後我們就可以遍歷它的子控制元件獲取想要的內容了。

private fun getRecordNode(webviewNode: AccessibilityNodeInfo) {
    val count = webviewNode.childCount
    Log.e("getRecordNode--", "孩子數:$count")
    ...
    val child = webviewNode.getChild(i)
    child.contentDescription.toString()
    ...
}

注意的地方:

WebView的子控制元件是沒有ID的,只能獲取contentDescription等有限的資訊。

目前測試WebView裡面的控制元件也不可以模擬點選,滾動等操作,估計非原生控制元件的緣故,找到好方法的可以告訴我。

還有WebView的內容在載入完成之後整個頁面的內容都可以獲取,包括螢幕不可見的部分,區別於原生控制元件的列表檢視只可以獲取螢幕可見的控制元件,原生控制元件的列表檢視是經過優化的,為達到減少記憶體消耗的目的,只建立滿足螢幕高度的有限個數Item,然後在滾動的時候重用不可見的Item。

系統自帶有一個叫Talkback的AccessibilityService,它是可以獲取WebView內容的,可以參考它的原始碼: