Flutter iOS端如何拦截WebView的所有请求?
解决Flutter WebView跨平台捕获所有HTTP请求的思路
思路一:利用flutter_inappwebview的onLoadResource事件
这个事件在iOS和Android平台都会触发,每次WebView加载资源(包括页面、图片、脚本、XHR、Fetch请求等)时都会回调,能直接获取请求的URL和头信息,完全满足跨平台获取请求数据的需求。
示例代码:
InAppWebView( initialUrlRequest: URLRequest(url: Uri.parse("https://example.com")), onLoadResource: (controller, request) async { // 获取请求URL String requestUrl = request.url.toString(); // 获取请求头 Map<String, String> requestHeaders = request.headers; // 处理获取到的请求信息 print("请求URL: $requestUrl"); print("请求头: $requestHeaders"); }, )
注意:该事件在资源加载完成后触发,若需要在请求发送前拦截,此方法不适用,但仅用于获取请求URL和头信息时完全可行。
思路二:重写JS请求方法实现持续监听
如果需要在请求发送前捕获信息,可以通过重写XMLHttpRequest和Fetch的原型方法,让每次请求都将信息传递给Flutter端。关键是确保重写代码在页面脚本执行前生效,且页面跳转/刷新后依然有效。
实现步骤:
- 创建JS拦截文件(比如
assets/request_interceptor.js):
// 重写XMLHttpRequest (function() { const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { this._requestInfo = { method: method, url: url, headers: {} }; originalOpen.apply(this, arguments); }; const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader; XMLHttpRequest.prototype.setRequestHeader = function(header, value) { if (this._requestInfo) { this._requestInfo.headers[header] = value; } originalSetRequestHeader.apply(this, arguments); }; const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { if (window.flutter_inappwebview) { window.flutter_inappwebview.callHandler('onRequestCaptured', this._requestInfo); } originalSend.apply(this, arguments); }; })(); // 重写Fetch (function() { const originalFetch = window.fetch; window.fetch = function(url, options) { const requestInfo = { method: options?.method || 'GET', url: typeof url === 'string' ? url : url.toString(), headers: options?.headers ? Object.fromEntries(options.headers.entries()) : {} }; if (window.flutter_inappwebview) { window.flutter_inappwebview.callHandler('onRequestCaptured', requestInfo); } return originalFetch.apply(this, arguments); }; })();
- 在Flutter中配置注入并监听回调:
InAppWebView( initialUrlRequest: URLRequest(url: Uri.parse("https://example.com")), initialSettings: InAppWebViewSettings( javaScriptEnabled: true, // 确保JS在页面内容加载前注入执行 injectedJavaScriptBeforeContentLoaded: await rootBundle.loadString('assets/request_interceptor.js'), ), onWebViewCreated: (controller) { // 注册JS调用的Flutter回调 controller.addJavaScriptHandler( handlerName: 'onRequestCaptured', callback: (args) { Map<String, dynamic> requestInfo = args[0]; String url = requestInfo['url']; Map<String, dynamic> headers = requestInfo['headers']; print("捕获到请求:URL=$url,Headers=$headers"); }, ); }, )
该方案能覆盖XMLHttpRequest和Fetch请求,且页面跳转后新页面的请求依然会被捕获。
思路三:自定义原生扩展(复杂场景)
如果上述方法无法满足需求(比如需要拦截WebView原生发起的所有请求),可以针对双平台分别实现原生拦截:
- iOS端:使用
WKNavigationDelegate的webView(_:decidePolicyFor:decisionHandler:)方法,在请求发送前获取URL和头信息,通过MethodChannel传递给Flutter。 - Android端:继续使用
shouldInterceptRequest方法保持原有逻辑。
这种方式需要编写原生代码,但能实现最全面的请求拦截能力。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

