Flutter网站集成Stripe测试模式遇「不支持操作系统」错误求助
解决Flutter Web集成Stripe测试模式的「Unsupported operation: Platform_operating System」错误
问题描述
尝试将Stripe测试账户接入Flutter网站,代码无语法错误但无法正常运行:支付网关不显示,弹出错误提示「Unsupported operation: Platform_operating System」。错误截图如下:

原代码如下:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart' as http; import 'package:flutter/foundation.dart' show kIsWeb; class PaymentPage extends StatefulWidget { @override _PaymentPageState createState() => _PaymentPageState(); } class _PaymentPageState extends State<PaymentPage> { Map<String, dynamic>? paymentIntent; @override void initState() { super.initState(); Stripe.publishableKey = kIsWeb ? "pk_test_your_key_for_web" : "pk_test_your_key_for_mobile"; } Future<void> _startPayment() async { try { // Check if the platform is web if (kIsWeb) { Fluttertoast.showToast( msg: 'Web platform is not supported for payments', ); return; } paymentIntent = await createPaymentIntent('100', 'INR'); await Stripe.instance.initPaymentSheet( paymentSheetParameters: SetupPaymentSheetParameters( billingDetails: BillingDetails( name: 'YOUR NAME', email: 'YOUREMAIL@gmail.com', ), paymentIntentClientSecret: paymentIntent!['client_secret'], ), ); // Display Payment sheet await displayPaymentSheet(); } catch (e) { print(e.toString()); Fluttertoast.showToast(msg: e.toString()); } } Future<void> displayPaymentSheet() async { try { // Display the payment sheet. await Stripe.instance.presentPaymentSheet(); Fluttertoast.showToast(msg: 'Payment successfully completed'); } on Exception catch (e) { if (e is StripeException) { Fluttertoast.showToast( msg: 'Error from Stripe: ${e.error.localizedMessage}', ); } else { Fluttertoast.showToast(msg: 'Unforeseen error: ${e}'); } } } Future<Map<String, dynamic>> createPaymentIntent( String amount, String currency) async { try { Map<String, dynamic> body = { 'amount': calculateAmount(amount), 'currency': currency, }; var response = await http.post( Uri.parse('https://api.stripe.com/v1/payment_intents'), headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: body, ); return json.decode(response.body); } catch (err) { throw Exception(err.toString()); } } String calculateAmount(String amount) { final calculatedAmount = (int.parse(amount)) * 100; return calculatedAmount.toString(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Stripe Payment Example'), ), body: Center( child: ElevatedButton( onPressed: _startPayment, child: Text('Make Payment'), ), ), ); } }
错误原因
- Web端初始化方式错误:直接给
Stripe.publishableKey赋值仅支持移动端,Web端需要调用Stripe.instance.init()完成初始化。 - 支付组件不兼容:Payment Sheet仅支持iOS/Android平台,Web端需使用Stripe Elements组件实现支付。
- API调用不安全且无效:前端直接调用Stripe创建Payment Intent的接口,缺少Secret Key验证会请求失败,同时暴露Secret Key存在严重安全风险。
解决方案
步骤1:修正Stripe初始化逻辑
在initState中针对Web平台单独初始化:
@override void initState() { super.initState(); _initStripe(); } Future<void> _initStripe() async { if (kIsWeb) { await Stripe.instance.init( publishableKey: "pk_test_your_key_for_web", stripeAccountId: null, ); } else { Stripe.publishableKey = "pk_test_your_key_for_mobile"; } }
步骤2:实现Web端专属支付流程
使用Stripe Elements替代Payment Sheet,新增Web端支付方法:
Future<void> _webPayment() async { try { // 调用后端接口创建Payment Intent(必须通过后端处理) final paymentIntent = await _createPaymentIntentThroughBackend('100', 'INR'); final clientSecret = paymentIntent['client_secret']; // 创建Stripe Elements实例与卡片组件 final elements = Stripe.instance.elements.create(); final cardElement = elements.create('card'); // 将卡片组件挂载到Web页面的DOM容器 await cardElement.mount('#card-element'); // 确认支付 final paymentResult = await Stripe.instance.confirmCardPayment( clientSecret, PaymentMethodParams.card( paymentMethodData: PaymentMethodData( billingDetails: BillingDetails( name: 'YOUR NAME', email: 'YOUREMAIL@gmail.com', ), ), ), ); // 处理支付结果 if (paymentResult.paymentIntentStatus == PaymentIntentStatus.succeeded) { Fluttertoast.showToast(msg: '支付成功'); } else { Fluttertoast.showToast(msg: '支付失败'); } // 支付完成后卸载卡片组件 await cardElement.unmount(); } catch (e) { Fluttertoast.showToast(msg: e.toString()); } }
步骤3:搭建后端接口创建Payment Intent
前端不能直接调用Stripe API,必须通过后端处理,以下是Node.js后端示例:
const stripe = require('stripe')('sk_test_your_secret_key'); const express = require('express'); const app = express(); app.use(express.json()); app.post('/create-payment-intent', async (req, res) => { const { amount, currency } = req.body; const paymentIntent = await stripe.paymentIntents.create({ amount: parseInt(amount) * 100, currency: currency, }); res.json({ client_secret: paymentIntent.client_secret }); }); app.listen(3000, () => console.log('Server running on port 3000'));
前端调用该后端接口的方法:
Future<Map<String, dynamic>> _createPaymentIntentThroughBackend(String amount, String currency) async { try { final response = await http.post( Uri.parse('http://localhost:3000/create-payment-intent'), headers: {'Content-Type': 'application/json'}, body: json.encode({'amount': amount, 'currency': currency}), ); return json.decode(response.body); } catch (err) { throw Exception(err.toString()); } }
步骤4:更新支付触发逻辑
在_startPayment中根据平台调用对应支付方法:
Future<void> _startPayment() async { try { if (kIsWeb) { await _webPayment(); return; } // 保留原有移动端Payment Sheet逻辑 paymentIntent = await _createPaymentIntentThroughBackend('100', 'INR'); await Stripe.instance.initPaymentSheet( paymentSheetParameters: SetupPaymentSheetParameters( billingDetails: BillingDetails( name: 'YOUR NAME', email: 'YOUREMAIL@gmail.com', ), paymentIntentClientSecret: paymentIntent!['client_secret'], ), ); await displayPaymentSheet(); } catch (e) { print(e.toString()); Fluttertoast.showToast(msg: e.toString()); } }
步骤5:Web端页面添加DOM容器
在Flutter Web的index.html中添加卡片组件挂载的容器:
<div id="card-element" style="width: 100%; padding: 16px; margin-bottom: 16px;"></div>
修正后的完整代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart' as http; import 'package:flutter/foundation.dart' show kIsWeb; class PaymentPage extends StatefulWidget { @override _PaymentPageState createState() => _PaymentPageState(); } class _PaymentPageState extends State<PaymentPage> { Map<String, dynamic>? paymentIntent; @override void initState() { super.initState(); _initStripe(); } Future<void> _initStripe() async { if (kIsWeb) { await Stripe.instance.init( publishableKey: "pk_test_your_key_for_web", stripeAccountId: null, ); } else { Stripe.publishableKey = "pk_test_your_key_for_mobile"; } } Future<void> _startPayment() async { try { if (kIsWeb) { await _webPayment(); return; } paymentIntent = await _createPaymentIntentThroughBackend('100', 'INR'); await Stripe.instance.initPaymentSheet( paymentSheetParameters: SetupPaymentSheetParameters( billingDetails: BillingDetails( name: 'YOUR NAME', email: 'YOUREMAIL@gmail.com', ), paymentIntentClientSecret: paymentIntent!['client_secret'], ), ); await displayPaymentSheet(); } catch (e) { print(e.toString()); Fluttertoast.showToast(msg: e.toString()); } } Future<void> _webPayment() async { try { final paymentIntent = await _createPaymentIntentThroughBackend('100', 'INR'); final clientSecret = paymentIntent['client_secret']; final elements = Stripe.instance.elements.create(); final cardElement = elements.create('card'); await cardElement.mount('#card-element'); final paymentResult = await Stripe.instance.confirmCardPayment( clientSecret, PaymentMethodParams.card( paymentMethodData: PaymentMethodData( billingDetails: BillingDetails( name: 'YOUR NAME', email: 'YOUREMAIL@gmail.com', ), ), ), ); if (paymentResult.paymentIntentStatus == PaymentIntentStatus.succeeded) { Fluttertoast.showToast(msg: '支付成功'); } else { Fluttertoast.showToast(msg: '支付失败'); } await cardElement.unmount(); } catch (e) { Fluttertoast.showToast(msg: e.toString()); } } Future<void> displayPaymentSheet() async { try { await Stripe.instance.presentPaymentSheet(); Fluttertoast.showToast(msg: '支付成功'); } on Exception catch (e) { if (e is StripeException) { Fluttertoast.showToast( msg: 'Stripe错误: ${e.error.localizedMessage}', ); } else { Fluttertoast.showToast(msg: '未知错误: ${e}'); } } } Future<Map<String, dynamic>> _createPaymentIntentThroughBackend(String amount, String currency) async { try { final response = await http.post( Uri.parse('http://localhost:3000/create-payment-intent'), headers: {'Content-Type': 'application/json'}, body: json.encode({'amount': amount, 'currency': currency}), ); return json.decode(response.body); } catch (err) { throw Exception(err.toString()); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Stripe支付示例'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Web端显示卡片输入区域 if (kIsWeb) const SizedBox( width: 300, height: 50, child: HtmlElementView(viewType: 'card-element'), ), const SizedBox(height: 20), ElevatedButton( onPressed: _startPayment, child: const Text('发起支付'), ), ], ), ), ); } }
内容的提问来源于stack exchange,提问作者Isuru Bandara
相关产品推荐
相关产品推荐

