Flutter:替换url_launcher为WebView实现内嵌支付网关
解决方案:Flutter内用WebView打开支付页面
1. 是否需要同时保留两个插件?
不需要。如果你的应用只有支付场景用到外部链接跳转,替换成WebView后就可以移除url_launcher依赖;如果其他功能还需要用到url_launcher,可以保留,两者不会冲突,但支付流程不再依赖它。
2. 具体实现步骤
步骤1:添加WebView插件依赖
在pubspec.yaml中添加webview_flutter(当前主流的Flutter WebView插件):
dependencies: flutter: sdk: flutter webview_flutter: ^4.4.0 # 替换为最新版本号
执行flutter pub get完成依赖安装。
步骤2:创建WebView支付页面组件
新建PaymentWebViewPage.dart文件,专门承载支付网关页面:
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class PaymentWebViewPage extends StatefulWidget { final String paymentUrl; final Function() onPaymentSuccess; final Function()? onPaymentFailed; const PaymentWebViewPage({ super.key, required this.paymentUrl, required this.onPaymentSuccess, this.onPaymentFailed, }); @override State<PaymentWebViewPage> createState() => _PaymentWebViewPageState(); } class _PaymentWebViewPageState extends State<PaymentWebViewPage> { late final WebViewController controller; @override void initState() { super.initState(); controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) // 支付页面普遍需要JS支持 ..loadRequest(Uri.parse(widget.paymentUrl)) ..setNavigationDelegate( NavigationDelegate( onNavigationRequest: (NavigationRequest request) { // 根据支付网关的回调URL判断支付状态 // 示例:假设支付成功后网关会跳转到包含"payment_success"的地址 if (request.url.contains('payment_success')) { widget.onPaymentSuccess(); Navigator.pop(context); return NavigationDecision.prevent; } // 处理支付失败场景 if (request.url.contains('payment_failed')) { widget.onPaymentFailed?.call(); Navigator.pop(context); return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('支付页面'), leading: IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context), ), ), body: WebViewWidget(controller: controller), ); } }
步骤3:修改原支付逻辑代码
把原来调用launchUrl的部分,替换为跳转到WebView页面:
if (selectedPaymentMethod == 'Pay Now' && _formKey.currentState!.validate()) { () async { final ozowApiRes = await OzowApiProvider().createPaymentRequest( 'R${(cart.totalAmount + cart.serviceFee + value * cart.newCylinderPrice).toStringAsFixed(0)}', userData?['username'], userData?['phoneNumber'], userData?['email'], ); // 替换原launchUrl逻辑,打开内部WebView Navigator.push( context, MaterialPageRoute( builder: (context) => PaymentWebViewPage( paymentUrl: ozowApiRes.data, onPaymentSuccess: () { // 支付成功后的业务逻辑:更新订单状态、提示用户等 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('支付成功!')), ); // 比如跳转回订单列表或首页 }, onPaymentFailed: () { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('支付失败,请重试')), ); }, ), ), ); }(); }
3. 关键注意事项
- 回调URL配置:提前确认支付网关的成功/失败回调地址,确保WebView的
NavigationDelegate能正确识别这些地址,及时触发后续逻辑。 - 权限配置:iOS端如果支付URL是HTTP协议,需要在
Info.plist中添加NSAppTransportSecurity配置允许非HTTPS请求;HTTPS则无需额外操作。 - 错误处理:可以在WebView中添加
onPageFinished或onWebResourceError监听,处理页面加载失败的情况。
内容的提问来源于stack exchange,提问作者supremo
相关产品推荐
相关产品推荐

