如何在Swift的WKWebView中完全屏蔽各类广告?
WKWebView全量屏蔽广告的优化方案
针对使用WKContentRuleListStore结合adaway.json规则仅能拦截部分广告、无法覆盖弹窗/横幅等所有广告形式的问题,以下是几个可行的优化方案:
1. 合并多套广告规则,扩展拦截范围
单一规则库覆盖的广告源有限,建议整合多套成熟的广告拦截规则(比如EasyList、AdGuard的iOS适配规则),将它们转换为WKContentRuleList支持的JSON格式后合并使用:
- 规则转换示例:将域名拦截规则转为WK规范格式
[ { "trigger": { "url-filter": "^https?://.*ad-example\\.com.*" }, "action": { "type": "block" } } ] - 合并时注意去重相同规则,避免冗余。
2. 注入用户脚本拦截动态广告与弹窗
很多广告是通过JS动态加载或弹窗触发的,这类广告无法仅靠URL拦截解决,需要注入脚本主动处理:
示例脚本(拦截弹窗+移除广告元素)
// 拦截各类弹窗 window.open = function() {}; window.alert = function() {}; window.confirm = function() {}; // 页面加载完成后移除静态广告元素 document.addEventListener('DOMContentLoaded', function() { // 覆盖常见广告类/id的选择器,可根据实际场景补充 const adSelectors = ['.ad', '.banner', '#ad-container', '[class*="ad"]', '[id*="ad"]', '[data-ad]']; adSelectors.forEach(selector => { document.querySelectorAll(selector).forEach(el => el.remove()); }); }); // 监听DOM变化,移除动态加载的广告 const adObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { const el = node; // 检查元素是否包含广告相关标识 if (el.className.includes('ad') || el.id.includes('ad') || el.hasAttribute('data-ad')) { el.remove(); } } }); }); }); adObserver.observe(document.body, { childList: true, subtree: true });
在WKWebView中添加脚本
// 加载脚本字符串 let adBlockScript = """ // 上面的JS脚本内容 """ // 创建WKUserScript,设置在文档加载前注入,覆盖所有子框架 let userScript = WKUserScript(source: adBlockScript, injectionTime: .atDocumentStart, forMainFrameOnly: false) // 添加到配置中 let contentController = WKUserContentController() contentController.addUserScript(userScript) // 同时保留原有的ContentRuleList规则 if let contentRuleList = contentRuleList { contentController.add(contentRuleList) } // 初始化WKWebView let config = WKWebViewConfiguration() config.userContentController = contentController let webView = WKWebView(frame: view.bounds, configuration: config)
3. 通过导航代理拦截可疑请求
实现WKNavigationDelegate的请求拦截方法,作为规则拦截的补充,手动拦截未被规则覆盖的广告请求:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { guard let url = navigationAction.request.url, let host = url.host else { decisionHandler(.allow) return } // 自定义广告域名/关键词列表,可根据需求扩展 let blockedDomains = ["adnetwork.com", "tracker-service.net", "banner-provider.com"] let blockedPathKeywords = ["ad", "track", "banner", "promo"] // 拦截匹配的域名或路径 if blockedDomains.contains(host) || blockedPathKeywords.contains(where: url.path.lowercased().contains) { decisionHandler(.cancel) return } decisionHandler(.allow) }
4. 定期更新规则库
广告源会持续新增和变化,建议在APP启动时检查规则版本,从本地资源或后台服务获取最新的规则文件,更新到WKContentRuleListStore中,确保拦截规则始终覆盖最新的广告源。
内容的提问来源于stack exchange,提问作者Yogesh Patel
相关产品推荐
相关产品推荐

