Android WebView仅加载指定网站页面的URL拦截问题
解决Android WebView拦截外部链接失效的问题
嘿,我之前做WebView封装的时候也踩过这个一模一样的坑!明明重写了shouldOverrideUrlLoading,但广告和外链还是能跳出来,后来才发现是几个容易忽略的细节没处理好,给你梳理一下解决方案:
一、先排查核心问题:你可能只重写了单一版本的shouldOverrideUrlLoading
Android在API 24之后新增了带WebResourceRequest参数的shouldOverrideUrlLoading方法,如果你只重写了旧版本(接收String类型url的),那在Android 7.0+的设备上,新的跳转请求会走新版本的默认实现,导致你的拦截逻辑完全没生效!
必须同时重写两个版本的方法,把判断逻辑抽成公共方法,避免重复代码。
二、优化URL匹配逻辑:别用字符串前缀匹配,用Host判断更靠谱
你之前用前缀判断的方式很容易被绕过,比如广告链接伪装成https://yourdomain.com.evil.com,前缀匹配会误以为是自有链接,但实际Host是evil.com。正确的做法是解析URL的Host,判断是否属于你的域名:
示例代码:统一的URL拦截逻辑
webView.setWebViewClient(new WebViewClient() { // 适配API < 24 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return isExternalUrl(url); } // 适配API >= 24 @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { String url = request.getUrl().toString(); return isExternalUrl(url); } // 核心判断方法:检查URL是否为外部链接 private boolean isExternalUrl(String url) { Uri uri = Uri.parse(url); String allowedHost = "yourdomain.com"; // 替换成你的自有域名 // 处理大小写问题,统一转小写 String actualHost = uri.getHost() != null ? uri.getHost().toLowerCase() : ""; allowedHost = allowedHost.toLowerCase(); // 判断是否为自有域名或子域名(如果需要允许子域名的话) boolean isAllowed = allowedHost.equals(actualHost) || actualHost.endsWith("." + allowedHost); if (!isAllowed) { // 这里可以给用户提示,或者直接拦截 Toast.makeText(getApplicationContext(), "此链接无法在App内打开", Toast.LENGTH_SHORT).show(); return true; // 返回true表示拦截,不加载该链接 } return false; // 返回false表示允许加载 } });
三、处理JavaScript跳转和新窗口请求
有些广告是通过JS跳转或者在新窗口打开的,这时候shouldOverrideUrlLoading可能不会触发,需要额外处理:
1. 拦截新窗口请求
重写WebChromeClient的onCreateWindow方法,阻止新窗口创建:
webView.setWebChromeClient(new WebChromeClient() { @Override public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { // 拦截所有新窗口请求 Toast.makeText(getApplicationContext(), "禁止打开外部窗口", Toast.LENGTH_SHORT).show(); return true; // 返回true表示我们自行处理,不创建新窗口 } });
2. 开启必要的WebSettings配置
确保WebView的JS支持开启(如果你的网站需要JS的话),同时禁用多窗口支持:
WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setSupportMultipleWindows(false); // 配合上面的新窗口拦截
四、额外防护:页面加载前再次校验
为了防止漏网之鱼,可以在onPageStarted方法里再次校验URL,如果是外部链接就停止加载并跳转到自有首页:
@Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); if (isExternalUrl(url)) { view.stopLoading(); // 跳转到自有网站首页 view.loadUrl("https://yourdomain.com"); } }
最后总结一下你之前失效的原因
大概率是这两个问题:
- 只重写了一个版本的
shouldOverrideUrlLoading,导致高版本设备上拦截逻辑不生效 - URL前缀匹配的方式有漏洞,被伪装的链接绕过了
按照上面的步骤修改后,应该就能彻底拦截所有外部链接,让WebView只加载你的自有网站内容啦!
内容的提问来源于stack exchange,提问作者ÊnnOâman




