前言
pay 是 Google 官方维护的 Flutter 插件,提供了统一的 API 来集成 Apple Pay 和 Google Pay。相比其他支付插件,它更加轻量且易于配置。本文将详细介绍如何使用这个插件在 Flutter 应用中实现原生支付功能。
插件介绍
为什么选择 pay 插件?
- 官方维护: 由 Google 官方团队维护,更新及时
- 统一 API: 一套代码同时支持 Apple Pay 和 Google Pay
- 配置简单: 使用 JSON 配置文件,无需复杂的原生代码
- 灵活性高: 支持多种支付网关(Stripe、Braintree、Adyen 等)
- 内置 UI: 提供标准的支付按钮组件
插件架构
ASCII
┌─────────────────────────────────────────────────────┐
│ Flutter App │
│ (Payment UI) │
├─────────────────────────────────────────────────────┤
│ pay │
│ (Plugin) │
├────────────────────────┬────────────────────────────┤
│ Apple Pay │ Google Pay │
│ (iOS) │ (Android) │
├────────────────────────┴────────────────────────────┤
│ Payment Gateway │
│ Stripe | Braintree | Adyen | Others... │
└─────────────────────────────────────────────────────┘
环境准备
前置要求
- Flutter SDK >= 3.0.0
- Dart >= 2.17.0
- iOS 12.0+ (Apple Pay)
- Android API 19+ (Google Pay)
- 支付网关账户(如 Stripe)
开发环境
- Xcode 14+ (iOS 开发)
- Android Studio / VS Code
- 真机设备(模拟器支持有限)
安装与配置
1. 添加依赖
在 pubspec.yaml 中添加:
yaml
dependencies:
pay: ^3.3.0
运行:
bash
flutter pub get
2. iOS 配置 (Apple Pay)
2.1 修改 ios/Podfile
ruby
platform :ios, '12.0'
2.2 在 Xcode 中添加 Apple Pay 能力
- 打开
ios/Runner.xcworkspace - 选择 Runner 项目 → Signing & Capabilities
- 点击 "+ Capability" → 添加 "Apple Pay"
- 添加你的 Merchant ID(格式:
merchant.com.yourcompany.yourapp)
2.3 Apple Developer 配置
- 登录 Apple Developer Portal
- 进入 Certificates, Identifiers & Profiles
- 选择 Identifiers → Merchant IDs
- 创建新的 Merchant ID
- 为你的 App ID 启用 Apple Pay 并关联 Merchant ID
3. Android 配置 (Google Pay)
3.1 修改 android/app/build.gradle.kts
kotlin
android {
compileSdk = 34
defaultConfig {
minSdk = 19
targetSdk = 34
}
}
3.2 修改 android/app/src/main/AndroidManifest.xml
xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<!-- 启用 Google Pay API -->
<meta-data
android:name="com.google.android.gms.wallet.api.enabled"
android:value="true" />
</application>
</manifest>
支付配置文件
pay 插件使用 JSON 配置文件来定义支付参数。这是该插件的核心特性。
1. 创建配置文件目录
assets/
├── apple_pay_config.json
└── google_pay_config.json
2. Apple Pay 配置文件
创建 assets/apple_pay_config.json:
json
{
"provider": "apple_pay",
"data": {
"merchantIdentifier": "merchant.com.yourcompany.yourapp",
"displayName": "Your Store Name",
"merchantCapabilities": [
"3DS",
"debit",
"credit"
],
"supportedNetworks": [
"amex",
"discover",
"masterCard",
"visa"
],
"countryCode": "US",
"currencyCode": "USD",
"requiredBillingContactFields": [
"emailAddress",
"name",
"phoneNumber",
"postalAddress"
],
"requiredShippingContactFields": [
"emailAddress",
"name",
"phoneNumber",
"postalAddress"
],
"shippingMethods": [
{
"amount": "0.00",
"detail": "3-5 business days",
"identifier": "standard",
"label": "Standard Shipping"
},
{
"amount": "9.99",
"detail": "1-2 business days",
"identifier": "express",
"label": "Express Shipping"
}
]
}
}
配置参数说明
| 参数 | 说明 |
|---|---|
merchantIdentifier |
Apple Developer 中创建的 Merchant ID |
displayName |
支付表单中显示的商户名称 |
merchantCapabilities |
支持的支付能力(3DS、借记卡、信用卡) |
supportedNetworks |
支持的卡网络 |
countryCode |
商户所在国家代码 |
currencyCode |
交易货币代码 |
3. Google Pay 配置文件
创建 assets/google_pay_config.json:
json
{
"provider": "google_pay",
"data": {
"environment": "TEST",
"apiVersion": 2,
"apiVersionMinor": 0,
"allowedPaymentMethods": [
{
"type": "CARD",
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "stripe",
"stripe:version": "2020-08-27",
"stripe:publishableKey": "pk_test_your_publishable_key"
}
},
"parameters": {
"allowedCardNetworks": [
"VISA",
"MASTERCARD",
"AMEX",
"DISCOVER"
],
"allowedAuthMethods": [
"PAN_ONLY",
"CRYPTOGRAM_3DS"
],
"billingAddressRequired": true,
"billingAddressParameters": {
"format": "FULL",
"phoneNumberRequired": true
}
}
}
],
"merchantInfo": {
"merchantId": "BCR2DN4XXXXX",
"merchantName": "Your Store Name"
},
"transactionInfo": {
"countryCode": "US",
"currencyCode": "USD"
}
}
}
Google Pay 配置参数说明
| 参数 | 说明 |
|---|---|
environment |
TEST 或 PRODUCTION |
gateway |
支付网关名称(stripe、braintree 等) |
merchantId |
Google Pay 商户 ID(生产环境需要) |
allowedCardNetworks |
支持的卡网络 |
allowedAuthMethods |
支持的认证方式 |
4. 引用资源文件
在 pubspec.yaml 中添加:
yaml
flutter:
assets:
- assets/apple_pay_config.json
- assets/google_pay_config.json
Apple Pay 实现
基础实现
dart
import 'package:pay/pay.dart';
import 'package:flutter/material.dart';
class ApplePayExample extends StatefulWidget {
const ApplePayExample({super.key});
@override
State<ApplePayExample> createState() => _ApplePayExampleState();
}
class _ApplePayExampleState extends State<ApplePayExample> {
late final Pay _payClient;
// 定义支付项目
final List<PaymentItem> _paymentItems = [
const PaymentItem(
label: '商品小计',
amount: '99.99',
status: PaymentItemStatus.final_price,
),
const PaymentItem(
label: '运费',
amount: '5.99',
status: PaymentItemStatus.final_price,
),
const PaymentItem(
label: '总计',
amount: '105.98',
status: PaymentItemStatus.final_price,
),
];
@override
void initState() {
super.initState();
// 从配置文件初始化
_payClient = Pay({
PayProvider.apple_pay: PaymentConfiguration.fromJsonString(
_applePayConfigString,
),
});
}
// 处理支付结果
void _onApplePayResult(Map<String, dynamic> result) {
// result 包含支付 token 和其他信息
debugPrint('Apple Pay 结果: $result');
// 将 token 发送到后端处理
_processPayment(result);
}
Future<void> _processPayment(Map<String, dynamic> paymentResult) async {
// 发送到后端
// final response = await http.post(...);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ApplePayButton(
paymentConfiguration: PaymentConfiguration.fromJsonString(
_applePayConfigString,
),
paymentItems: _paymentItems,
style: ApplePayButtonStyle.black,
type: ApplePayButtonType.buy,
onPaymentResult: _onApplePayResult,
onError: (error) {
debugPrint('Apple Pay 错误: $error');
},
loadingIndicator: const CircularProgressIndicator(),
),
),
);
}
}
Apple Pay 按钮样式
dart
// 按钮样式选项
ApplePayButtonStyle.black // 黑色背景
ApplePayButtonStyle.white // 白色背景
ApplePayButtonStyle.whiteOutline // 白色带边框
// 按钮类型选项
ApplePayButtonType.buy // "使用 Apple Pay 购买"
ApplePayButtonType.plain // Apple Pay 图标
ApplePayButtonType.setUp // "设置 Apple Pay"
ApplePayButtonType.inStore // "店内使用 Apple Pay"
ApplePayButtonType.donate // "使用 Apple Pay 捐赠"
ApplePayButtonType.checkout // "使用 Apple Pay 结账"
ApplePayButtonType.book // "使用 Apple Pay 预订"
ApplePayButtonType.subscribe // "使用 Apple Pay 订阅"
Google Pay 实现
基础实现
dart
import 'package:pay/pay.dart';
import 'package:flutter/material.dart';
class GooglePayExample extends StatefulWidget {
const GooglePayExample({super.key});
@override
State<GooglePayExample> createState() => _GooglePayExampleState();
}
class _GooglePayExampleState extends State<GooglePayExample> {
// 定义支付项目
final List<PaymentItem> _paymentItems = [
const PaymentItem(
label: '商品总计',
amount: '99.99',
status: PaymentItemStatus.final_price,
),
const PaymentItem(
label: '运费',
amount: '5.99',
status: PaymentItemStatus.final_price,
),
const PaymentItem(
label: '总计',
amount: '105.98',
status: PaymentItemStatus.final_price,
),
];
// 处理支付结果
void _onGooglePayResult(Map<String, dynamic> result) {
debugPrint('Google Pay 结果: $result');
// 从结果中提取 token
final token = result['paymentMethodData']['tokenizationData']['token'];
debugPrint('支付 Token: $token');
// 将 token 发送到后端处理
_processPayment(token);
}
Future<void> _processPayment(String token) async {
// 发送到后端
// final response = await http.post(...);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GooglePayButton(
paymentConfiguration: PaymentConfiguration.fromAsset(
'assets/google_pay_config.json',
),
paymentItems: _paymentItems,
type: GooglePayButtonType.buy,
onPaymentResult: _onGooglePayResult,
onError: (error) {
debugPrint('Google Pay 错误: $error');
},
loadingIndicator: const CircularProgressIndicator(),
),
),
);
}
}
Google Pay 按钮样式
dart
// 按钮类型选项
GooglePayButtonType.buy // "使用 Google Pay 购买"
GooglePayButtonType.book // "使用 Google Pay 预订"
GooglePayButtonType.checkout // "使用 Google Pay 结账"
GooglePayButtonType.donate // "使用 Google Pay 捐赠"
GooglePayButtonType.order // "使用 Google Pay 下单"
GooglePayButtonType.pay // "使用 Google Pay 支付"
GooglePayButtonType.plain // Google Pay 图标
GooglePayButtonType.subscribe // "使用 Google Pay 订阅"
完整代码示例
支付服务类
dart
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:pay/pay.dart';
class NativePayService {
static NativePayService? _instance;
late Pay _payClient;
PaymentConfiguration? _applePayConfig;
PaymentConfiguration? _googlePayConfig;
NativePayService._();
static NativePayService get instance {
_instance ??= NativePayService._();
return _instance!;
}
/// 初始化支付服务
Future<void> initialize() async {
final configurations = <PayProvider, PaymentConfiguration>{};
if (Platform.isIOS) {
final applePayConfigString = await rootBundle.loadString(
'assets/apple_pay_config.json',
);
_applePayConfig = PaymentConfiguration.fromJsonString(
applePayConfigString,
);
configurations[PayProvider.apple_pay] = _applePayConfig!;
}
if (Platform.isAndroid) {
final googlePayConfigString = await rootBundle.loadString(
'assets/google_pay_config.json',
);
_googlePayConfig = PaymentConfiguration.fromJsonString(
googlePayConfigString,
);
configurations[PayProvider.google_pay] = _googlePayConfig!;
}
_payClient = Pay(configurations);
}
/// 获取当前平台的支付配置
PaymentConfiguration? get currentConfig {
if (Platform.isIOS) return _applePayConfig;
if (Platform.isAndroid) return _googlePayConfig;
return null;
}
/// 检查原生支付是否可用
Future<bool> isAvailable() async {
try {
if (Platform.isIOS) {
return await _payClient.userCanPay(PayProvider.apple_pay);
} else if (Platform.isAndroid) {
return await _payClient.userCanPay(PayProvider.google_pay);
}
return false;
} catch (e) {
return false;
}
}
/// 显示支付表单
Future<Map<String, dynamic>> showPaymentSheet({
required List<PaymentItem> paymentItems,
}) async {
if (Platform.isIOS) {
return await _payClient.showPaymentSelector(
PayProvider.apple_pay,
paymentItems,
);
} else if (Platform.isAndroid) {
return await _payClient.showPaymentSelector(
PayProvider.google_pay,
paymentItems,
);
}
throw UnsupportedError('不支持的平台');
}
}
跨平台支付页面
dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:pay/pay.dart';
import '../services/native_pay_service.dart';
class CheckoutScreen extends StatefulWidget {
const CheckoutScreen({super.key});
@override
State<CheckoutScreen> createState() => _CheckoutScreenState();
}
class _CheckoutScreenState extends State<CheckoutScreen> {
bool _isLoading = true;
bool _isPayAvailable = false;
String? _errorMessage;
// 购物车商品
final List<CartItem> _cartItems = [
CartItem(name: 'Flutter 开发指南', price: 49.99),
CartItem(name: 'Dart 编程实战', price: 39.99),
];
// 计算总价
double get _subtotal => _cartItems.fold(0, (sum, item) => sum + item.price);
double get _shipping => 5.99;
double get _total => _subtotal + _shipping;
// 支付项目列表
List<PaymentItem> get _paymentItems => [
PaymentItem(
label: '商品小计',
amount: _subtotal.toStringAsFixed(2),
status: PaymentItemStatus.final_price,
),
PaymentItem(
label: '运费',
amount: _shipping.toStringAsFixed(2),
status: PaymentItemStatus.final_price,
),
PaymentItem(
label: '总计',
amount: _total.toStringAsFixed(2),
status: PaymentItemStatus.final_price,
),
];
@override
void initState() {
super.initState();
_initializePayment();
}
Future<void> _initializePayment() async {
try {
await NativePayService.instance.initialize();
final isAvailable = await NativePayService.instance.isAvailable();
setState(() {
_isPayAvailable = isAvailable;
_isLoading = false;
});
} catch (e) {
setState(() {
_errorMessage = e.toString();
_isLoading = false;
});
}
}
void _onPaymentResult(Map<String, dynamic> result) {
debugPrint('支付结果: $result');
// 显示成功提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('支付成功!'),
backgroundColor: Colors.green,
),
);
// 处理支付结果
_processPaymentOnServer(result);
}
Future<void> _processPaymentOnServer(Map<String, dynamic> result) async {
// 提取 token 并发送到后端
String token;
if (Platform.isIOS) {
// Apple Pay token
token = result['token'] ?? '';
} else {
// Google Pay token
token = result['paymentMethodData']?['tokenizationData']?['token'] ?? '';
}
// 发送到后端处理
// await PaymentApi.processPayment(token: token, amount: _total);
}
void _onPaymentError(Object? error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('支付失败: $error'),
backgroundColor: Colors.red,
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('结账'),
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: _buildContent(),
);
}
Widget _buildContent() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 购物车商品列表
_buildCartItems(),
const SizedBox(height: 16),
// 价格明细
_buildPriceSummary(),
const SizedBox(height: 24),
// 支付按钮
_buildPaymentButton(),
const SizedBox(height: 16),
// 或者使用其他支付方式
_buildAlternativePayment(),
],
),
);
}
Widget _buildCartItems() {
return Card(
child: Column(
children: _cartItems.map((item) => ListTile(
title: Text(item.name),
trailing: Text('\$${item.price.toStringAsFixed(2)}'),
)).toList(),
),
);
}
Widget _buildPriceSummary() {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_buildPriceRow('小计', _subtotal),
_buildPriceRow('运费', _shipping),
const Divider(),
_buildPriceRow('总计', _total, isBold: true),
],
),
),
);
}
Widget _buildPriceRow(String label, double amount, {bool isBold = false}) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: TextStyle(
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
fontSize: isBold ? 18 : 14,
),
),
Text(
'\$${amount.toStringAsFixed(2)}',
style: TextStyle(
fontWeight: isBold ? FontWeight.bold : FontWeight.normal,
fontSize: isBold ? 18 : 14,
),
),
],
),
);
}
Widget _buildPaymentButton() {
if (!_isPayAvailable) {
return const Text(
'此设备不支持 Apple Pay / Google Pay',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey),
);
}
final config = NativePayService.instance.currentConfig;
if (config == null) return const SizedBox.shrink();
if (Platform.isIOS) {
return ApplePayButton(
paymentConfiguration: config,
paymentItems: _paymentItems,
style: ApplePayButtonStyle.black,
type: ApplePayButtonType.checkout,
onPaymentResult: _onPaymentResult,
onError: _onPaymentError,
loadingIndicator: const Center(
child: CircularProgressIndicator(),
),
);
} else {
return GooglePayButton(
paymentConfiguration: config,
paymentItems: _paymentItems,
type: GooglePayButtonType.checkout,
onPaymentResult: _onPaymentResult,
onError: _onPaymentError,
loadingIndicator: const Center(
child: CircularProgressIndicator(),
),
);
}
}
Widget _buildAlternativePayment() {
return Column(
children: [
const Row(
children: [
Expanded(child: Divider()),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text('或', style: TextStyle(color: Colors.grey)),
),
Expanded(child: Divider()),
],
),
const SizedBox(height: 16),
OutlinedButton(
onPressed: () {
// 跳转到信用卡支付页面
},
child: const Text('使用信用卡支付'),
),
],
);
}
}
class CartItem {
final String name;
final double price;
CartItem({required this.name, required this.price});
}
应用入口
dart
import 'package:flutter/material.dart';
import 'screens/checkout_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Pay Plugin Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const CheckoutScreen(),
);
}
}
与支付网关集成
Stripe 集成
后端代码 (Node.js)
javascript
const express = require('express');
const stripe = require('stripe')('sk_test_your_secret_key');
const app = express();
app.use(express.json());
// 处理 Apple Pay / Google Pay token
app.post('/process-payment', async (req, res) => {
try {
const { token, amount, currency } = req.body;
// 创建支付
const charge = await stripe.charges.create({
amount: Math.round(amount * 100), // 转换为分
currency: currency || 'usd',
source: token,
description: 'App Purchase',
});
res.json({
success: true,
chargeId: charge.id,
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
});
}
});
// 或者使用 Payment Intent(推荐)
app.post('/create-payment-intent', async (req, res) => {
try {
const { amount, currency } = req.body;
const paymentIntent = await stripe.paymentIntents.create({
amount: Math.round(amount * 100),
currency: currency || 'usd',
automatic_payment_methods: {
enabled: true,
},
});
res.json({
clientSecret: paymentIntent.client_secret,
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000);
其他支付网关配置
Braintree
json
{
"provider": "google_pay",
"data": {
"environment": "TEST",
"apiVersion": 2,
"apiVersionMinor": 0,
"allowedPaymentMethods": [
{
"type": "CARD",
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "braintree",
"braintree:apiVersion": "v1",
"braintree:sdkVersion": "3.0.0",
"braintree:merchantId": "your_merchant_id",
"braintree:clientKey": "your_client_key"
}
},
"parameters": {
"allowedCardNetworks": ["VISA", "MASTERCARD"],
"allowedAuthMethods": ["PAN_ONLY", "CRYPTOGRAM_3DS"]
}
}
]
}
}
Adyen
json
{
"provider": "google_pay",
"data": {
"environment": "TEST",
"apiVersion": 2,
"apiVersionMinor": 0,
"allowedPaymentMethods": [
{
"type": "CARD",
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "adyen",
"gatewayMerchantId": "your_merchant_account"
}
},
"parameters": {
"allowedCardNetworks": ["VISA", "MASTERCARD", "AMEX"],
"allowedAuthMethods": ["PAN_ONLY", "CRYPTOGRAM_3DS"]
}
}
]
}
}
测试与调试
测试环境设置
-
Google Pay 测试模式
- 配置文件中设置
"environment": "TEST" - 加入 Google Pay API 测试卡组
- 配置文件中设置
-
Apple Pay 沙盒测试
- 使用 Sandbox 测试账户
- 在设置中添加测试卡
调试技巧
dart
// 详细日志输出
void _onPaymentResult(Map<String, dynamic> result) {
// 打印完整结果
debugPrint('完整支付结果:');
debugPrint(const JsonEncoder.withIndent(' ').convert(result));
// Apple Pay 结果结构
if (Platform.isIOS) {
debugPrint('Token: ${result['token']}');
debugPrint('Transaction ID: ${result['transactionIdentifier']}');
debugPrint('Payment Method: ${result['paymentMethod']}');
}
// Google Pay 结果结构
if (Platform.isAndroid) {
final paymentMethodData = result['paymentMethodData'];
debugPrint('Type: ${paymentMethodData['type']}');
debugPrint('Token: ${paymentMethodData['tokenizationData']['token']}');
debugPrint('Card Network: ${paymentMethodData['info']['cardNetwork']}');
}
}
常见测试场景
dart
// 测试不同金额
final testAmounts = [
PaymentItem(label: '小额测试', amount: '1.00', status: PaymentItemStatus.final_price),
PaymentItem(label: '标准测试', amount: '99.99', status: PaymentItemStatus.final_price),
PaymentItem(label: '大额测试', amount: '999.99', status: PaymentItemStatus.final_price),
];
// 测试待定价格(如运费计算中)
final pendingItems = [
PaymentItem(label: '商品', amount: '50.00', status: PaymentItemStatus.final_price),
PaymentItem(label: '运费', amount: '0.00', status: PaymentItemStatus.pending), // 待计算
];
常见问题
Q1: Apple Pay 按钮不显示?
可能原因与解决方案:
-
设备未添加支付卡
- 在设置 → 钱包与 Apple Pay 中添加卡片
-
Merchant ID 配置错误
- 检查 Xcode 中的 Merchant ID 是否与配置文件一致
- 确认 Apple Developer 中已正确配置
-
模拟器限制
- Apple Pay 在模拟器上支持有限,建议使用真机测试
Q2: Google Pay 返回 "Request Failed"?
解决方案:
- 检查
AndroidManifest.xml中的 meta-data 配置 - 确认 Google Play Services 已更新
- 检查配置文件中的 gateway 参数是否正确
- 确保设备已安装 Google Pay 应用
Q3: 如何处理用户取消支付?
dart
void _onPaymentError(Object? error) {
if (error is PlatformException) {
if (error.code == 'cancelled') {
// 用户取消了支付
debugPrint('用户取消支付');
return;
}
}
// 其他错误
debugPrint('支付错误: $error');
}
Q4: 如何自定义支付按钮?
dart
// 使用 Pay 客户端手动触发支付
class CustomPayButton extends StatelessWidget {
final List<PaymentItem> paymentItems;
final Function(Map<String, dynamic>) onResult;
const CustomPayButton({
super.key,
required this.paymentItems,
required this.onResult,
});
Future<void> _handlePayment() async {
try {
final result = await NativePayService.instance.showPaymentSheet(
paymentItems: paymentItems,
);
onResult(result);
} catch (e) {
debugPrint('支付错误: $e');
}
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _handlePayment,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 32),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Platform.isIOS ? Icons.apple : Icons.g_mobiledata),
const SizedBox(width: 8),
Text(Platform.isIOS ? 'Apple Pay' : 'Google Pay'),
],
),
);
}
}
Q5: 如何支持多种货币?
dart
// 动态配置货币
PaymentItem createPaymentItem({
required String label,
required double amount,
required String currencyCode,
}) {
// 根据货币格式化金额
String formattedAmount;
switch (currencyCode) {
case 'JPY': // 日元无小数
formattedAmount = amount.toInt().toString();
break;
default:
formattedAmount = amount.toStringAsFixed(2);
}
return PaymentItem(
label: label,
amount: formattedAmount,
status: PaymentItemStatus.final_price,
);
}
生产环境检查清单
通用检查
- 替换测试配置为生产配置
- 配置生产环境的支付网关密钥
- 实现支付结果的服务端验证
- 添加支付失败重试机制
- 配置错误监控和日志
- 实现订单状态同步
Apple Pay 检查
- 在 Apple Developer 中完成商户认证
- 上传支付处理证书到支付网关
- 测试所有支持的卡网络
- 验证 Merchant ID 配置
Google Pay 检查
- 申请 Google Pay 生产环境访问权限
- 设置
"environment": "PRODUCTION" - 配置正确的
merchantId - 完成 Google Pay API 集成检查清单