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

如何在Flutter Web中通过Stripe实现用户自定义金额的动态支付

解决Flutter Web中Stripe自定义金额结账问题

问题背景

已在Stripe仪表板创建默认价格$888的产品,通过Firebase Cloud Functions和Stripe扩展将产品数据同步到Firestore。目前点击「Add amount」按钮创建结账会话后,跳转至Stripe结账页面显示固定金额$888,需要改为让用户先在Flutter Web的TextField输入自定义金额,再以此金额完成支付。

核心思路

原来的结账会话直接使用产品的默认priceId生成固定金额订单,要实现自定义金额,需在创建结账会话时动态指定金额,而非依赖固定priceId。推荐通过Firebase Cloud Functions后端处理(避免客户端篡改金额),结合用户输入的金额生成对应结账会话。

实现步骤

1. Flutter端添加金额输入框

先在界面中添加用于收集用户自定义金额的TextField:

final TextEditingController _customAmountController = TextEditingController();

// 界面组件
TextField(
  controller: _customAmountController,
  keyboardType: TextInputType.numberWithOptions(decimal: true),
  decoration: const InputDecoration(
    labelText: "输入支付金额(美元)",
    hintText: "例如:100.00",
  ),
);

2. 修改按钮点击事件逻辑

原按钮事件调用Cloud Function传递固定priceId,现在改为传递用户输入的金额(转换为美分)和产品ID:

void _handleCustomPayment() async {
  // 验证输入合法性
  final amountInput = _customAmountController.text.trim();
  if (amountInput.isEmpty) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text("请输入有效的支付金额")),
    );
    return;
  }

  final double amount;
  try {
    amount = double.parse(amountInput);
  } catch (_) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text("金额格式错误")),
    );
    return;
  }

  if (amount <= 0) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text("金额必须大于0")),
    );
    return;
  }

  // 转换为Stripe要求的最小单位(美分)
  final int amountInCents = (amount * 100).toInt();

  // 从Firestore获取产品ID
  final productDoc = await FirebaseFirestore.instance
      .collection('products')
      .doc('你的产品文档ID')
      .get();
  final productId = productDoc.data()?['id'] as String;

  // 调用自定义的Cloud Function生成结账会话
  try {
    final sessionResult = await FirebaseFunctions.instance
        .httpsCallable('createCustomAmountCheckout')
        .call({
      'productId': productId,
      'amountInCents': amountInCents,
      'successUrl': 'https://你的域名.com/success',
      'cancelUrl': 'https://你的域名.com/cancel',
    });

    // 跳转至Stripe结账页面
    await Stripe.instance.redirectToCheckout(
      url: sessionResult.data['checkoutUrl'] as String,
    );
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text("创建会话失败:${e.toString()}")),
    );
  }
}

3. 编写对应的Firebase Cloud Function

创建一个新的Callable函数,用于生成带自定义金额的结账会话:

const functions = require("firebase-functions");
const stripe = require("stripe")(functions.config().stripe.secret);

exports.createCustomAmountCheckout = functions.https.onCall(async (data, context) => {
  const { productId, amountInCents, successUrl, cancelUrl } = data;

  // 生成Stripe结账会话
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ["card"],
    line_items: [
      {
        price_data: {
          currency: "usd",
          product: productId,
          unit_amount: amountInCents, // 使用用户输入的金额(美分)
        },
        quantity: 1,
      },
    ],
    mode: "payment",
    success_url: successUrl,
    cancel_url: cancelUrl,
  });

  return { checkoutUrl: session.url };
});

你的解决方案验证

你提到通过添加line_items字段解决问题,本质就是绕开固定priceId,改用price_data动态生成对应金额的订单,这个思路是完全正确的。需要注意的是一定要将金额转换为对应货币的最小单位(比如美元转美分),否则Stripe API会报错。

内容的提问来源于stack exchange,提问作者ᴅ ᴇ ʙ ᴊ ᴇᴇ ᴛ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:55:43