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:yumi/services/auth/user_profile_manager.dart'; import 'package:provider/provider.dart'; import 'package:yumi/shared/tools/sc_loading_manager.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:yumi/app_localizations.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_product_config_res.dart'; import 'package:yumi/modules/wallet/recharge/recharge_page.dart'; import '../../shared/data_sources/models/enum/sc_erro_code.dart'; class IOSPaymentProcessor extends ChangeNotifier { StreamSubscription>? _subscription; final InAppPurchase iap = InAppPurchase.instance; // 只复制必要的状态变量 bool _isAvailable = false; String _errorMessage = ''; List _products = []; late BuildContext context; Map productMap = {}; // 公开访问器 bool get isAvailable => _isAvailable; String get errorMessage => _errorMessage; List get products => _products; // 初始化 - 只处理iOS逻辑 Future initializePaymentProcessor(BuildContext context) async { this.context = context; // 如果不是iOS,直接返回 if (!Platform.isIOS) { _errorMessage = 'This provider is for iOS only'; return; } try { SCLoadingManager.show(context: context); // 检查支付是否可用 _isAvailable = await iap.isAvailable(); if (!_isAvailable) { _errorMessage = 'App Store payment service is unavailable'; SCTts.show(_errorMessage); return; } _subscription?.cancel(); // 设置购买流监听 _subscription = iap.purchaseStream.listen( _handlePurchase, onError: (error, stackTrace) => _handleError(error, stackTrace), ); // 获取iOS商品配置 await _loadIOSProductConfig(); // 获取苹果商品信息 await _fetchIOSProducts(); } catch (e) { SCTts.show("Apple Pay init fail: $e"); _errorMessage = 'Apple Pay init fail: ${e.toString()}'; } finally { SCLoadingManager.hide(); notifyListeners(); } } /// 加载iOS商品配置 Future _loadIOSProductConfig() async { productMap.clear(); // 假设你的接口支持按平台获取配置 var productConfigs = await SCConfigRepositoryImp().productConfig(); for (var value in productConfigs) { productMap[value.productPackage!] = value; } notifyListeners(); } // 获取iOS商品信息 Future _fetchIOSProducts() async { try { SCLoadingManager.show(context: context); notifyListeners(); Set productIds = productMap.keys.toSet(); ProductDetailsResponse response = await iap.queryProductDetails( productIds, ); if (response.notFoundIDs.isNotEmpty) { _errorMessage = '未找到商品: ${response.notFoundIDs.join(', ')}'; debugPrint(_errorMessage); } var details = response.productDetails; // 保持你的排序逻辑 if (details.isNotEmpty) { // 这里可以添加iOS特定的排序逻辑 } _products.clear(); for (var v in details) { _products.add(SelecteProductConfig(v, _products.isEmpty)); // 第一个选中 } } catch (e) { SCTts.show("Failed to retrieve iOS products: $e"); _errorMessage = 'Failed to get iOS goods: ${e.toString()}'; debugPrint(_errorMessage); } finally { SCLoadingManager.hide(); notifyListeners(); } } // 发起iOS购买 Future processPurchase() async { ProductDetails? product; _products.forEach((d) { 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: () { _goIOSBuy(product!); }, ); }, ); } // iOS购买流程 void _goIOSBuy(ProductDetails product) async { try { SCLoadingManager.show(); notifyListeners(); final PurchaseParam purchaseParam = PurchaseParam( productDetails: product, applicationUserName: null, ); // iOS统一使用buyNonConsumable,但实际类型由App Store Connect配置决定 bool success = await iap.buyConsumable(purchaseParam: purchaseParam); if (!success) { _errorMessage = 'If the purchase fails to start, check your network connection'; SCTts.show(_errorMessage); } } catch (e) { SCTts.show("iOS Purchase failed: $e"); _errorMessage = 'iOS purchase failed: ${e.toString()}'; debugPrint(_errorMessage); } finally { SCLoadingManager.hide(); notifyListeners(); } } // 处理iOS购买结果 void _handlePurchase(List purchases) { for (var purchase in purchases) { switch (purchase.status) { case PurchaseStatus.purchased: _verifyIOSPayment(purchase); break; case PurchaseStatus.error: if (purchase.error != null) { _handleIOSError(purchase.error!); } break; case PurchaseStatus.pending: debugPrint('iOS支付处理中: ${purchase.productID}'); SCTts.show('Payment is being processed, please wait...'); break; case PurchaseStatus.restored: // SmartDialog.show( // tag: "showConfirmDialog", // alignment: Alignment.center, // animationType: SmartAnimationType.fade, // builder: (_) { // return MsgDialog( // title: SCAppLocalizations.of(context)!.tips, // msg: SCAppLocalizations.of(context)!.restorePurchasesTips, // btnText: SCAppLocalizations.of(context)!.confirm, // onEnsure: () { // // }, // ); // }, // ); _verifyIOSPayment(purchase); // 恢复的购买也需要验证 break; case PurchaseStatus.canceled: break; } } notifyListeners(); } // 验证iOS支付 Future _verifyIOSPayment(PurchaseDetails purchase) async { SCLoadingManager.show(); try { String receiptData = purchase.verificationData.serverVerificationData; if (receiptData.isEmpty) { receiptData = purchase.verificationData.localVerificationData; } // iOS验证 - 使用服务器收据验证 try { await SCConfigRepositoryImp().applePay( purchase.productID, receiptData, purchase.purchaseID ?? "", ); // 🔥 iOS关键:必须完成交易 await iap.completePurchase(purchase); // 更新用户信息 Provider.of(context, listen: false).fetchUserProfileData(); Provider.of(context, listen: false).balance(); SCTts.show('Purchase is successful!'); debugPrint('iOS购买成功: ${purchase.productID}'); } catch (e) { if (e.toString().endsWith("${SCErroCode.orderExistsCreated.code}")) { SCTts.show('The order already exists!'); await iap.completePurchase(purchase); } } } catch (e) { SCTts.show("ios verification fails $e"); _errorMessage = 'iOS verification failed: ${e.toString()}'; debugPrint(_errorMessage); // 即使验证失败,也要完成交易,否则会卡住 if (purchase.pendingCompletePurchase) { await iap.completePurchase(purchase); } } finally { SCLoadingManager.hide(); notifyListeners(); } } // 交付商品(与安卓相同) Future _deliverProduct(String productId) async { debugPrint('交付iOS商品: $productId'); // 使用相同的业务逻辑 } // iOS错误处理 void _handleIOSError(IAPError error) { _errorMessage = 'iOS payment error: ${error.message} (${error.code})'; switch (error.code) { case 'SKErrorPaymentCancelled': SCTts.show('the purchase has been canceled'); break; case 'SKErrorPaymentNotAllowed': SCTts.show('the device does not support in app purchases'); break; default: SCTts.show('ios payment failed: ${error.message}'); break; } debugPrint(_errorMessage); SCLoadingManager.hide(); notifyListeners(); } void _handleError(Object error, StackTrace stackTrace) { if (error is IAPError) { _handleIOSError(error); } else { _errorMessage = 'iOS Unknown Error: ${error.toString()}'; SCTts.show(_errorMessage); } } // iOS恢复购买 Future recoverTransactions() async { try { SCLoadingManager.show(context: context); notifyListeners(); SCTts.show('recovering ios purchases...'); await iap.restorePurchases(); } catch (e) { _errorMessage = 'Failed to restore iOS purchases: ${e.toString()}'; SCTts.show(_errorMessage); } finally { SCLoadingManager.hide(); notifyListeners(); } } void chooseProductConfig(int index) { for (var v in _products) { v.isSelecte = false; } _products[index].isSelecte = true; notifyListeners(); } @override void dispose() { _subscription?.cancel(); super.dispose(); } }