Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android block ads in webview

I want to implement a mechanism in a custom webview client (without JavaScript injection) that can block ads. Is a way I can catch ads and replace them with other ads from a trusted source? Thanks

like image 389
Stefan Avatar asked Jul 03 '14 07:07

Stefan


3 Answers

In your custom WebViewClient, you can override the function shouldInterceptRequest(WebView, WebResourceRequest).

From Android docs:

Notify the host application of a resource request and allow the application to return the data.

So the general idea is to check if the request is coming from an ad URL (plenty of black list filters out there), then return a "fake" resource that isn't the ad.

For a more in depth explanation plus an example, I recommend checking out this blog post.

like image 128
Bill Avatar answered Nov 08 '22 21:11

Bill


I made a custom WebViewClient like:

public class MyWebViewClient extends WebViewClient {

    @Override
    public void onPageFinished(WebView view, String url) { }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.endsWith(".mp4")) {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.parse(url), "video/*");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            view.getContext().startActivity(intent);
            return true;
        } else if (url.startsWith("tel:") || url.startsWith("sms:") || url.startsWith("smsto:")
                || url.startsWith("mms:") || url.startsWith("mmsto:")) {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            view.getContext().startActivity(intent);
            return true;
        } else {
            return super.shouldOverrideUrlLoading(view, url);
        }
    }

    private Map<String, Boolean> loadedUrls = new HashMap<>();

    @SuppressWarnings("deprecation")
    @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);
    }
}

And created an AdBlocker class like:

public class AdBlocker {
private static final Set<String> AD_HOSTS = new HashSet<>();

public static boolean isAd(String url) {
    try {
        return isAdHost(getHost(url));
    } catch (MalformedURLException e) {
        Log.e("Devangi..", 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 WebResourceResponse createEmptyResource() {
    return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes()));
}

public static String getHost(String url) throws MalformedURLException {
    return new URL(url).getHost();
}

}

And use this WebViewClient in your oncreate like:

 webview.setWebViewClient(new MyWebViewClient());
like image 22
Devangi Avatar answered Nov 08 '22 21:11

Devangi


To implement this, you have two options:

  1. Use Javascript injected code to do this (which you explicitely said, don't want)
  2. In WebView, instead of "http://example.com" load "http://myproxy.com?t=http://example.com" (properly escaped, of course) and setup "myproxy.com" to be a proxy which will fetch the upstream page (given in "t" query parameter, or in any other way) and replace ads with the trusted ones before sending response to the client. This will be pretty complex, though, because ads can be in many forms, they're usually Javascript injected themselves and you'd probably need to rewrite a lot of URL's in the fetched HTML, CSS and JS files etc.
like image 36
kamituel Avatar answered Nov 08 '22 22:11

kamituel