You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
        },
      ),
    );
  }
}

问题原因

  1. URL匹配范围过窄:Facebook视频跳转的URL可能是www.facebook.com/watch/而非仅m.facebook.com/watch/,甚至可能包含额外参数或重定向路径。
  2. 未处理window.open跳转:部分视频链接会通过window.open打开新窗口,原代码未监听该事件。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:40:40