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

Flutter如何拦截WebView跳转并唤起原生浏览器打开链接

Flutter WebView 外链跳转系统浏览器实现方案

实现思路

  • 拦截WebView所有页面跳转请求,过滤出外部http/https链接
  • 拦截到外链时阻止WebView内部加载,弹出跳转确认提示
  • 用户确认后调用系统能力唤起原生浏览器打开对应链接

具体实现步骤

1. 添加必要依赖

在项目pubspec.yaml文件中添加跳转系统浏览器所需的官方插件,如果你项目已经引入过对应版本可跳过:

dependencies:
  flutter:
    sdk: flutter
  # 你项目已有的webview依赖无需重复添加
  webview_flutter: ^4.4.2
  # 用于唤起系统浏览器
  url_launcher: ^6.2.2

Android端需要在android/app/src/main/AndroidManifest.xml的<manifest>节点下添加包可见性配置,适配Android 11及以上版本:

<queries>
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="https" />
  </intent>
</queries>

2. 完整修改后的代码

直接替换原有隐私政策页代码即可,核心逻辑是给WebView添加导航委托拦截跳转:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:url_launcher/url_launcher.dart';

class PrivacyPolicyPage extends StatefulWidget {
  const PrivacyPolicyPage({super.key});
  static const routeName = '/privacy_policy';
  @override
  State<PrivacyPolicyPage> createState() => _PrivacyPolicyPageState();
}

class _PrivacyPolicyPageState extends State<PrivacyPolicyPage> {
  final _filePath = Assets.assetsPrivacyPolicy;
  late WebViewController _webViewController;

  @override
  void initState() {
    super.initState();
    _webViewController = WebViewController()
      // 开启JS支持
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      // 设置导航委托拦截跳转
      ..setNavigationDelegate(
        NavigationDelegate(
          onNavigationRequest: (request) async {
            final url = request.url;
            // 本地加载的隐私政策是data URI格式,直接放行
            if (url.startsWith('data:')) {
              return NavigationDecision.navigate;
            }
            // 其余外链全部拦截,先弹提示
            final isConfirm = await showDialog<bool>(
              context: context,
              barrierDismissible: false,
              builder: (context) {
                return AlertDialog(
                  title: const Text('跳转提示'),
                  content: const Text('即将离开应用,跳转至系统浏览器打开第三方页面,是否继续?'),
                  actions: [
                    TextButton(
                      onPressed: () => Navigator.pop(context, false),
                      child: const Text('取消'),
                    ),
                    TextButton(
                      onPressed: () => Navigator.pop(context, true),
                      child: const Text('确认'),
                    ),
                  ],
                );
              },
            );
            // 用户确认跳转则唤起系统浏览器
            if (isConfirm == true) {
              final uri = Uri.parse(url);
              if (await canLaunchUrl(uri)) {
                await launchUrl(
                  uri,
                  // 强制使用外部系统浏览器打开
                  mode: LaunchMode.externalApplication,
                );
              }
            }
            // 阻止WebView内部加载外链
            return NavigationDecision.prevent;
          },
        ),
      );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Privacy Policy'),
        centerTitle: true,
      ),
      body: WebViewWidget(
        controller: _webViewController,
      ),
    );
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _loadHtmlFromAssets();
  }

  Future<void> _loadHtmlFromAssets() async {
    final fileHtmlContents = await rootBundle.loadString(_filePath);
    await _webViewController.loadRequest(
      Uri.dataFromString(
        fileHtmlContents,
        mimeType: 'text/html',
        encoding: Encoding.getByName('utf-8'),
      ),
    );
  }
}

注意事项

  • 代码中用WebViewWidget替代了旧版WebView组件,适配webview_flutter4.x版本的官方写法,如果你用的是3.x旧版本,可以把导航委托逻辑放到旧版WebView的navigationDelegate参数里,逻辑完全一致
  • 拦截判断逻辑以data:开头作为本地内容放行规则,如果你后续有其他应用内页面需要在WebView里加载,可以自行扩展白名单判断
  • launchUrl方法必须传入LaunchMode.externalApplication参数,否则可能会在应用内打开自定义标签页,达不到唤起系统浏览器的效果

内容的提问来源于stack exchange,提问作者userName

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:57:49