在探索其他选项后,我了解到解决在 Flutter Web 应用程序中接受卡付款的用例问题的唯一方法是通过 Flutter_stripe 和 flutter_stripe_web 包。
我实现了这两个功能,以发现 Web 不支持 Stripe.PaymentSheet。 :( 从 Stripe 支持中,我了解到我应该使用 Stripe.PaymentElement 而不是 PaymentSheet,而其余代码保持不变,即 PaymentIntent 和后端函数等
我尝试过以下文档(尽管在 Flutter/dart 的上下文中有点不清楚),但我只是无法填充缺失的块。
你们能看一下并让我知道我做错了什么或者什么是实现 PaymentElement 而不是 Sheets 的正确方法吗
提前致谢。
我的付款文件
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:http/http.dart' as http;
class StripePayments {
Future<void> initPaymentSheet(context,
{required String email, required int amount}) async {
try {
// 1. create payment intent on the server
final response = await http.post(
Uri.parse(
'https://mycloudFunctionUrl/stripePaymentIntentRequest'),
body: {
'email': email,
'amount': amount.toString(),
});
if (response.statusCode != 200) {
throw Exception('Failed to create payment intent: ${response.body}');
}
final jsonResponse = jsonDecode(response.body);
log('Payment intent response: $jsonResponse');
// 2. Verify the keys and data
if (jsonResponse['paymentIntent'] == null ||
jsonResponse['customer'] == null ||
jsonResponse['ephemeralKey'] == null) {
throw Exception('Invalid response from server: $jsonResponse');
}
// 3. initialize the payment sheet
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: jsonResponse['paymentIntent'],
merchantDisplayName: 'Cruise-App',
customerId: jsonResponse['customer'],
customerEphemeralKeySecret: jsonResponse['ephemeralKey'],
style: ThemeMode.light,
),
);
// 4. Present the payment sheet
await Stripe.instance.presentPaymentSheet();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment completed!')),
);
} catch (e) {
if (e is StripeException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error from Stripe: ${e.error.localizedMessage}'),
),
);
} else if (e is StripeConfigException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Stripe configuration error: ${e.message}'),
),
);
} else {
print(e.toString());
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}
}
}
这就是我的后端/云功能的样子
const functions = require("firebase-functions");
const cors = require("cors")({ origin: true });
const stripe = require("stripe")("sk_test_my_secret_key");
exports.stripePaymentIntentRequest = functions.region("europe-west3").https.onRequest((req, res) => {
cors(req, res, async () => {
try {
let customerId;
// Gets the customer whose email id matches the one sent by the client
const customerList = await stripe.customers.list({
email: req.body.email,
limit: 1
});
// Checks if the customer exists, if not creates a new customer
if (customerList.data.length !== 0) {
customerId = customerList.data[0].id;
} else {
const customer = await stripe.customers.create({
email: req.body.email
});
customerId = customer.id; // Changed customer.data.id to customer.id
}
// Creates a temporary secret key linked with the customer
const ephemeralKey = await stripe.ephemeralKeys.create(
{ customer: customerId },
{ apiVersion: '2020-08-27' }
);
// Creates a new payment intent with amount passed in from the client
const paymentIntent = await stripe.paymentIntents.create({
amount: parseInt(req.body.amount),
currency: 'nok',
customer: customerId,
});
res.status(200).send({
paymentIntent: paymentIntent.client_secret,
ephemeralKey: ephemeralKey.secret,
customer: customerId,
success: true,
});
} catch (error) {
res.status(404).send({ success: false, error: error.message });
}
});
});
这是 Stripe 团队向我推荐的文档,但他们的支持人员在 Discord 上表示,“我们不知道 dart 或 flutter。不确定已经做过的人是如何做到这一点的”
请推荐!再次感谢您
您可以直接使用PaymentElement小部件。我对此了解不多,但这可能会帮助您入门。
var paymentIntentResult = await createPaymentIntent('100','JYP');
var paymentIntentSecret = paymentIntentResult['client_secret'];
PaymentElement(
autofocus: true,
enablePostalCode: true,
onCardChanged: (_) {},
clientSecret: paymentIntentSecret ?? '',
)
createPaymentIntent(String amount, String currency) async {
try {
//Request body
Map<String, dynamic> body = {
'amount': calculateAmount(amount),
'currency': currency,
};
//Make post request to Stripe
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
headers: {
'Authorization':
'Bearer [your_key]',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body,
);
return json.decode(response.body);
} catch (err) {
throw Exception(err.toString());
}
并用它来拨打电话
OutlinedButton(
onPressed: () async {
try {
await WebStripe.instance
.confirmPaymentElement(ConfirmPaymentElementOptions(
redirect: PaymentConfirmationRedirect.ifRequired,
confirmParams: ConfirmPaymentParams(return_url: ''),
));
} on Exception catch (e) {
print(e.toString());
}
},
child: Text('Go'));
完整情况的简要说明
class StripeTestScreen extends StatefulWidget {
const StripeTestScreen({super.key});
@override
State<StripeTestScreen> createState() => _StripeTestScreenState();
}
class _StripeTestScreenState extends State<StripeTestScreen> {
final controller = CardFormEditController();
String? paymentIntentSecret;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
if (paymentIntentSecret != null)
PaymentElement(
autofocus: true,
enablePostalCode: true,
onCardChanged: (_) {},
clientSecret: paymentIntentSecret ?? '',
),
ElevatedButton(
onPressed: makePayment,
child: const Text('Get Product'),
),
OutlinedButton(
onPressed: () async {
try {
var paymentIntent = await WebStripe.instance.confirmPaymentElement(const ConfirmPaymentElementOptions(
redirect: PaymentConfirmationRedirect.ifRequired,
confirmParams: ConfirmPaymentParams(return_url: ''),
));
log(paymentIntent.toString());
} on Exception catch (e) {
print(e.toString());
}
},
child: Text('Go')),
],
),
);
}
Future<void> makePayment() async {
try {
paymentIntentSecret = await createPaymentIntent('499', 'USD');
setState(() {});
} catch (err) {
throw Exception(err);
}
}
createPaymentIntent(String amount, String currency) async {
try {
Map<String, dynamic> body = {
'amount': amount,
'currency': currency,
};
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
headers: {
'Authorization':
'Bearer <your secret key>',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body,
);
log('LOG: ${response.body}');
return json.decode(response.body)?['client_secret'];
} catch (err) {
log("LOG ERR createPaymentIntent: ${err.toString()}");
throw Exception(err.toString());
}
}
}