Flutter InAppWebView点击Facebook视频跳转自定义页面失败问题
解决Flutter InAppWebView点击Facebook视频无法跳转至Material组件的问题
问题描述
在Flutter的InAppWebView中访问Facebook时,点击视频希望跳转到自定义的Material组件,但当前代码触发了Facebook的默认导航,未实现预期效果。原代码如下:
import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { InAppWebViewController? webViewController; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('InAppWebView Button Click Example'), ), body: InAppWebView( initialUrlRequest: URLRequest(url: Uri.parse('https://www.facebook.com')), onWebViewCreated: (controller) { webViewController = controller; }, onLoadStop: (controller, url) { // Inject JavaScript to listen for button clicks controller.evaluateJavascript(source: """ document.querySelector('button').addEventListener('click', function() { window.flutter_inappwebview.callHandler('buttonClicked'); }); """); }, onConsoleMessage: (controller, consoleMessage) { print("Console Message: ${consoleMessage.message}"); }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, ), ), shouldOverrideUrlLoading: (controller, navigationAction) async { final url = navigationAction.request.url.toString(); if (url.startsWith("https://m.facebook.com/watch/")) { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return const Material(); })); return NavigationActionPolicy.CANCEL; } print("URL: $url"); return NavigationActionPolicy.ALLOW; }, ), ); } }
问题原因
- URL匹配范围过窄:Facebook视频跳转的URL可能是
www.facebook.com/watch/而非仅m.facebook.com/watch/,甚至可能包含额外参数或重定向路径。 - 未处理window.open跳转:部分视频链接会通过
window.open打开新窗口,原代码未监听该事件。 - JS监听目标错误:Facebook的视频触发元素并非普通
<button>,而是自定义DOM元素,原JS代码无法捕获点击事件。
解决方案
1. 扩展URL匹配规则
将URL匹配改为检查是否包含facebook.com/watch/,覆盖移动端和桌面端的URL格式。
2. 监听onCreateWindow事件
处理通过window.open打开视频的情况,拦截并跳转至自定义组件。
3. 修正JS监听目标
针对Facebook视频的实际DOM元素注入点击监听(比如包含watch类或属性的元素)。
修改后的代码
import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { InAppWebViewController? webViewController; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('InAppWebView Facebook Video Redirect'), ), body: InAppWebView( initialUrlRequest: URLRequest(url: Uri.parse('https://www.facebook.com')), onWebViewCreated: (controller) { webViewController = controller; }, onLoadStop: (controller, url) async { // 注入JS监听视频元素点击,适配Facebook的DOM结构 await controller.evaluateJavascript(source: """ // 监听所有包含watch相关的元素点击 document.addEventListener('click', function(e) { let target = e.target; // 向上遍历DOM,找到包含视频跳转属性的元素 while (target && target.tagName !== 'BODY') { if (target.href && target.href.includes('facebook.com/watch/')) { e.preventDefault(); // 阻止默认跳转 window.flutter_inappwebview.callHandler('videoClicked', target.href); break; } target = target.parentNode; } }); """); }, // 注册JS回调处理视频点击 onWebMessageReceived: (controller, message) { if (message.message == 'videoClicked') { final videoUrl = message.args?.first.toString(); if (videoUrl != null) { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return const Material( child: Center(child: Text('自定义视频页面')), ); })); } } }, initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, javaScriptEnabled: true, javaScriptCanOpenWindowsAutomatically: true, ), ), shouldOverrideUrlLoading: (controller, navigationAction) async { final url = navigationAction.request.url.toString(); // 匹配所有包含facebook.com/watch/的URL if (url.contains('facebook.com/watch/')) { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return const Material( child: Center(child: Text('自定义视频页面')), ); })); return NavigationActionPolicy.CANCEL; } return NavigationActionPolicy.ALLOW; }, // 处理window.open的跳转请求 onCreateWindow: (controller, createWindowRequest) async { final url = createWindowRequest.request.url.toString(); if (url.contains('facebook.com/watch/')) { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return const Material( child: Center(child: Text('自定义视频页面')), ); })); return false; // 不创建新的WebView窗口 } return true; }, ), ); } }
关键修改点说明
- JS事件监听:通过全局点击事件+DOM遍历,精准捕获视频跳转链接,阻止默认行为后通过
callHandler通知Flutter。 - URL匹配优化:使用
contains替代startsWith,覆盖更多视频URL格式。 - window.open处理:通过
onCreateWindow拦截新窗口请求,直接跳转至自定义组件。 - 增强WebView配置:启用
javaScriptEnabled和javaScriptCanOpenWindowsAutomatically确保JS交互正常。
内容的提问来源于stack exchange,提问作者beewares
相关产品推荐
相关产品推荐

