import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:in_app_purchase/in_app_purchase.dart'; import 'package:in_app_purchase_android/in_app_purchase_android.dart'; import 'package:yumi/app_localizations.dart'; import 'package:yumi/services/auth/user_profile_manager.dart'; import 'package:yumi/services/general/sc_app_general_manager.dart'; import 'package:provider/provider.dart'; import 'package:yumi/shared/tools/sc_string_utils.dart'; import 'package:yumi/shared/tools/sc_loading_manager.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:yumi/ui_kit/components/dialog/dialog_base.dart'; import 'package:yumi/ui_kit/components/sc_tts.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_config_repository_imp.dart'; import 'package:yumi/shared/business_logic/models/res/sc_google_pay_res.dart'; import 'package:yumi/shared/business_logic/models/res/sc_product_config_res.dart'; import 'package:yumi/modules/wallet/recharge/recharge_page.dart'; class AndroidPaymentProcessor extends ChangeNotifier { StreamSubscription>? _subscription; final InAppPurchase iap = InAppPurchase.instance; // 状态管理变量 bool _isAvailable = false; String _errorMessage = ''; final List _products = []; List _purchases = []; ///商品列表 List productConfigs = []; // 维护商品类型映射 final Map _productTypeMap = {}; final Set _verifyingPurchaseKeys = {}; bool _isReconcilingPastPurchases = false; DateTime? _lastPastPurchaseReconcileAt; // 公开访问器 bool get isAvailable => _isAvailable; String get errorMessage => _errorMessage; List get products => _products; List get purchases => _purchases; late BuildContext context; Map productMap = {}; Map productTypes = {}; // 初始化支付系统 Future initializePaymentProcessor(BuildContext context) async { this.context = context; try { SCLoadingManager.show(context: context); // 检查支付是否可用 _isAvailable = await iap.isAvailable(); if (!_isAvailable) { _errorMessage = 'Google Play payment service is unavailable'; SCTts.show("Google Play payment service is unavailable"); return; } _ensurePurchaseStreamListener(); // 先获取商品配置 await fetchProductConfiguration(); // 然后获取谷歌商品信息 await _fetchProducts(); // 最后恢复购买,处理未完成交易 await recoverTransactions(); await reconcilePendingGooglePurchases(force: true); } catch (e) { SCTts.show("init fail: $e"); _errorMessage = 'init fail: ${e.toString()}'; } finally { SCLoadingManager.hide(); notifyListeners(); } } void _ensurePurchaseStreamListener() { _subscription ??= iap.purchaseStream.listen( _handlePurchase, onError: (error, stackTrace) => _handleError(error, stackTrace), ); } ///用户获取商店配置的商品列表 Future fetchProductConfiguration() async { productMap.clear(); productConfigs = await SCConfigRepositoryImp().productConfig(); int index = 0; for (var value in productConfigs) { productMap[value.productPackage!] = value; productTypes[value.productPackage!] = "consumable"; index = index + 1; } notifyListeners(); } // 获取商品信息 Future _fetchProducts() async { try { SCLoadingManager.show(context: context); notifyListeners(); Set productIds = productTypes.keys.toSet(); ProductDetailsResponse response = await iap.queryProductDetails( productIds, ); if (response.notFoundIDs.isNotEmpty) { _errorMessage = '未找到商品: ${response.notFoundIDs.join(', ')}'; } var dtails = response.productDetails; if (dtails.isNotEmpty) { dtails.sort((a, b) { int ia = 0; int ib = 0; if (a.id.contains(".")) { ia = SCStringUtils.convertToInteger(a.id.split(".").last); } if (b.id.contains(".")) { ib = SCStringUtils.convertToInteger(b.id.split(".").last); } return ia.compareTo(ib); }); } int index = 0; _products.clear(); for (var v in dtails) { if (index == 0) { _products.add(SelecteProductConfig(v, true)); } else { _products.add(SelecteProductConfig(v, false)); } index++; } // 初始化商品类型映射 for (var product in _products) { if (productTypes.containsKey(product.produc.id)) { _productTypeMap[product.produc.id] = productTypes[product.produc.id]!; } else { _productTypeMap[product.produc.id] = 'nonConsumable'; // 默认类型 } } } catch (e) { SCTts.show("Failed to retrieve the product: $e"); _errorMessage = '获取商品失败: ${e.toString()}'; } finally { SCLoadingManager.hide(); notifyListeners(); } } // 获取商品类型 String _getProductType(String productId) { if (productId.startsWith('coins.')) { return 'consumable'; } return _productTypeMap[productId] ?? 'nonConsumable'; } // 发起购买 Future processPurchase() async { ProductDetails? product; for (final d in _products) { if (d.isSelecte) { product = d.produc; } } if (product == null) { SCTts.show(SCAppLocalizations.of(context)!.pleaseSelectaItem); return; } SmartDialog.show( tag: "showConfirmDialog", alignment: Alignment.center, debounce: true, animationType: SmartAnimationType.fade, builder: (_) { return MsgDialog( title: SCAppLocalizations.of(context)!.tips, msg: SCAppLocalizations.of(context)!.areYouRureRoRecharge, btnText: SCAppLocalizations.of(context)!.confirm, onEnsure: () { _goBuy(product!); }, ); }, ); } Future processFirstRechargePurchase({ required BuildContext context, required int rechargeAmountCents, String productPackage = '', }) async { this.context = context; if (!Platform.isAndroid) { SCTts.show('Google Play payment is only available on Android'); return; } if (!_isAvailable || _products.isEmpty || productMap.isEmpty) { await initializePaymentProcessor(context); } if (!_isAvailable) { return; } final product = _findFirstRechargeProduct( rechargeAmountCents: rechargeAmountCents, productPackage: productPackage, ); if (product == null) { SCTts.show('No matching Google Play product was found'); return; } for (final item in _products) { item.isSelecte = identical(item, product); } notifyListeners(); await _goBuy(product.produc); } SelecteProductConfig? _findFirstRechargeProduct({ required int rechargeAmountCents, required String productPackage, }) { final targetProduct = productPackage.trim(); if (targetProduct.isNotEmpty) { for (final product in _products) { if (product.produc.id == targetProduct) { return product; } } } if (rechargeAmountCents <= 0) { return null; } for (final product in _products) { final config = productMap[product.produc.id]; if (_matchesAmountCents(config?.unitPrice, rechargeAmountCents)) { return product; } if (_matchesAmountCents(product.produc.rawPrice, rechargeAmountCents)) { return product; } } return null; } bool _matchesAmountCents(num? value, int targetCents) { if (value == null) { return false; } final cents = value >= 20 ? value.round() : (value * 100).round(); return (cents - targetCents).abs() <= 1; } // 处理购买结果 void _handlePurchase(List purchases) { _purchases = purchases; for (var purchase in purchases) { switch (purchase.status) { case PurchaseStatus.purchased: _verifyPayment(purchase); break; case PurchaseStatus.error: if (purchase.error != null) { _handleIAPError(purchase.error!); // 特别处理 "item-already-owned" 错误 if (purchase.error!.code == 'item-already-owned') { _handleAlreadyOwnedItem(purchase); } } break; case PurchaseStatus.pending: break; case PurchaseStatus.restored: // 处理恢复的购买 _verifyPayment(purchase, forceSubmit: true); break; default: break; } } notifyListeners(); } // 新增:处理已拥有商品的情况 Future _handleAlreadyOwnedItem(PurchaseDetails purchase) async { final profileManager = Provider.of( context, listen: false, ); final firstRechargeManager = Provider.of( context, listen: false, ); try { await reconcilePendingGooglePurchases(force: true, showToast: true); profileManager.balance(); _refreshFirstRechargeRewardState(firstRechargeManager); } catch (e) { debugPrint('handle already-owned purchase failed: $e'); } } // 验证支付凭证 Future _verifyPayment( PurchaseDetails purchase, { bool forceSubmit = false, bool showToast = true, }) async { final profileManager = Provider.of( context, listen: false, ); final firstRechargeManager = Provider.of( context, listen: false, ); try { // 1. 基本验证 if (purchase.verificationData.serverVerificationData.isEmpty) { _errorMessage = '无效的支付凭证'; if (showToast) { SCTts.show("Invalid payment voucher"); } return; } // 2. 正常购买流依赖 pendingCompletePurchase;启动/回前台补偿流需要允许 // 已确认但仍未消费的一次性商品再次上报后端,否则用户付款后退出 App 会漏单。 if (!forceSubmit && !purchase.pendingCompletePurchase) { return; } final purchaseKey = purchase.purchaseID ?? purchase.verificationData.serverVerificationData; if (purchaseKey.isNotEmpty && !_verifyingPurchaseKeys.add(purchaseKey)) { return; } // 3. 获取购买数据 String purchaseData = purchase.verificationData.localVerificationData; String signature = ""; if (purchase is GooglePlayPurchaseDetails) { signature = purchase.billingClientPurchase.signature; } // 4. 服务器验证 await _submitGooglePayVerification( purchase.productID, signature, purchaseData, ); // 5. 交付商品 await _deliverProduct(purchase.productID); // 6. 完成购买 await iap.completePurchase(purchase); // 7. 如果是消耗型商品,确保消耗 if (_getProductType(purchase.productID) == 'consumable') { await _ensurePurchaseConsumed(purchase); } // 8. 更新用户余额 profileManager.fetchUserProfileData(); profileManager.balance(); _refreshFirstRechargeRewardState(firstRechargeManager); if (showToast) { SCTts.show('purchase successful'); } } catch (e) { if (showToast) { SCTts.show("verification failed: $e"); } _errorMessage = '验证失败: ${e.toString()}'; } finally { final purchaseKey = purchase.purchaseID ?? purchase.verificationData.serverVerificationData; if (purchaseKey.isNotEmpty) { _verifyingPurchaseKeys.remove(purchaseKey); } SCLoadingManager.hide(); notifyListeners(); } } Future reconcilePendingGooglePurchases({ BuildContext? context, bool force = false, bool showToast = false, }) async { if (!Platform.isAndroid) { return; } if (context != null) { this.context = context; } if (_isReconcilingPastPurchases) { return; } final lastCheck = _lastPastPurchaseReconcileAt; if (!force && lastCheck != null && DateTime.now().difference(lastCheck) < const Duration(seconds: 20)) { return; } _isReconcilingPastPurchases = true; _lastPastPurchaseReconcileAt = DateTime.now(); try { _ensurePurchaseStreamListener(); _isAvailable = await iap.isAvailable(); if (!_isAvailable) { return; } final InAppPurchaseAndroidPlatformAddition androidAddition = iap.getPlatformAddition(); final response = await androidAddition.queryPastPurchases(); if (response.error != null) { debugPrint('query past google purchases failed: ${response.error}'); return; } final purchases = response.pastPurchases.where((purchase) { final isPurchased = purchase.status == PurchaseStatus.purchased || purchase.status == PurchaseStatus.restored; final productType = _getProductType(purchase.productID); final isUnacknowledged = purchase.pendingCompletePurchase || !purchase.billingClientPurchase.isAcknowledged; // Google 只会返回未消费的一次性商品;即使它已确认,也说明仍可补上报后端。 return isPurchased && (isUnacknowledged || productType == 'consumable'); }).toList(); if (purchases.isEmpty) { return; } _purchases = purchases; for (final purchase in purchases) { await _verifyPayment(purchase, forceSubmit: true, showToast: showToast); } } catch (e) { debugPrint('reconcile pending google purchases failed: $e'); } finally { _isReconcilingPastPurchases = false; notifyListeners(); } } Future _submitGooglePayVerification( String product, String signature, String purchaseData, ) async { const api = 'order/purchase-pay/google'; final paramsForLog = { 'product': product, 'signature': _clipForDebugLog(signature), 'purchaseData': _clipForDebugLog(purchaseData), }; if (kDebugMode) { debugPrint('[GooglePay] request api=$api params=$paramsForLog'); } final result = await SCConfigRepositoryImp().googlePay( product, signature, purchaseData, ); if (kDebugMode) { debugPrint('[GooglePay] response api=$api result=${result.toJson()}'); } return result; } String _clipForDebugLog(String value) { if (value.length <= 240) { return value; } return '${value.substring(0, 120)}...${value.substring(value.length - 80)}'; } // 交付商品 Future _deliverProduct(String productId) async { // 实现您的业务逻辑 // 例如:增加用户余额、解锁功能等 } void _refreshFirstRechargeRewardState(SCAppGeneralManager manager) { try { unawaited(manager.refreshFirstRechargeRewardHome(forceRefresh: true)); } catch (error) { if (kDebugMode) { debugPrint('[FirstRecharge][payment] refresh state failed: $error'); } } } // 新增:确保购买被消耗 Future _ensurePurchaseConsumed(PurchaseDetails purchase) async { try { // 等待一段时间确保购买完成 await Future.delayed(Duration(seconds: 1)); // 尝试消耗购买 await consumePurchase(purchase); } catch (e) { debugPrint('consume purchase failed: $e'); } } void _handleError(Object error, StackTrace stackTrace) { SCTts.show("Payment error: $error"); if (error is IAPError) { // 处理IAP特定错误 _handleIAPError(error); } else { // 处理其他类型的错误 _errorMessage = '未知错误: ${error.toString()}'; SCTts.show(_errorMessage); } } // 添加了专门的IAP错误处理方法 void _handleIAPError(IAPError error) { _errorMessage = '支付错误: ${error.message} (${error.code})'; // 处理特定错误代码 switch (error.code) { case 'payment-invalid': SCTts.show( 'Payment configuration error, please contact customer service', ); break; case 'item-already-owned': SCTts.show('Unfinished purchase detected, processing...'); break; case 'user-cancelled': SCTts.show('Purchase cancelled'); break; case 'service-timeout': case 'service-unavailable': SCTts.show( 'Google Play services are temporarily unavailable, please try again later', ); break; default: SCTts.show('Payment failed: ${error.message}'); break; } SCLoadingManager.hide(); notifyListeners(); } // 恢复购买 Future recoverTransactions() async { try { SCLoadingManager.show(context: context); notifyListeners(); await iap.restorePurchases(); // 给恢复操作一些时间 await Future.delayed(Duration(milliseconds: 1000)); } catch (e) { _errorMessage = '恢复购买失败: ${e.toString()}'; SCTts.show("Failed to restore purchase: ${e.toString()}"); } finally { SCLoadingManager.hide(); notifyListeners(); } } // 消耗型商品手动消耗 Future consumePurchase(PurchaseDetails purchase) async { try { if (Platform.isAndroid) { final InAppPurchaseAndroidPlatformAddition androidAddition = iap.getPlatformAddition(); await androidAddition.consumePurchase(purchase); } } catch (e) { _errorMessage = '消耗商品失败: ${e.toString()}'; } } // 购买流程 Future _goBuy(ProductDetails product) async { try { SCLoadingManager.show(context: context); notifyListeners(); // 购买前检查是否有未完成的购买 await _checkPendingPurchases(); final PurchaseParam purchaseParam = PurchaseParam( productDetails: product, applicationUserName: null, ); String productType = _getProductType(product.id); bool success; if (productType == 'consumable') { success = await iap.buyConsumable( purchaseParam: purchaseParam, autoConsume: false, ); } else { success = await iap.buyNonConsumable(purchaseParam: purchaseParam); } if (!success) { _errorMessage = '购买启动失败,请检查网络连接'; SCTts.show(_errorMessage); } } catch (e) { SCTts.show("Purchase failed: $e"); _errorMessage = '购买失败: ${e.toString()}'; } finally { SCLoadingManager.hide(); notifyListeners(); } } // 新增:检查未完成的购买 Future _checkPendingPurchases() async { try { await reconcilePendingGooglePurchases(); // 恢复购买以获取所有未完成交易 await iap.restorePurchases(); // 给一点时间处理恢复的购买 await Future.delayed(Duration(milliseconds: 550)); } catch (e) { debugPrint('check pending purchases failed: $e'); } } // 添加调试方法 void logCurrentPurchaseStatus() { debugPrint('current purchase count: ${_purchases.length}'); } // 释放资源 @override void dispose() { _subscription?.cancel(); super.dispose(); } void chooseProductConfig(int index) { for (var v in _products) { v.isSelecte = false; } _products[index].isSelecte = true; notifyListeners(); } }