Flutter WebView页面导航限制配置及onNavigationRequest失效问题
Flutter WebView 拦截所有URL跳转并返回应用的解决方案
问题核心
你当前使用的onNavigationRequest仅能拦截WebView的顶级导航请求(比如用户直接点击页面链接的跳转),但对于页面内JavaScript触发的跳转(如window.location.href、window.open)、iframe内部跳转等场景,该回调不会被触发,导致无法捕获所有URL。同时现有逻辑中部分拦截操作未返回NavigationDecision.prevent,会导致WebView仍尝试加载受限URL。
具体解决步骤
1. 修复现有onNavigationRequest逻辑
在拦截受限URL后,必须返回NavigationDecision.prevent来阻止WebView加载目标页面,同时完成应用内跳转:
onNavigationRequest: (NavigationRequest request) { if (request.url.startsWith('https://www.youtube.com/')) { return NavigationDecision.prevent; } else if (request.url.endsWith('page5')) { Navigator.pushNamedAndRemoveUntil( context, '/landingpage', (Route<dynamic> route) => false); return NavigationDecision.prevent; // 新增:阻止WebView加载 } else if (request.url.startsWith('https://www.facebook.com/')) { Navigator.pushAndRemoveUntil( context, MaterialPageRoute( builder: (context) => verifyquickbuy(price: int.parse(widget.price))), (Route<dynamic> route) => false); return NavigationDecision.prevent; // 新增:阻止WebView加载 } return NavigationDecision.navigate; },
2. 注入JS脚本捕获所有跳转事件
通过注入自定义JavaScript,监听页面内所有可能的跳转行为(包括JS触发的跳转),再通过JavaScriptChannel将URL传递给Flutter端处理:
// 在WebViewController配置中添加以下代码 ..addJavaScriptChannel( 'UrlInterceptor', onMessageReceived: (JavaScriptMessage message) { final String url = message.message; // 复用之前的拦截逻辑 if (url.startsWith('https://www.youtube.com/')) { // 阻止跳转 } else if (url.endsWith('page5')) { Navigator.pushNamedAndRemoveUntil(context, '/landingpage', (route) => false); } else if (url.startsWith('https://www.facebook.com/')) { Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => verifyquickbuy(price: int.parse(widget.price))), (route) => false, ); } }, ) ..runJavaScript(''' // 监听页面内所有链接点击 document.addEventListener('click', function(e) { let target = e.target; while (target && target.tagName !== 'A') { target = target.parentElement; } if (target && target.href) { UrlInterceptor.postMessage(target.href); } }); // 监听window.location跳转 const originalHref = Object.getOwnPropertyDescriptor(window.location, 'href'); Object.defineProperty(window.location, 'href', { set: function(value) { UrlInterceptor.postMessage(value); originalHref.set.call(this, value); }, get: function() { return originalHref.get.call(this); } }); // 监听window.open跳转 const originalOpen = window.open; window.open = function(url) { UrlInterceptor.postMessage(url); return originalOpen.apply(this, arguments); }; ''');
3. 避免重复创建WebViewController
检查getcontroller()方法,确保它不会在每次页面构建时重新创建WebViewController——控制器应仅在initState中初始化一次,否则之前配置的导航代理和JS通道会被覆盖失效。
内容的提问来源于stack exchange,提问作者CINO
相关产品推荐
相关产品推荐

