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做为类名。

因此获取了个数以后,降之隐藏。

结语

至此,咱们简单地实现了对豆瓣移动端网页的拦截。

参考连接:

相关文章
相关标签/搜索