Flutter 支付插件 in_app_purchase 使用指南
目前在 Dart 的 pub.dev 上,比较流行的支付插件有:
- in_app_purchase - Flutter 官方团队出品
- flutter_inapp_purchase - 社区流行插件
其中 in_app_purchase 是官方推荐的选择,本文会详细讲解这个库的用法和一些实用封装技巧。
发起支付
商品概念
在支付开发中,每个商品都有对应的 sku 标识。我们通常通过后端获取可购买商品信息,包含 sku 和业务相关信息。
查询商品
const Set<String> _kIds = <String>{'product1', 'product2'};
final ProductDetailsResponse response =
await InAppPurchase.instance.queryProductDetails(_kIds);
if (response.notFoundIDs.isNotEmpty) {
// 处理错误
}
List<ProductDetails> products = response.productDetails;
发起支付
final ProductDetails productDetails = ... // 查询到的商品
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
if (_isConsumable(productDetails)) {
InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam);
} else {
InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam);
}
消耗型 vs 非消耗型商品:
- 消耗型商品可多次购买(如游戏币)
- 非消耗型商品只能购买一次(如应用解锁)
深入支付参数
PurchaseParam 包含两个重要字段:
productDetails:商品信息applicationUserName:业务关联字段(如用户ID或订单ID)
高级支付实现
对于需要更多控制的情况,可以直接使用 BillingClientManager:
BillingClientManager get _billingClientManager {
return (InAppPurchasePlatform.instance as InAppPurchaseAndroidPlatform)
.billingClientManager;
}
Future launchPayment({
required GooglePlayProductDetails product,
required String orderId,
required String userId,
}) async {
await _billingClientManager.runWithClient((client) {
return client.launchBillingFlow(
product: product.id,
accountId: userId,
obfuscatedProfileId: orderId,
offerToken: product.offerToken,
);
});
}
提示:如果你在开发iOS应用,可以使用AppUploader这样的工具来简化应用上传和测试流程,它提供了便捷的IPA包管理和设备管理功能。
支付结果监听
使用 Stream 监听支付结果:
StreamSubscription<List<PurchaseDetails>> _subscription;
@override
void initState() {
final Stream purchaseUpdated = InAppPurchase.instance.purchaseStream;
_subscription = purchaseUpdated.listen((purchaseDetailsList) {
_listenToPurchaseUpdated(purchaseDetailsList);
}, onDone: () {
_subscription.cancel();
}, onError: (error) {
// 处理错误
});
super.initState();
}
封装为 Promise 风格
Future<TWIAPGooglePurchaseResult> launchPayment({
required ProductDetails product,
required String orderId,
}) async {
final c = Completer<TWIAPGooglePurchaseResult>();
_completer = c;
_billingClientManager.runWithClient((client) {
return client.launchBillingFlow(
product: product.id,
accountId: userId,
obfuscatedProfileId: orderId,
offerToken: product.offerToken,
);
}).then((value) {
if (value.responseCode != BillingResponse.ok) {
c.complete(TWIAPGooglePurchaseResult.failure());
} else {
TWIAPUpdateDispatcher().register(_handlePurchase);
}
});
return c.future;
}
订单处理
订单消耗/确认
必须在3天内处理,否则会自动退款:
// 确认订单(非消耗型)
InAppPurchase.instance.completePurchase(purchase);
// 消耗订单(消耗型)
final wrapper = await InAppPurchase.instance
.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>()
.consumePurchase(purchase);
历史订单查询
// 恢复购买
InAppPurchase.instance.restorePurchases();
// 查询历史订单
final restoredResp = await _billingClientManager.runWithClient((client) =>
client.queryPurchases(ProductType.inapp));
处理Pending订单
对于线下支付产生的Pending订单:
- 收到时提醒用户订单待支付
- App启动时初始化后台服务监听订单状态变化
- 订单转为已支付时完成入账并提醒用户
- App启动时立即检查一次历史订单
总结
本文详细介绍了Flutter官方支付插件in_app_purchase的使用方法,包括:
- 基础支付流程
- 高级支付控制
- 结果监听封装
- 订单处理策略
- 特殊状态处理
对于iOS开发者,使用像AppUploader这样的工具可以简化应用测试和发布流程,提高开发效率。希望这些内容能帮助你更好地实现应用内支付功能。