Flutter 集成谷歌支付[in_app_purchase]

717 阅读2分钟

Flutter 支付插件 in_app_purchase 使用指南

目前在 Dart 的 pub.dev 上,比较流行的支付插件有:

其中 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订单:

  1. 收到时提醒用户订单待支付
  2. App启动时初始化后台服务监听订单状态变化
  3. 订单转为已支付时完成入账并提醒用户
  4. App启动时立即检查一次历史订单

总结

本文详细介绍了Flutter官方支付插件in_app_purchase的使用方法,包括:

  • 基础支付流程
  • 高级支付控制
  • 结果监听封装
  • 订单处理策略
  • 特殊状态处理

对于iOS开发者,使用像AppUploader这样的工具可以简化应用测试和发布流程,提高开发效率。希望这些内容能帮助你更好地实现应用内支付功能。