chatapp3-flutter/lib/services/payment/google_payment_manager.dart
2026-04-09 21:32:23 +08:00

497 lines
15 KiB
Dart

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: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_product_config_res.dart';
import 'package:yumi/modules/wallet/recharge/recharge_page.dart';
class AndroidPaymentProcessor extends ChangeNotifier {
StreamSubscription<List<PurchaseDetails>>? _subscription;
final InAppPurchase iap = InAppPurchase.instance;
// 状态管理变量
bool _isAvailable = false;
String _errorMessage = '';
List<SelecteProductConfig> _products = [];
List<PurchaseDetails> _purchases = [];
///商品列表
List<SCProductConfigRes> productConfigs = [];
// 维护商品类型映射
final Map<String, String> _productTypeMap = {};
// 公开访问器
bool get isAvailable => _isAvailable;
String get errorMessage => _errorMessage;
List<SelecteProductConfig> get products => _products;
List<PurchaseDetails> get purchases => _purchases;
late BuildContext context;
Map<String, SCProductConfigRes> productMap = {};
Map<String, String> productTypes = {};
// 初始化支付系统
Future<void> 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;
}
_subscription?.cancel();
// 设置购买流监听
_subscription = iap.purchaseStream.listen(
_handlePurchase,
onError: (error, stackTrace) => _handleError(error, stackTrace),
);
// 先获取商品配置
await fetchProductConfiguration();
// 然后获取谷歌商品信息
await _fetchProducts();
// 最后恢复购买,处理未完成交易
await recoverTransactions();
} catch (e) {
SCTts.show("init fail: $e");
_errorMessage = 'init fail: ${e.toString()}';
} finally {
SCLoadingManager.hide();
notifyListeners();
}
}
///用户获取商店配置的商品列表
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<void> _fetchProducts() async {
try {
SCLoadingManager.show(context: context);
notifyListeners();
Set<String> productIds = productTypes.keys.toSet();
ProductDetailsResponse response = await iap.queryProductDetails(
productIds,
);
if (response.notFoundIDs.isNotEmpty) {
_errorMessage = '未找到商品: ${response.notFoundIDs.join(', ')}';
debugPrint(_errorMessage);
}
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'; // 默认类型
}
}
// 打印商品信息用于调试
for (var product in _products) {
debugPrint(
'商品: ${product.produc.id}, 类型: ${_productTypeMap[product.produc.id]}, 价格: ${product.produc.price}',
);
}
} catch (e) {
SCTts.show("Failed to retrieve the product: $e");
_errorMessage = '获取商品失败: ${e.toString()}';
debugPrint(_errorMessage);
} finally {
SCLoadingManager.hide();
notifyListeners();
}
}
// 获取商品类型
String _getProductType(String productId) {
return _productTypeMap[productId] ?? 'nonConsumable';
}
// 发起购买
Future<void> 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: () {
_goBuy(product!);
},
);
},
);
}
// 处理购买结果
void _handlePurchase(List<PurchaseDetails> 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:
debugPrint('支付处理中: ${purchase.productID}');
break;
case PurchaseStatus.restored:
// 处理恢复的购买
_verifyPayment(purchase);
break;
default:
break;
}
}
notifyListeners();
}
// 新增:处理已拥有商品的情况
Future<void> _handleAlreadyOwnedItem(PurchaseDetails purchase) async {
try {
debugPrint('检测到已拥有商品: ${purchase.productID},尝试消耗');
// 如果是消耗型商品,尝试消耗
if (_getProductType(purchase.productID) == 'consumable') {
await consumePurchase(purchase);
// 消耗后重新获取余额
Provider.of<SocialChatUserProfileManager>(context, listen: false).balance();
SCTts.show('outstanding purchases have been reinstated');
}
} catch (e) {
debugPrint('处理已拥有商品失败: $e');
}
}
// 验证支付凭证
Future<void> _verifyPayment(PurchaseDetails purchase) async {
try {
// 1. 基本验证
if (purchase.verificationData.serverVerificationData.isEmpty) {
_errorMessage = '无效的支付凭证';
SCTts.show("Invalid payment voucher");
return;
}
// 2. 检查是否已经处理过这个购买
if (!purchase.pendingCompletePurchase) {
debugPrint('购买已处理过: ${purchase.productID}');
return;
}
// 3. 获取购买数据
String purchaseData = purchase.verificationData.localVerificationData;
String signature = "";
if (purchase is GooglePlayPurchaseDetails) {
signature = purchase.billingClientPurchase.signature;
}
// 4. 服务器验证
await SCConfigRepositoryImp().googlePay(
purchase.productID,
signature,
purchaseData,
);
// 5. 交付商品
await _deliverProduct(purchase.productID);
// 6. 完成购买
await iap.completePurchase(purchase);
// 7. 如果是消耗型商品,确保消耗
if (_getProductType(purchase.productID) == 'consumable') {
await _ensurePurchaseConsumed(purchase);
}
// 8. 更新用户余额
Provider.of<SocialChatUserProfileManager>(context, listen: false).fetchUserProfileData();
Provider.of<SocialChatUserProfileManager>(context, listen: false).balance();
SCTts.show('purchase successful');
debugPrint('购买成功: ${purchase.productID}');
} catch (e) {
SCTts.show("verification failed: $e");
_errorMessage = '验证失败: ${e.toString()}';
debugPrint(_errorMessage);
} finally {
SCLoadingManager.hide();
notifyListeners();
}
}
// 交付商品
Future<void> _deliverProduct(String productId) async {
debugPrint('交付商品: $productId');
// 实现您的业务逻辑
// 例如:增加用户余额、解锁功能等
}
// 新增:确保购买被消耗
Future<void> _ensurePurchaseConsumed(PurchaseDetails purchase) async {
try {
// 等待一段时间确保购买完成
await Future.delayed(Duration(seconds: 1));
// 尝试消耗购买
await consumePurchase(purchase);
debugPrint('商品已成功消耗: ${purchase.productID}');
} catch (e) {
debugPrint('消耗商品失败,可能已自动消耗: $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':
debugPrint('支付无效: 商品ID可能配置错误');
SCTts.show(
'Payment configuration error, please contact customer service',
);
break;
case 'item-already-owned':
debugPrint('商品已拥有,尝试消耗商品');
SCTts.show('Unfinished purchase detected, processing...');
break;
case 'user-cancelled':
debugPrint('用户取消购买');
SCTts.show('Purchase cancelled');
break;
case 'service-timeout':
case 'service-unavailable':
debugPrint('Google Play服务不可用');
SCTts.show(
'Google Play services are temporarily unavailable, please try again later',
);
break;
default:
SCTts.show('Payment failed: ${error.message}');
break;
}
debugPrint(_errorMessage);
SCLoadingManager.hide();
notifyListeners();
}
// 恢复购买
Future<void> recoverTransactions() async {
try {
SCLoadingManager.show(context: context);
notifyListeners();
await iap.restorePurchases();
// 给恢复操作一些时间
await Future.delayed(Duration(milliseconds: 1000));
} catch (e) {
_errorMessage = '恢复购买失败: ${e.toString()}';
debugPrint(_errorMessage);
SCTts.show("Failed to restore purchase: ${e.toString()}");
} finally {
SCLoadingManager.hide();
notifyListeners();
}
}
// 消耗型商品手动消耗
Future<void> consumePurchase(PurchaseDetails purchase) async {
try {
if (Platform.isAndroid) {
final InAppPurchaseAndroidPlatformAddition androidAddition =
iap.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>();
await androidAddition.consumePurchase(purchase);
debugPrint('已消耗商品: ${purchase.productID}');
}
} catch (e) {
_errorMessage = '消耗商品失败: ${e.toString()}';
debugPrint(_errorMessage);
}
}
// 购买流程
void _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: kReleaseMode, // 生产环境自动消耗,调试时手动控制
);
} else {
success = await iap.buyNonConsumable(purchaseParam: purchaseParam);
}
if (!success) {
_errorMessage = '购买启动失败,请检查网络连接';
SCTts.show(_errorMessage);
}
} catch (e) {
SCTts.show("Purchase failed: $e");
_errorMessage = '购买失败: ${e.toString()}';
debugPrint(_errorMessage);
} finally {
SCLoadingManager.hide();
notifyListeners();
}
}
// 新增:检查未完成的购买
Future<void> _checkPendingPurchases() async {
try {
// 恢复购买以获取所有未完成交易
await iap.restorePurchases();
// 给一点时间处理恢复的购买
await Future.delayed(Duration(milliseconds: 550));
} catch (e) {
debugPrint('检查未完成购买时出错: $e');
}
}
// 添加调试方法
void logCurrentPurchaseStatus() {
debugPrint('=== 当前购买状态 ===');
debugPrint('可用商品数量: ${_products.length}');
debugPrint('未完成购买数量: ${_purchases.length}');
for (var purchase in _purchases) {
debugPrint('商品: ${purchase.productID}, 状态: ${purchase.status}');
debugPrint('待完成: ${purchase.pendingCompletePurchase}');
}
debugPrint('==================');
}
// 释放资源
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
void chooseProductConfig(int index) {
for (var v in _products) {
v.isSelecte = false;
}
_products[index].isSelecte = true;
notifyListeners();
}
}