WebView 廣告攔截淺析

原文連接 blog.rosuh.me/2019/02/web…javascript

前言

查豆瓣 使用的是 WebView 加載頁面,在豆瓣的移動頁面中存在兩到三個的廣告輪播圖,比較影響閱讀體驗。因此開始着手看看怎麼屏蔽掉廣告。html

在 WebView 中有如下三個方法能夠考慮:java

fun onPageFinished(view: WebView, url: String)
fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? 
fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean 
複製代碼
  • onPageFinished方法會在頁面加載完畢後回調android

  • shouldInterceptRequest方法會通知 host Application,也就是啓動 WebView 的應用返回WebResourceResponse。若是本地應用返回null,則webView會正常加載資源git

  • shouldOverrideUrlLoading會在Url被加載前被回調。實現此方法,返回trueWebView將不會加載該Url,不然將會正常加載Urlgithub

    • 此方法僅在主動或被動調用WebView.load(url)方法時纔會回調,而頁面中的資源加載時是不會被回調的
      • 好比主動顯式調用:webview.load(url)
      • 被動則是頁面中點擊連接以後加載
    • 此方法不適用於POST請求

    基於上述三個方法,咱們看看可否作到:web

    1. 禁止加載廣告域名
    2. 給廣告域名請求返回空的數據
    3. 在頁面加載完畢後消除廣告佔位的div或相似元素

1. 禁止加載廣告域名

根據shouldOverrideUrlLoading()方法的特性,咱們幾乎沒法用之來屏蔽頁面中加載的廣告。ide

在實踐中,通常在這處理網頁對本地資源的調用,好比最多見的拉起 APP 的操做。ui

override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
    val url = request.url.toString()
    if (url.startsWith("douban:")) {
        // 拉起豆瓣 APP
        handleAppRequest(view, url)
        return true
    }
    return super.shouldOverrideUrlLoading(view, request)
}
複製代碼

此方法看起來應該是不行了。這一步也應該無法輕易辦到。lua

2. 給廣告域名請求返回空的數據

咱們把目光彙集到了shouldInterceptRequest()方法,實際上這個方法的功勞最大。咱們很輕易就是實現了廣告攔截。

override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
    return if (isAdDomain(request.url.toString())) {
        createEmptyResource()
    } else super.shouldInterceptRequest(view, request)
}

fun createEmptyResource(): WebResourceResponse {
    return WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray()))
}

fun isAdDomain(url: String): Boolean {
    return (!url.contains("douban")) or url.contains("baidu")
}
複製代碼

前面提起的,此方法會在請求數據前回調。因此咱們能夠本身構建WebResourceResponse對象返回。

豆瓣的移動端對接的是百度的推廣,因此基本上廣告域名都帶有baidu的關鍵字。因此我這樣就已經足夠了。

更通常的狀況,咱們能夠本身維護規則列表或者,使用一些公開的規則列表。或者本身收集一下常見的大的推廣聯盟的連接就能夠了。

3. 消除空白廣告元素

咱們給廣告請求返回了空數據,可是原有的廣告佔位元素依然存在。因此咱們要用到

onPageFinished()方法,來刪除廣告佔位標籤。

override fun onPageFinished(view: WebView, url: String) {
    webView.evaluateJavascript(
        "javascript:(" +
                " function() {" +
                " var len = document.getElementsByClassName('Advertisement').length; " +
                " for(var i = 0; i < len; i ++){" +
                " document.getElementsByClassName('Advertisement')[i].style.display = 'none'" +
                " }" +
                " }" +
                ")()"
    ) {
        print(it)
    }
}
複製代碼

這裏利用了WebView.evaluateJavascript()方法,執行了一段 JavaScript 代碼:

javascript:(
    function() {
            var len = document.getElementsByClassName('Advertisement').length;
            for(var i = 0; i < len; i ++ ){
                document.getElementsByClassName('Advertisement')[i].style.display = 'none'
            }
        }
)()
複製代碼

這裏的代碼須要你根據不一樣的頁面來維護規則。好比豆瓣的移動端廣告都用Advertisement做爲類名。

因此獲取了個數以後,降之隱藏。

結語

至此,咱們簡單地實現了對豆瓣移動端網頁的攔截。

參考連接:

相關文章
相關標籤/搜索