如何在Flutter WebApp中嵌入WebView并解析网页URI?
解决Flutter Web内嵌VivaWallet支付页并处理回调的方案
方案1:使用官方webview_flutter包(推荐)
这是Flutter官方支持的WebView组件,适配Web平台,能直接内嵌支付页并监听URL变化,兼容性拉满。
- 先在
pubspec.yaml添加依赖:
dependencies: webview_flutter: ^4.4.0
执行flutter pub get完成安装。
- 实现内嵌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
相关产品推荐
相关产品推荐

