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

Flutter集成Razorpay支付网关:能否自定义结账页面UI?

Razorpay Flutter 自定义结账UI实现方案

是的,可以为Razorpay制作自定义结账UI。你当前使用的razorpay.open(options)调用的是Razorpay托管的预构建弹窗,要实现自定义UI需要采用**Custom Checkout(自定义结账)**方案,全程在你的Flutter页面内控制UI与支付流程。

核心实现思路

自定义结账需要走「后端创建订单→前端自定义UI收集支付信息→发起支付→验证支付状态」的流程,核心是不再依赖Razorpay的预构建弹窗,而是通过SDK提供的底层方法完成支付操作。

关键步骤与代码示例

1. 后端创建Razorpay订单(必须步骤)

绝对不能在前端暴露Razorpay密钥,必须通过你的后端调用Razorpay的订单创建API,生成order_id后返回给前端。

2. 自定义支付UI与支付触发逻辑

替换原有的_openCheckout方法,改为先从后端获取订单ID,再通过自定义UI收集支付信息并发起支付:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:razorpay_flutter/razorpay_flutter.dart';

// 从后端获取Razorpay订单ID
Future<String> _fetchRazorpayOrderId(double amount) async {
  final response = await http.post(
    Uri.parse('https://你的后端地址/create-razorpay-order'),
    body: {'amount': (amount * 100).toString()}, // 转成派萨单位
  );
  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    return data['order_id'];
  } else {
    throw Exception('创建订单失败');
  }
}

// 自定义支付触发方法
void _initiateCustomPayment() async {
  var amount = (double.tryParse(_amountController.text) ?? 0);
  if (amount <= 0) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请输入有效的金额')),
    );
    return;
  }

  try {
    // 第一步:获取后端生成的订单ID
    String orderId = await _fetchRazorpayOrderId(amount);
    
    // 第二步:从自定义UI获取用户支付信息(示例为UPI支付)
    String upiVpa = _upiController.text; // 假设你有一个输入UPI ID的控制器
    
    // 构建支付参数
    var paymentParams = {
      'order_id': orderId,
      'payment_method': 'upi',
      'upi': {'vpa': upiVpa},
      'amount': (amount * 100).toInt(),
      'currency': 'INR',
    };

    // 第三步:发起支付
    _razorpay.createPayment(paymentParams);
  } catch (e) {
    debugPrint('支付错误: $e');
  }
}

// 初始化支付回调监听
@override
void initState() {
  super.initState();
  _razorpay = Razorpay();
  _razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
  _razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
  _razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
}

// 支付成功回调
void _handlePaymentSuccess(PaymentSuccessResponse response) {
  // 必须通过后端验证Razorpay的webhook回调,确认支付状态真实有效
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('支付成功,支付ID: ${response.paymentId}')),
  );
}

// 支付失败回调
void _handlePaymentError(PaymentFailureResponse response) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('支付失败: ${response.message}')),
  );
}

// 外部钱包支付回调
void _handleExternalWallet(ExternalWalletResponse response) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('跳转到外部钱包: ${response.walletName}')),
  );
}

重要注意事项

  • 密钥安全:你的现有代码中直接暴露了rzp_live_ILgsfZCZoFIKMb这个生产环境密钥,这会导致严重的安全风险,必须立即移到后端。
  • 支付状态验证:前端的支付成功回调不可信,必须通过Razorpay的webhook通知后端,再由后端告知前端最终支付状态。
  • 支付方式适配:不同支付方式(银行卡、钱包、EMI等)的参数格式不同,需要参考Razorpay官方文档调整paymentParams。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 11:54:59