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內容的,可以參考它的原始碼: