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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 14:40:30