android WebView實踐總結(四) WebView廣告攔截(AdBlock)
網站的站長為了提高自己的收入往往會選擇在網頁中新增廣告,有一些廣告把內容覆蓋住或者佔據大部分位置,嚴重影響了使用者體驗。
1.思路
攔截我們先要獲取到網頁中所有請求連結,我們在哪裡獲取呢,通常網頁的監聽都是在 WebViewClient
中去實現,通過檢視 WebViewClient
的原始碼發現裡面有個回撥方法 WebResourceResponse shouldInterceptRequest(WebView view, String url)
這個方法中的 url
引數可以獲取到所有的請求連結,我們需要一個規則檔案裡面包含大量廣告 host
,每次獲取 url
判斷 host
規則檔案中是否包含次連結/ js
名稱/規則,對 url
進行解析對比判斷是否為廣告,如果是就對其進行攔截。
2.實現
1.1 在 assets
中建立一個 host
檔案,裡面包含大量廣告域名/規則, host
檔案 demo 裡面有的,也可以從伺服器動態獲取。我這裡為了方便演示就放 assets
裡面了。

LE%MU{9$30D%CA6_UH)H(N4.png
host
檔案按照行數進行讀取新增到臨時儲存容器
Set
集合中,
private static final String AD_HOSTS_FILE = "host.txt"; private static final Set<String> AD_HOSTS = new HashSet<>(); InputStream stream = context.getAssets().open(AD_HOSTS_FILE); InputStreamReader inputStreamReader = new InputStreamReader(stream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String line; while ((line = bufferedReader.readLine()) != null) AD_HOSTS.add(line); bufferedReader.close(); inputStreamReader.close(); stream.close();
1.3 解析url判斷是否為廣告
if (TextUtils.isEmpty(host)) { return false; } int index = host.indexOf("."); return index >= 0 && (AD_HOSTS.contains(host) || index + 1 < host.length() && isAdHost(host.substring(index + 1)));
3.完整程式碼
解析類AdBlocker
public class AdBlocker { private static final String AD_HOSTS_FILE = "host.txt"; private static final Set<String> AD_HOSTS = new HashSet<>(); public static void init(final Context context) { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { try { loadFromAssets(context); } catch (IOException e) { // noop } return null; } }.execute(); } @WorkerThread private static void loadFromAssets(Context context) throws IOException { InputStream stream = context.getAssets().open(AD_HOSTS_FILE); InputStreamReader inputStreamReader = new InputStreamReader(stream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String line; while ((line = bufferedReader.readLine()) != null) AD_HOSTS.add(line); bufferedReader.close(); inputStreamReader.close(); stream.close(); } public static boolean isAd(String url) { try { return isAdHost(getHost(url))||AD_HOSTS.contains(Uri.parse(url).getLastPathSegment()); } catch (MalformedURLException e) { Log.d("AmniX", e.toString()); return false; } } private static boolean isAdHost(String host) { if (TextUtils.isEmpty(host)) { return false; } int index = host.indexOf("."); return index >= 0 && (AD_HOSTS.contains(host) || index + 1 < host.length() && isAdHost(host.substring(index + 1))); } public static String getHost(String url) throws MalformedURLException { return new URL(url).getHost(); } public static WebResourceResponse createEmptyResource() { return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes())); } }
呼叫
//幫助WebView處理各種通知、請求事件 mWebView.setWebViewClient(new WebViewClient() { private Map<String, Boolean> loadedUrls = new HashMap<>(); @Nullable @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { boolean ad; if (!loadedUrls.containsKey(url)) { ad = AdBlocker.isAd(url); loadedUrls.put(url, ad); } else { ad = loadedUrls.get(url); } return ad ? AdBlocker.createEmptyResource() : super.shouldInterceptRequest(view, url); } });
4.效果圖

攔截前.jpg

攔截後.jpg
附上demo連結: https://github.com/Allyns/AllynWebView
5.擴充套件
有時候 host
檔案裡面沒有包含該域名怎麼辦?
我們需要手動標記為廣告,然後把該廣告隱藏掉。
網頁 載入完成
後隱藏廣告圖片可以使用 js注入
的方式動態處理網頁。
使用 js程式碼
獲取此 ur
l的 父元素
,然後隱藏掉父元素就可以實現這個需求
這裡簡單的附上程式碼供參考:
1.隱藏圖片父元素
String js = "javascript: (function () {\n" + "var aList = document.getElementsByTagName(\"img\");\n" + "var parentList = [];\n" + "for (var i = 0; i < aList.length; i++) {\n" + "parentList = parentList.concat([aList[i].parentElement]);\n" + "}\n" + "for (var i = 0; i < aList.length; i++) {\n" + "if (aList[i].getAttribute(\"src\").indexOf(\"" + url + "\") != -1) {\n" + "parentList[i].style.display = \"none\";\n" + "}\n" + "}\n" + "})();"; getWebView().loadUrl(js);
2.隱藏a標籤
String js = "javascript: (function () {\n" + "var aList = document.getElementsByTagName(\"a\");\n" + "var parentList = [];\n" + "for (var i = 0; i < aList.length; i++) {\n" + "parentList = parentList.concat([aList[i].parentElement]);\n" + "}\n" + "for (var i = 0; i < aList.length; i++) {\n" + "if (aList[i].getAttribute(\"href\").indexOf(\"" + url + "\") != -1) {\n" + "parentList[i].style.display = \"none\";\n" + "}\n" + "}\n" + "})();"; LogHelper.i("wessd", js); getWebView().loadUrl(js);
WwebView廣告攔截
還有很大的優化空間,歡迎大家可以給出更好的建議~