WebViewの広告を消したい
javascriptをオフにすれば大抵の広告は消えるけど、javascriptが使えないと何かと不便なので、adblockを実装したときのメモです。英語ではそれなりに資料が合ったのですが、日本語のページが見つからなかったので。
参考
このページを追えば実装できます
https://www.hidroh.com/2016/05/19/hacking-up-ad-blocker-android/
広告のホスト一覧
https://sites.google.com/site/hosts2ch/
↑無くなっていたので↓を使わせていただくのが良さそうです。
https://qiita.com/AKKYM/items/9772884e925c0647adb7
だいたいの流れ
WebViewClient.shouldInterceptRequest()をオーバーライドして、ページ内からのリクエストURLが広告配信ホストかどうかを判定する。
もし広告の場合は空のレスポンスを返す。
以上。
実装
広告ホスト一覧を扱いやすいように成形する
https://qiita.com/AKKYM/items/9772884e925c0647adb7 で、広告を配信しているホストの一覧がダウンロードできます。(めっちゃ便利..!!)
ダウンロードするとこんな感じになってると思うので、扱いやすいように成形します。
# hosts2ch - Japanese mobile ad servers hosts file.
# This file is public domain, of course.
#
# file size: 34 kB
# entries: 1279
#
# ---------- last updated: 2019-01-16 ----------
127.0.0.1 100234.advision-adnw.jp
127.0.0.1 100291.adnico.jp
127.0.0.1 100602.advision-adnw.jp
127.0.0.1 100651.advision-adnw.jp
127.0.0.1 100800.advision-adnw.jp
127.0.0.1 101623.sprout-ad.com
127.0.0.1 107008.speead.jp
127.0.0.1 150601.fc2rs.com
127.0.0.1 1tmg.info
127.0.0.1 2.chmato.me
・
・
・
これのコメント行とIPアドレスの列を削除してホストだけにし、ファイル名をhosts.txtにします。
こんな感じ↓
100234.advision-adnw.jp
100291.adnico.jp
100602.advision-adnw.jp
100651.advision-adnw.jp
100800.advision-adnw.jp
101623.sprout-ad.com
107008.speead.jp
150601.fc2rs.com
1tmg.info
2.chmato.me
・
・
・
hosts.txtをプロジェクトファイルに追加する
assetsフォルダに追加します。もしassetsフォルダがない場合は作ってください。
AdBlockを実装する
public class AdBlocker {
private static final String AD_HOSTS_FILE = "hosts.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);
BufferedSource buffer = Okio.buffer(Okio.source(stream));
String line;
while ((line = buffer.readUtf8Line()) != null) {
AD_HOSTS.add(line);
}
buffer.close();
stream.close();
}
public static boolean isAd(String url) {
HttpUrl httpUrl = HttpUrl.parse(url);
return isAdHost(httpUrl != null ? httpUrl.host() : "");
}
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)));
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static WebResourceResponse createEmptyResource() {
return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes()));
}
}
WebViewClient.shouldInterceptRequest()を実装する
WebViewClientのshouldInterceptRequest()メソッドをオーバーライドして実装します。
webviewで読み込んだソースからのリクエストは全て一度shouldInterceptRequest()を通る(という認識なのですが合ってるのでしょうか)
private Map<String, Boolean> loadedUrls = new HashMap<>();
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@override99
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
boolean ad;
if (!loadedUrls.containsKey(url)) {
ad = AdBlocker.isAd(url);
loadedUrls.put(url, ad);
} else {
ad = mLoadedUrls.get(url);
}
return ad ? AdBlocker.createEmptyResource() :
super.shouldInterceptRequest(view, url);
}
Applicationを実装する
Applicationを継承したMyApplicationの中でAdBlockerを初期化します。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
AdBlocker.init(this);
}
}
AndroidManifestにも忘れず追加しましょう。
<application
android:name="MyApplication"
....
....
/>
以上
https://www.hidroh.com/2016/05/19/hacking-up-ad-blocker-android/ ほとんどこのページにある通りなので、詳細はこちらを参考にされるといいと思います。