前言
說起網(wǎng)頁廣告,那真是讓人又恨又愛,它們不但占用了網(wǎng)頁的可視控件,分散用戶的注意力,還有些浮動(dòng)廣告干擾甚至誤導(dǎo)用戶操作。但是廣告又是開發(fā)者重要的收入來源之一,比如我們?cè)谧鰹g覽器的同時(shí)需要接入新的廣告,同時(shí)又要過濾掉網(wǎng)頁中的廣告,這就是一個(gè)很正常的現(xiàn)象。說起應(yīng)用廣告過濾對(duì)于PC端來說可能更方便,網(wǎng)上有大量各種廣告過濾插件。但對(duì)于Android等移動(dòng)端來說就不那么友好了。Android應(yīng)用的廣告過濾方案大概可以分為以下幾種方式

分析
從上圖來看,雖然有這幾種方式,甚至還有一些方式?jīng)]有列出來,但其根本可以用一句話來概括:根據(jù)規(guī)則來過濾URL。其原理可以簡單概括如下:
過濾廣告很簡單,就是判斷頁面是否有廣告,如果有廣告,則不加載這條廣告。具體就要從網(wǎng)頁加載原理說起了。我們知道網(wǎng)頁其實(shí)就是html+css+js,請(qǐng)求網(wǎng)頁的時(shí)候,會(huì)先根據(jù)url來下載html文件,并進(jìn)行解析,解析到需要加載的css和js以及圖片視頻等資源的時(shí)候,就會(huì)去下載這些文件。也就是說,每一個(gè)文件的下載都對(duì)應(yīng)一條url,打開一個(gè)網(wǎng)頁,可能需要下載數(shù)十上百個(gè)文件,也就有這么多的url。所以我們可以針對(duì)每一條url進(jìn)行判斷,看其到底是不是會(huì)產(chǎn)生廣告的url,或者就是廣告的資源。
代理方式:
1.1 服務(wù)器方式:對(duì)于一個(gè)應(yīng)用如果數(shù)據(jù)來源于指定的服務(wù)器,只需要我們?cè)谥付ǖ姆?wù)器里控制好資源請(qǐng)求與分發(fā)即可,那么對(duì)于移動(dòng)應(yīng)用來說去廣告的效率更好,因?yàn)橘Y源的過濾運(yùn)算均在服務(wù)器,而不在移動(dòng)端,相對(duì)來說更可維護(hù),但這樣的對(duì)服務(wù)器的任務(wù)又是一個(gè)問題了。
1.2 AdBlockplus: 世界上的網(wǎng)站何止千萬,而這些網(wǎng)站的內(nèi)容又隨時(shí)都有可能發(fā)生變化。因此,AdBlockPlus想出了一個(gè)解決方案:通過社區(qū)來維護(hù)一個(gè)規(guī)則表,然后根據(jù)這個(gè)規(guī)則表來過濾url,同時(shí)讓用戶自己動(dòng)手,參與到制作這個(gè)規(guī)則表的過程中來,以成千上萬的用戶來對(duì)抗千變?nèi)f化的廣告。但是一個(gè)app是怎么能夠?qū)φ麄€(gè)手機(jī)的流量進(jìn)行過濾的呢?其實(shí)很簡單,AdBlockPlus自動(dòng)對(duì)手機(jī)設(shè)置了代理,代理到本機(jī)的2020端口,然后建立了一個(gè)簡單的代理服務(wù)器,將所有的網(wǎng)絡(luò)請(qǐng)求都統(tǒng)一通過這個(gè)代理來處理,從而達(dá)到全局的廣告過濾效果。當(dāng)然,當(dāng)使用數(shù)據(jù)流量的時(shí)候,需要root權(quán)限,在4.0版本以上的wifi下的代理設(shè)置,也需要root權(quán)限,或者手動(dòng)進(jìn)行設(shè)置。我們先不管AdBlockPlus的代理服務(wù)器那部分功能,只看其核心的部分,也就是下載并讀取規(guī)則文件,然后根據(jù)規(guī)則文件來判斷url是否應(yīng)該被過濾。如果你看過其安卓源碼,你就會(huì)驚訝的發(fā)現(xiàn),里面居然是用jni實(shí)現(xiàn)的,再仔細(xì)看的話,會(huì)發(fā)現(xiàn)jni的代碼只是封裝了靜態(tài)鏈接庫里面的內(nèi)容,真正干活的部分都在靜態(tài)鏈接庫里,至于靜態(tài)鏈接庫里面的源碼,就得裝上git,hg,然后按照使用說明,才能同步下來整個(gè)代碼庫。這還不算完,因?yàn)楣烙?jì)是為了能跨平臺(tái)使用,其核心部分代碼是用js寫的。AdBlockPlus就是通過V8引擎來執(zhí)行js代碼的,而js代碼和V8引擎,都先通過交叉編譯,被整合到了靜態(tài)鏈接庫中,最后通過jni封裝以后,編譯成動(dòng)態(tài)鏈接庫來Android使用??梢哉fAdBlockPlus的核心就是對(duì)規(guī)則庫的解析和匹配了,所以如果想修改AdBlockPlus的核心代碼,則需要修改js、編譯V8才行,或者使用java完全重寫js代碼的內(nèi)容,而如果只想快速的將AdBlockPlus的廣告過濾功能應(yīng)用到自己的app中,就只能把原封不動(dòng)的使用現(xiàn)成的模塊了。WebView自處理:
2.1 shouldInterceptRequest攔截:通過WebViewClient的源代碼發(fā)現(xiàn)里面有個(gè)回調(diào)方法WebResourceResponse shouldInterceptRequest(WebView view, String url)這個(gè)方法中的url參數(shù)可以獲取到所有的請(qǐng)求鏈接,我們需要一個(gè)規(guī)則文件里面包含大量廣告host,每次獲取url判斷host規(guī)則文件中是否包含次鏈接/js名稱/規(guī)則,對(duì)url進(jìn)行解析對(duì)比判斷是否為廣告,如果是就對(duì)其進(jìn)行攔截。
2.2 onPageFinished過濾:既然PC端能夠通過js實(shí)現(xiàn)廣告過濾,那么Android端同樣也可以實(shí)現(xiàn),即通過webview調(diào)用js腳本即可。
/**
* 注入js代碼,獲取當(dāng)前頁面所有的img
*
* @param view WebView
*/
private void parseHTML(WebView view) {
view.loadUrl("javascript:function getImgslist() {\n" +
" var imgs = document.querySelectorAll(\"body img\");\n" +
"\n" +
" if (imgs && imgs.length <= 0) return \"\";\n" +
" var imgsArr = [].slice\n" +
" .call(imgs)\n" +
" .map(function(el) {\n" +
" return el.src;\n" +
" })\n" +
" .filter(Boolean);\n" +
"\n" +
" return imgsArr;\n" +
"}\n" +
"window.local_obj.showSource(getImgslist());");
}
可在方法onPageFinished 方法中調(diào)用該腳本,即可以實(shí)現(xiàn)相關(guān)功能。
總結(jié)
以上為廣告過濾在Android中使用的幾種方案,簡單的概括為:在應(yīng)用發(fā)起請(qǐng)求或者收請(qǐng)求去按照規(guī)則過濾相關(guān)url。當(dāng)然廣告過濾的方法遠(yuǎn)不止這幾種,如果有其他方式歡迎交流討論,但規(guī)則始終逃不過按照規(guī)則過濾url。
一下為AdBlockplus 維護(hù)的幾個(gè)過濾表(過濾強(qiáng)度依次減弱):
https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt
https://easylist-downloads.adblockplus.org/easylistchina.txt
https://adfiltering-rules.googlecode.com/svn/trunk/lastest/rules_for_ABP.txt