LoginSignup
9
6

More than 1 year has passed since last update.

[Android]WebViewにAdblockを実装する

Last updated at Posted at 2019-01-22

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 で、広告を配信しているホストの一覧がダウンロードできます。(めっちゃ便利..!!)
ダウンロードするとこんな感じになってると思うので、扱いやすいように成形します。

ja.txt
# 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にします。
こんな感じ↓

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フォルダがない場合は作ってください。

スクリーンショット 2019-01-22 15.57.10.png

AdBlockを実装する

AdBlocker.java
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()を通る(という認識なのですが合ってるのでしょうか)

MyWebViewClient.java
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を初期化します。

MyApplication.java
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        AdBlocker.init(this);
    }
}

AndroidManifestにも忘れず追加しましょう。

AndroidManifest.xml
<application
        android:name="MyApplication"
        ....
        ....
/>

以上

https://www.hidroh.com/2016/05/19/hacking-up-ad-blocker-android/ ほとんどこのページにある通りなので、詳細はこちらを参考にされるといいと思います。

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6