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

Flutter iOS端Stripe支付Sheet如何设置barrierDismissible: false?

解决Flutter iOS端Stripe支付Sheet点击外部关闭的问题

Stripe Flutter SDK的presentPaymentSheet()确实没有直接提供barrierDismissible这类参数,但可以通过两种方式处理iOS端的这个需求:

方法一:拦截并忽略外部点击引发的取消错误

用户点击支付Sheet外部关闭时,会触发StripeException,我们可以在异常捕获逻辑里区分错误类型,只响应用户主动点击Sheet内取消按钮的操作,忽略外部点击的情况。

修改你的displayPaymentSheet()方法:

displayPaymentSheet() async {
  try {
    await Stripe.instance.presentPaymentSheet().then((value) async {
      // 这里处理支付成功后的逻辑
    });
  } on StripeException catch (e) {
    // 只在用户主动点击Sheet内的取消按钮时弹出提示
    if (e.error.code == 'Canceled') {
      showDialog(
        context: context,
        builder: (_) => const AlertDialog(
          content: Text("已取消支付"),
        )
      );
    }
    // 外部点击导致的取消错误直接忽略,不做任何提示
  } catch (e) {
    print('支付出错: $e');
  }
}

方法二:修改iOS原生代码彻底禁止外部点击

Stripe的iOS原生SDK支持调整支付Sheet的弹窗样式,设置为全屏模式后就无法点击外部关闭。需要在Flutter项目的iOS端做以下修改:

  1. 打开iOS项目的Runner目录,找到AppDelegate.swift(如果用SwiftUI则是RunnerApp.swift);
  2. 通过自定义MethodChannel扩展原生逻辑,示例如下:

原生Swift代码示例

import UIKit
import Flutter
import Stripe

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    
    // 注册MethodChannel,用于Flutter调用原生支付Sheet展示逻辑
    let channel = FlutterMethodChannel(name: "com.yourcompany/stripe_payment", binaryMessenger: self.window!.rootViewController!.view.window!.binaryMessenger)
    channel.setMethodCallHandler { [weak self] call, result in
      if call.method == "presentPaymentSheet" {
        guard let clientSecret = call.arguments as? String else {
          result.error("INVALID_ARGUMENT", "缺少clientSecret", nil)
          return
        }
        self?.presentStripePaymentSheet(clientSecret: clientSecret, result: result)
      } else {
        result.notImplemented()
      }
    }
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  private func presentStripePaymentSheet(clientSecret: String, result: FlutterResult) {
    let paymentSheet = STPPaymentSheet(paymentIntentClientSecret: clientSecret)
    paymentSheet.present(from: self.window?.rootViewController) { stpResult in
      switch stpResult {
      case .completed:
        result(true)
      case .canceled:
        result(false)
      case .failed(let error):
        result(FlutterError(code: "PAYMENT_FAILED", message: error.localizedDescription, details: nil))
      }
    }
    // 设置弹窗为全屏模式,禁止外部点击关闭
    if let presentedVC = self.window?.rootViewController?.presentedViewController {
      presentedVC.modalPresentationStyle = .fullScreen
    }
  }
}

Flutter端调用代码

替换原来的displayPaymentSheet()方法:

displayPaymentSheet() async {
  const channel = MethodChannel('com.yourcompany/stripe_payment');
  try {
    final result = await channel.invokeMethod('presentPaymentSheet', paymentIntentData!['client_secret']);
    if (result == true) {
      // 支付成功逻辑
    } else if (result == false) {
      // 用户主动取消支付,弹出提示
      showDialog(
        context: context,
        builder: (_) => const AlertDialog(
          content: Text("已取消支付"),
        )
      );
    }
  } on PlatformException catch (e) {
    print('支付出错: ${e.message}');
  }
}

总结

  • 不想碰原生代码的话,优先用方法一,通过过滤错误码避免外部点击带来的报错;
  • 要彻底禁止外部点击,就需要修改iOS原生代码,将支付Sheet设置为全屏弹窗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 11:15:40