flutter_kinetra/lib/kt_utils/kt_iap_util.dart
2025-09-23 15:09:18 +08:00

127 lines
4.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
import 'package:in_app_purchase_storekit/store_kit_wrappers.dart';
// 内购工具类
class KtInAppPurchaseUtil {
static final InAppPurchase _iap = InAppPurchase.instance;
/// 查询可用商品
static Future<ProductDetailsResponse> queryProducts(Set<String> productIds) async {
return await _iap.queryProductDetails(productIds);
}
/// 购买商品(自动区分消耗型/非消耗型)
static Future<void> buy(ProductDetails product, {bool consumable = false}) async {
final purchaseParam = PurchaseParam(productDetails: product);
if (consumable) {
await _iap.buyConsumable(purchaseParam: purchaseParam, autoConsume: Platform.isIOS);
} else {
await _iap.buyNonConsumable(purchaseParam: purchaseParam);
}
}
/// 监听购买更新
static Stream<List<PurchaseDetails>> get purchaseStream => _iap.purchaseStream;
/// 完成购买(消耗型商品)
static Future<void> completePurchase(PurchaseDetails purchase, {bool isRetry = false}) async {
if (purchase.pendingCompletePurchase) {
if (isRetry) {
for (int i = 0; i < 3; i++) {
try {
await _iap.completePurchase(purchase);
return;
} catch (e) {
debugPrint('---err:${e}');
}
}
} else {
await _iap.completePurchase(purchase);
}
}
// if (Platform.isAndroid) {
// final InAppPurchaseAndroidPlatformAddition addition =
// InAppPurchasePlatformAddition.instance! as InAppPurchaseAndroidPlatformAddition;
// if (purchase.productID.contains('coins')) {
// await addition.consumePurchase(purchase);
// }
// QueryPurchaseDetailsResponse response = await addition.queryPastPurchases();
// for (GooglePlayPurchaseDetails purchaseDetails in response.pastPurchases) {
// _iap.completePurchase(purchaseDetails);
// }
// } else {
// if (purchase.pendingCompletePurchase) {
// await _iap.completePurchase(purchase);
// }
// }
}
static Future<void> consumeIfNeeded(PurchaseDetails purchaseDetails) async {
if (purchaseDetails is GooglePlayPurchaseDetails) {
final InAppPurchaseAndroidPlatformAddition addition =
InAppPurchasePlatformAddition.instance! as InAppPurchaseAndroidPlatformAddition;
await addition.consumePurchase(purchaseDetails);
}
}
/// 检查是否可用
static Future<bool> isAvailable() async {
return await _iap.isAvailable();
}
/// 恢复购买(非消耗型商品)
static Future<void> restorePurchases() async {
await _iap.restorePurchases();
}
/// 校验购买状态
static bool isPurchaseSuccess(PurchaseDetails purchase) {
return purchase.status == PurchaseStatus.purchased || purchase.status == PurchaseStatus.restored;
}
/// 取消订阅流(如需手动管理)
static void cancelStreamSubscription(StreamSubscription? sub) {
sub?.cancel();
}
/// 完成错误的购买
// static void completeFailed() {
// _iap.clearPendingPurchases();
// }
// @visibleForTesting
static Future<void> clearFailedPurchases() async {
if (Platform.isIOS || Platform.isMacOS) {
final wrapper = SKPaymentQueueWrapper();
final transactions = await wrapper.transactions();
for (final transaction in transactions) {
// if (transaction.transactionState == SKPaymentTransactionStateWrapper.failed) {
await wrapper.finishTransaction(transaction);
// }
}
}
}
/// 获取未完成的购买(通过监听 purchaseStream
static Future<List<PurchaseDetails>> getPendingPurchases() async {
final available = await isAvailable();
if (!available) return [];
final List<PurchaseDetails> pending = [];
// 只获取一次当前流数据
final completer = Completer<List<PurchaseDetails>>();
final sub = purchaseStream.listen((purchases) {
pending.addAll(purchases.where((p) => p.status == PurchaseStatus.pending));
completer.complete(pending);
});
final result = await completer.future;
await sub.cancel();
return result;
}
}