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

如何在Flutter WebApp中嵌入WebView并解析网页URI?

解决Flutter Web内嵌VivaWallet支付页并处理回调的方案

方案1:使用官方webview_flutter包(推荐)

这是Flutter官方支持的WebView组件,适配Web平台,能直接内嵌支付页并监听URL变化,兼容性拉满。

  1. 先在pubspec.yaml添加依赖:
dependencies:
  webview_flutter: ^4.4.0

执行flutter pub get完成安装。

  1. 实现内嵌WebView并监听URL回调:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class VivaPaymentWebView extends StatefulWidget {
  final String orderCode;
  const VivaPaymentWebView({super.key, required this.orderCode});

  @override
  State<VivaPaymentWebView> createState() => _VivaPaymentWebViewState();
}

class _VivaPaymentWebViewState extends State<VivaPaymentWebView> {
  late WebViewController _controller;

  @override
  void initState() {
    super.initState();
    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..loadRequest(Uri.parse('https://demo.vivapayments.com/web2?ref=${widget.orderCode}&lang=fr-BE'))
      ..setNavigationDelegate(
        NavigationDelegate(
          onNavigationRequest: (NavigationRequest request) {
            // 拦截支付完成后的回调URL,这里假设你的回调URL带payment-result标识
            if (request.url.contains('payment-result')) {
              // 解析URL里的支付参数
              final uri = Uri.parse(request.url);
              final status = uri.queryParameters['status'];
              final orderId = uri.queryParameters['orderId'];
              // 把结果存入数据库,替换成你的实际存储逻辑
              _saveToDatabase(status, orderId);
              // 关闭支付页面返回应用
              Navigator.pop(context);
              return NavigationDecision.prevent;
            }
            return NavigationDecision.navigate;
          },
        ),
      );
  }

  void _saveToDatabase(String? status, String? orderId) {
    // 示例:打印结果,实际替换为数据库插入/更新逻辑
    print('支付状态:$status,关联订单ID:$orderId');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('完成支付')),
      body: WebViewWidget(controller: _controller),
    );
  }
}

使用时直接导航到这个页面:

Navigator.push(context, MaterialPageRoute(
  builder: (context) => VivaPaymentWebView(orderCode: '你的订单编号'),
));

方案2:用dart:html内嵌IFrame(无第三方包)

如果不想依赖第三方包,可直接用原生HTML的IFrame嵌入Flutter Widget,同样能实现需求(注意跨域限制)。

import 'dart:html' as html;
import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

class VivaPaymentIFrame extends StatefulWidget {
  final String orderCode;
  const VivaPaymentIFrame({super.key, required this.orderCode});

  @override
  State<VivaPaymentIFrame> createState() => _VivaPaymentIFrameState();
}

class _VivaPaymentIFrameState extends State<VivaPaymentIFrame> {
  late html.IFrameElement _iframe;
  late String _viewId;

  @override
  void initState() {
    super.initState();
    _viewId = 'viva-payment-${DateTime.now().millisecondsSinceEpoch}';
    _iframe = html.IFrameElement()
      ..src = 'https://demo.vivapayments.com/web2?ref=${widget.orderCode}&lang=fr-BE'
      ..style.border = 'none'
      ..width = '100%'
      ..height = '100%';

    // 监听URL变化(部分浏览器可能因跨域限制无法读取IFrame URL,优先用方案1)
    html.window.setInterval(() {
      try {
        final url = _iframe.src;
        if (url.contains('payment-result')) {
          final uri = Uri.parse(url);
          final status = uri.queryParameters['status'];
          final orderId = uri.queryParameters['orderId'];
          _saveToDatabase(status, orderId);
          Navigator.pop(context);
        }
      } catch (e) {
        // 跨域读取失败,建议切换方案1或在VivaWallet后台配置postMessage回调
      }
    }, 1000);

    // 注册IFrame到Flutter Web视图
    registerViewFactory(
      _viewId,
      (int viewId) => _iframe,
    );
  }

  void _saveToDatabase(String? status, String? orderId) {
    // 替换为你的数据库存储逻辑
    print('支付状态:$status,关联订单ID:$orderId');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('完成支付')),
      body: HtmlElementView(viewType: _viewId),
    );
  }

  @override
  void dispose() {
    _iframe.remove();
    super.dispose();
  }
}

关键注意事项

  • 必须在VivaWallet后台配置支付完成回调URL,比如设置为你的Flutter Web应用的路由(如https://yourapp.com/#/payment-result),这样支付完成后会自动跳转,方便拦截解析。
  • 你之前用的HTMLWidget是用来渲染静态HTML内容的,根本不能加载外部网页,所以完全无效,别再用了。
  • 跨域问题:IFrame方案可能因浏览器跨域限制无法读取URL,这种情况下优先用webview_flutter方案,兼容性更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:45:34