如何用shouldInterceptRequest拦截URL?求Android广告拦截App开发帮助
如何用shouldInterceptRequest拦截WebView中的广告JS请求
嘿,刚好我之前做过类似的WebView广告拦截功能,给你梳理下具体的实现步骤和代码细节,应该能帮你解决问题!
核心原理
shouldInterceptRequest是WebViewClient提供的回调方法,当WebView准备加载任何资源(JS、图片、CSS等)时都会触发这个回调。我们可以在这里对请求的URL进行校验,判断是否属于需要拦截的广告资源,然后返回空响应来阻止加载。
具体实现代码
1. 定义禁止的广告域名列表
首先我们需要维护一个预定义的广告域名集合,用HashSet来存储可以保证高效的查询速度:
import java.util.Arrays; import java.util.HashSet; import java.util.Set; // 预定义需要拦截的广告域名,你可以根据自己的需求添加或修改 private static final Set<String> BLOCKED_AD_DOMAINS = new HashSet<>(Arrays.asList( "ad.example.com", "ads.tracker.net", "cdn.adnetwork.com", "analytics.adcompany.org" ));
2. 自定义WebViewClient并重写拦截方法
我们需要同时兼容低版本(API < 21)和高版本(API 21+)的shouldInterceptRequest方法,确保在不同系统版本上都能正常工作:
import android.annotation.TargetApi; import android.os.Build; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; import java.net.URI; import java.net.URISyntaxException; webView.setWebViewClient(new WebViewClient() { // 兼容Android 5.0以下的版本 @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { if (isBlockableRequest(url)) { // 返回空响应,阻止WebView加载该资源 return new WebResourceResponse(null, null, null); } return super.shouldInterceptRequest(view, url); } // Android 5.0及以上推荐使用这个方法,能获取更详细的请求信息 @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { String url = request.getUrl().toString(); if (isBlockableRequest(url)) { return new WebResourceResponse(null, null, null); } return super.shouldInterceptRequest(view, request); } // 核心判断逻辑:判断当前请求是否需要被拦截 private boolean isBlockableRequest(String url) { // 第一步:先判断是不是JS请求(只拦截.js资源) boolean isJsResource = url.toLowerCase().endsWith(".js"); if (!isJsResource) { return false; } // 第二步:解析URL中的域名,判断是否在禁止列表中 try { URI uri = new URI(url); String domain = uri.getHost(); if (domain == null) { return false; } // 这里可以根据需求调整匹配逻辑,比如拦截子域名的话可以用domain.endsWith(".ad.example.com") return BLOCKED_AD_DOMAINS.contains(domain); } catch (URISyntaxException e) { // URL解析失败,不拦截 e.printStackTrace(); return false; } } });
关键注意事项
- 域名匹配的灵活性:如果需要拦截某个域名的所有子域名(比如
sub.ad.example.com、abc.ad.example.com),可以把判断逻辑改成domain.endsWith(".ad.example.com"),而不是直接匹配完整域名。 - 避免网站异常:有些网站依赖某些JS资源,盲目拦截可能导致页面加载异常。你可以先测试拦截效果,或者返回一个空白的JS文件(比如创建一个空的InputStream传入WebResourceResponse)来替代直接返回null。
- 性能优化:使用
HashSet存储禁止域名,因为它的查询时间复杂度是O(1),比ArrayList的线性查找效率高很多,尤其是当禁止域名数量较多时。 - 动态更新域名:如果需要支持用户自定义拦截域名,建议使用线程安全的集合(比如
ConcurrentHashMap或者CopyOnWriteArraySet),避免在更新域名时出现并发问题。 - 其他资源拦截:如果之后需要拦截图片、CSS等其他广告资源,只需要修改
isBlockableRequest中的判断条件,比如添加url.toLowerCase().endsWith(".png")来拦截图片。
内容的提问来源于stack exchange,提问作者Leonar Aung




