feat: 全局监听iap,在home初始化。避免过早处理,升级dart和flutter,支持storekit插件,强制指定storekit2版本

This commit is contained in:
2025-12-17 16:47:35 -08:00
parent 743631c4ce
commit 05d2c71cd0
10 changed files with 271 additions and 161 deletions
@@ -37,6 +37,8 @@ import 'package:flutter/foundation.dart';
import 'package:kaer_with_panels/app/utils/kr_init_log_collector.dart'; // 🔧 新增:导入日志收集器
import 'package:kaer_with_panels/app/utils/kr_latency_tester.dart'; // 🔧 新增:导入真实延迟测试工具
import 'package:kaer_with_panels/app/utils/account_guard.dart';
import 'package:kaer_with_panels/app/services/iap/iap_service.dart';
class KRHomeController extends GetxController with WidgetsBindingObserver {
// 🔧 新增:日志收集器实例
@@ -23,6 +23,7 @@ import 'dart:async';
import 'package:kaer_with_panels/app/model/response/kr_purchase_order_no.dart';
import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart';
import 'package:kaer_with_panels/app/services/iap/iap_pending_order_service.dart';
import 'package:kaer_with_panels/app/services/iap/iap_service.dart';
/// 会员购买控制器
/// 负责处理会员套餐选择、支付方式选择和订阅流程
@@ -55,9 +56,6 @@ class KRPurchaseMembershipController extends GetxController {
/// 当前余额
RxInt _kr_balance = 0.obs;
// -------------------- IAP 全局监听 --------------------
late StreamSubscription<List<PurchaseDetails>> _iapSubscription;
@override
void onInit() async {
super.onInit();
@@ -85,22 +83,11 @@ class KRPurchaseMembershipController extends GetxController {
print('💳 [PurchaseMembership] ❌ 写入调试日志失败: $e');
}
// 初始化 IAP 全局监听
if (Platform.isIOS) {
_iapSubscription = InAppPurchase.instance.purchaseStream.listen(
_handleIapUpdates,
onError: (error) {
print('IAP Stream Error: $error');
},
);
}
kr_initializeData();
}
@override
void onClose() {
_iapSubscription.cancel();
_kr_eventWorker?.dispose();
super.onClose();
}
@@ -461,21 +448,26 @@ class KRPurchaseMembershipController extends GetxController {
print('开始订阅流程,选定支付');
kr_errorMessage.value = '';
// ✅ 仅在 iOS 检查未完成订单
// ✅ 1. iOS 核心拦截:检测本地是否有“挂起”的订单
if (Platform.isIOS) {
final existing = await IAPPendingOrderService.getPendingOrderNo();
if (existing != null && existing.isNotEmpty) {
final existingOrderNo = await IAPPendingOrderService.getPendingOrderNo();
if (existingOrderNo != null && existingOrderNo.isNotEmpty) {
print('🛑 [IAP] 拦截成功:发现未结单 $existingOrderNo');
await HIDialog.show(
title: '存在未完成订单',
message: '检测到未完成订单,需要恢复购买以完成订阅',
confirmText: '恢复购买',
title: '检测到待激活订单',
message: '您有一笔订单已支付成功,但尚未同步会员权益。请点击“立即激活”完成同步',
confirmText: '立即激活',
cancelText: '取消',
barrierDismissible: false,
preventBackDismiss: true,
onConfirm: () {
kr_restorePurchases(); // 恢复未完成订单
// 🚀 调用全局 Service 的重试逻辑
// 这会触发苹果重新推送 PurchaseStream,进而走验证流程
KRIAPService.instance.retryUnfinishedTransactions();
},
);
return; // 等待恢复完成,不再继续发起新订
return; // 🛑 关键:必须 return,阻止创建重复的新订
}
}
@@ -1008,9 +1000,10 @@ class KRPurchaseMembershipController extends GetxController {
// ----------------------------------------------------------------------
// ProductDetails 已成功获取,并已构造 purchaseParam。
// ----------------------------------------------------------------------
await IAPPendingOrderService.setPendingOrderNo(orderNo);
KRCommonUtil.kr_showLoading();
try {
await IAPPendingOrderService.setPendingOrderNo(orderNo);
KRCommonUtil.kr_showLoading();
final result =
await iap.buyNonConsumable(purchaseParam: purchaseParam);
if (!result) {
@@ -1030,67 +1023,6 @@ class KRPurchaseMembershipController extends GetxController {
);
}
// -------------------- IAP 统一处理 --------------------
void _handleIapUpdates(List<PurchaseDetails> purchases) async {
final iap = InAppPurchase.instance;
final pendingOrderNo = await IAPPendingOrderService.getPendingOrderNo();
print('p.pendingOrderNo ${pendingOrderNo}');
if (pendingOrderNo == null || pendingOrderNo.isEmpty) return;
for (final p in purchases) {
print('p.status ${p.status}');
if (p.status == PurchaseStatus.pending) continue;
if (p.status == PurchaseStatus.error) {
if (p.pendingCompletePurchase) await iap.completePurchase(p);
KRCommonUtil.kr_showToast('购买失败');
continue;
}
if (p.status == PurchaseStatus.purchased || p.status == PurchaseStatus.restored) {
KRCommonUtil.kr_showLoading();
bool ok = false;
final either = await _kr_subscribeApi.kr_attachAppleIapTransaction(p.purchaseID!, pendingOrderNo);
either.fold((e) {}, (v) => ok = true);
// if (p.status == PurchaseStatus.purchased) {
//
// either.fold((e) {}, (v) => ok = true);
// } else if (p.status == PurchaseStatus.restored) {
// final either = await _kr_subscribeApi.kr_restoreAppleIapTransaction(p.purchaseID!, pendingOrderNo);
// either.fold((e) {}, (v) => ok = true);
// }
// ❌ 服务端失败,必须给用户反馈
if (!ok) {
KRCommonUtil.kr_hideLoading();
HIDialog.show(
title: '激活失败,请稍后重试',
message: '检测到未完成订单,需要恢复购买以完成订阅。',
confirmText: '恢复购买',
cancelText: '关闭',
barrierDismissible: false,
preventBackDismiss: true,
onConfirm: () {
kr_restorePurchases(); // 恢复未完成订单
},
);
return;
}
if (p.pendingCompletePurchase) await iap.completePurchase(p);
await IAPPendingOrderService.clearPendingOrderNo();
KRCommonUtil.kr_hideLoading();
Get.toNamed(
Routes.KR_ORDER_STATUS,
arguments: {
'order': pendingOrderNo,
'payment_type': 'apple_iap',
'checkout_type': 'ipa',
},
);
}
}
}
Future<void> kr_restorePurchases({bool isShowLoading = true}) async {
print('重试');
@@ -19,6 +19,8 @@ import 'package:kaer_with_panels/app/widgets/swipe/swipe_config.dart';
import 'dart:convert';
import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart';
import '../../../routes/app_pages.dart';
import 'package:kaer_with_panels/app/services/iap/iap_service.dart';
/// 购买会员页面视图
@@ -201,9 +203,9 @@ class KRPurchaseMembershipView extends GetView<KRPurchaseMembershipController>
}
return Center(
child: GestureDetector(
onTap: () {
onTap: () async{
// 异步处理补单
controller.kr_restorePurchases(isShowLoading: false); // 恢复未完成订单
await KRIAPService.instance.retryUnfinishedTransactions();
HIDialog.show(
title: '温馨提示',
message: '购买订单已确认,请耐心等待。若时长未到账,请联系在线客服处理。',