Help us understand the problem. What is going on with this article?

[Android]WebViewにAdblockを実装する

More than 1 year has passed since last update.

WebViewの広告を消したい

javascriptをオフにすれば大抵の広告は消えるけど、javascriptが使えないと何かと不便なので、adblockを実装したときのメモです。英語ではそれなりに資料が合ったのですが、日本語のページが見つからなかったので。

参考

このページを追えば実装できます
https://www.hidroh.com/2016/05/19/hacking-up-ad-blocker-android/

広告のホスト一覧
https://sites.google.com/site/hosts2ch/

だいたいの流れ

WebViewClient.shouldInterceptRequest()をオーバーライドして、ページ内からのリクエストURLが広告配信ホストかどうかを判定する。
もし広告の場合は空のレスポンスを返す。
以上。

実装

広告ホスト一覧を扱いやすいように成形する

https://sites.google.com/site/hosts2ch/ で、広告を配信しているホストの一覧がダウンロードできます。(めっちゃ便利..!!)
ダウンロードするとこんな感じになってると思うので、扱いやすいように成形します。

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/ ほとんどこのページにある通りなので、詳細はこちらを参考にされるといいと思います。

_tacptac
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away