Files
peko-ios/YuMi/Modules/YMMine/View/Recharge/IAPManager.m

440 lines
16 KiB
Mathematica
Raw Normal View History

2024-09-24 18:01:08 +08:00
//
// IAPManager.m
// YuMi
//
// Created by P on 2024/9/24.
//
#import "IAPManager.h"
#import "Api+Mine.h"
#import "YuMi-swift.h"
#import "RechargeStorage.h"
@interface IAPManager()
2024-09-27 11:17:04 +08:00
@property (nonatomic, assign) BOOL isLogin;
@property (nonatomic, assign) NSInteger recheckInterval;
@property (nonatomic, assign) NSInteger recheckIndex;
@property (nonatomic, strong) NSTimer *recheckTimer;
@property (nonatomic, assign) BOOL isProcessing;
2024-09-24 18:01:08 +08:00
@property (nonatomic, copy) NSString *orderID;
@property (nonatomic, copy) NSString *transactionID;
2024-09-27 11:17:04 +08:00
@property (nonatomic, copy) void(^successPurchase)(NSString *transactionID, NSString *orderID);
@property (nonatomic, copy) void(^successRecheck)(void);
2024-09-24 18:01:08 +08:00
@property (nonatomic, copy) void(^failurePurchase)(NSError *error);
@property (nonatomic, copy) void(^contactCustomerService)(NSString *uid);
@end
@implementation IAPManager
+ (instancetype)sharedManager {
static IAPManager *proxy;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
proxy = [[self alloc] init];
2024-09-27 11:17:04 +08:00
proxy.recheckIndex = 0;
proxy.recheckInterval = 1.0;
2024-09-24 18:01:08 +08:00
});
return proxy;
}
2024-09-27 11:17:04 +08:00
- (void)handleLogin {
self.isLogin = YES;
}
- (void)handleLogout {
self.isLogin = NO;
if (self.recheckTimer) {
[self.recheckTimer invalidate];
}
}
//
2024-09-24 18:01:08 +08:00
- (void)purchase:(NSString *)productId
2024-09-27 11:17:04 +08:00
success:(void(^)(NSString *transactionID, NSString *orderID))success
2024-09-24 18:01:08 +08:00
failure:(void(^)(NSError *error))failure
contactCS:(void(^)(NSString *uid))contactCS {
self.successPurchase = success;
self.failurePurchase = failure;
self.contactCustomerService = contactCS;
[self handleIAPState];
2024-09-27 11:17:04 +08:00
[self requestAPPOrderData:productId isFroRecheck:NO];
}
//
- (void)retryCheckAllReceipt {
self.recheckTimer = [NSTimer scheduledTimerWithTimeInterval:self.recheckInterval
target:self
selector:@selector(handleRetryCheckReceipt)
userInfo:nil
repeats:NO];
}
//
- (void)handleRetryCheckReceipt {
NSArray *array = [RechargeStorage getAllReceiptsWithUid:[AccountInfoStorage instance].getUid];
NSLog(@" ------------.------------ 尝试:%@", array);
@synchronized (array) {
if (array.count == 0 || self.isProcessing) {
return;
}
if (!self.isLogin) {
return;
}
if (self.recheckIndex >= array.count) {
self.recheckIndex = 0;
}
//
[self requestAPPOrderData:@"com.hflighting.yumi.gold.1_7000" isFroRecheck:YES];
self.isProcessing = YES;
NSDictionary *dic = [array xpSafeObjectAtIndex:self.recheckIndex];
NSString *transactionId = dic[@"transactionId"];
[self backgroundCheckReceiptWithTransactionID:transactionId
orderID:dic[@"orderId"]
next:^(BOOL isSuccess){
if (isSuccess) {
[RechargeStorage delegateTransactionId:transactionId
uid:[AccountInfoStorage instance].getUid];
self.recheckInterval = 1.0;
} else {
self.recheckInterval = self.recheckInterval * 2;
}
self.recheckIndex += 1;
self.isProcessing = NO;
[self.recheckTimer invalidate];
[self retryCheckAllReceipt];
}];
}
2024-09-24 18:01:08 +08:00
}
2024-09-27 11:17:04 +08:00
//
- (void)handleSuccessPurchase:(NSString *)tID order:(NSString *)orderID {
2024-09-24 18:01:08 +08:00
if (self.successPurchase) {
@kWeakify(self);
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
2024-09-27 11:17:04 +08:00
self.successPurchase(tID, orderID);
});
}
if (self.successRecheck) {
@kWeakify(self);
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
self.successRecheck();
2024-09-24 18:01:08 +08:00
});
}
}
2024-09-27 11:17:04 +08:00
//
2024-09-24 18:01:08 +08:00
- (void)handleFailurePurchase:(NSString *)errorMsg {
if (self.failurePurchase) {
@kWeakify(self);
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
if (errorMsg.length == 0) {
self.failurePurchase(nil);
} else {
self.failurePurchase([NSError errorWithDomain:errorMsg code:-1 userInfo:nil]);
}
});
}
}
2024-09-27 11:17:04 +08:00
//
2024-09-24 18:01:08 +08:00
- (void)handleContactCS {
@kWeakify(self);
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
TTAlertConfig *config = [[TTAlertConfig alloc]init];
config.title = YMLocalizedString(@"XPIAPRechargeViewController7");
config.message = YMLocalizedString(@"XPIAPRechargeViewController8");
TTAlertButtonConfig *confirmButtonConfig = [[TTAlertButtonConfig alloc]init];
confirmButtonConfig.title = YMLocalizedString(@"XPIAPRechargeViewController9");
UIImage *image = [UIImage gradientColorImageFromColors:@[UIColorFromRGB(0x13E2F5),UIColorFromRGB(0x9DB4FF),UIColorFromRGB(0xCC67FF)] gradientType:GradientTypeLeftToRight imgSize:CGSizeMake(200, 200)];
confirmButtonConfig.backgroundColor = [UIColor colorWithPatternImage:image];
confirmButtonConfig.cornerRadius = 38/2;
config.confirmButtonConfig = confirmButtonConfig;
@kWeakify(self);
[TTPopup alertWithConfig:config confirmHandler:^{
@kStrongify(self);
[self loadCSUid];
} cancelHandler:^{}];
});
}
2024-09-27 11:17:04 +08:00
// UID
- (void)loadCSUid {
if (self.contactCustomerService) {
[Api requestContactCustomerServiceCompletion:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
if (code == 200) {
NSString *uid = [NSString stringWithFormat:@"%@",data.data];
self.contactCustomerService(uid);
}
}];
}
}
//
2024-09-24 18:01:08 +08:00
- (void)handleIAPState {
if (@available(iOS 15.0, *)) {
@kWeakify(self);
2024-09-27 11:17:04 +08:00
[[PIIAPRegulate shared] setConditionBlock:^(enum StoreConditionResult state, NSDictionary<NSString *,NSString *> * _Nullable param) {
2024-09-24 18:01:08 +08:00
@kStrongify(self);
switch (state) {
case StoreConditionResultStart:
NSLog(@"~~~```~~~ Purchase started");
break;
case StoreConditionResultPay:
NSLog(@"~~~```~~~ Processing payment");
break;
case StoreConditionResultVerifiedServer:
NSLog(@"~~~```~~~ Verified by server");
[self handleIAPSuccess:param];
break;
case StoreConditionResultUserCancelled:
NSLog(@"~~~```~~~ User cancelled purchase");
[self handleFailurePurchase:@""];
break;
case StoreConditionResultNoProduct:
NSLog(@"~~~```~~~ No product found");
[self handleFailurePurchase:[NSString stringWithFormat:@"%@ No product found", YMLocalizedString(@"XPIAPRechargeViewController1")]];
break;
case StoreConditionResultFailedVerification:
NSLog(@"~~~```~~~ Verification failed");
[self handleFailurePurchase:YMLocalizedString(@"XPIAPRechargeViewController1")];
break;
case StoreConditionResultUnowned:
NSLog(@"~~~```~~~ Result Unowned");
[self handleFailurePurchase:YMLocalizedString(@"XPIAPRechargeViewController1")];
break;
default:
[self handleFailurePurchase:YMLocalizedString(@"XPIAPRechargeViewController0")];
break;
}
}];
}
}
//
2024-09-27 11:17:04 +08:00
- (void)requestAPPOrderData:(NSString *)productId isFroRecheck:(BOOL)isFroRecheck {
2024-09-24 18:01:08 +08:00
if (@available(iOS 15.0, *)) {
@kWeakify(self);
[Api requestIAPRecharge:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
2024-09-27 11:17:04 +08:00
if (isFroRecheck) {
return;
}
2024-09-24 18:01:08 +08:00
@kStrongify(self);
if (code == 200) {
NSString *orderId = (NSString *)data.data[@"recordId"];
NSString *uuid = (NSString *)data.data[@"appAccountToken"];
[self requestIAPOrder:orderId
productID:productId
uuid:uuid];
} else if (code == 50000) {
[self handleContactCS];
[self handleFailurePurchase:@""];
} else {
[self handleFailurePurchase:msg];
}
}
chargeProdId:productId
uid:[AccountInfoStorage instance].getUid
ticket:[AccountInfoStorage instance].getTicket
deviceInfo:[YYUtility deviceID]
clientIp:[YYUtility ipAddress]];
} else {
[self handleFailurePurchase:YMLocalizedString(@"XPIAPRechargeViewController10")];
}
}
2024-09-27 11:17:04 +08:00
// 线 productID PIIAPRegulate - purchase
2024-09-24 18:01:08 +08:00
- (void)requestIAPOrder:(NSString *)orderID productID:(NSString *)productID uuid:(NSString *)uuid {
self.orderID = orderID;
if (@available(iOS 15.0, *)) {
2024-09-27 11:17:04 +08:00
// @kWeakify(self);
2024-09-24 18:01:08 +08:00
[[PIIAPRegulate shared] demandCommodityThingWithProductId:productID
uuid:uuid
completionHandler:^(NSError * _Nullable error) {
2024-09-27 11:17:04 +08:00
// @kStrongify(self);
2024-09-24 18:01:08 +08:00
if (error) {
// ConditionBlock
}
}];
}
}
//
- (void)handleIAPSuccess:(NSDictionary *)param {
2024-09-27 11:17:04 +08:00
id tid = param[@"transactionId"];
self.transactionID = tid;
2024-09-24 18:01:08 +08:00
if (self.transactionID.length == 0) {
[self handleFailurePurchase:YMLocalizedString(@"XPIAPRechargeViewController1")];
return;
}
[self saveTransactionID];
2024-09-27 11:17:04 +08:00
[self checkReceiptWithTransactionID:self.transactionID
orderID:self.orderID];
2024-09-24 18:01:08 +08:00
}
// id
- (void)saveTransactionID {
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
NSString *encodedReceipt = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
//
NSMutableDictionary *receiptInfo = [NSMutableDictionary dictionary];
// 使
[self addValueIfNotNil:self.transactionID forKey:@"transactionId" toDictionary:receiptInfo];
[self addValueIfNotNil:encodedReceipt forKey:@"receipt" toDictionary:receiptInfo];
[self addValueIfNotNil:self.orderID forKey:@"orderId" toDictionary:receiptInfo];
//
if (receiptInfo.count == 0) {
return;
}
// RechargeStorage
2024-09-27 11:17:04 +08:00
@synchronized (self.transactionID) {
[RechargeStorage saveTransactionId:self.transactionID
receipt:[receiptInfo toJSONString]
uid:[AccountInfoStorage instance].getUid];
}
NSLog(@" ------------.------------ 保存账单内容:%@ ", receiptInfo);
2024-09-24 18:01:08 +08:00
}
//
// MARK:
2024-09-27 11:17:04 +08:00
- (void)checkReceiptWithTransactionID:(NSString *)tID
orderID:(NSString *)orderID {
NSLog(@" ------------.------------ 后端验单:%@ | %@", tID, orderID);
2024-09-24 18:01:08 +08:00
@kWeakify(self);
[Api checkReceipt:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
@kStrongify(self);
if (code == 200) {
2024-09-27 11:17:04 +08:00
[self handleSuccessPurchase:tID order:orderID];
[self handleCheckReceiptSuccess:tID isFromRecheck:NO];
2024-09-24 18:01:08 +08:00
} else {
[self handleFailurePurchase:msg];
if (code == 1444) {
2024-09-27 11:17:04 +08:00
//
2024-09-24 18:01:08 +08:00
}
}
2024-09-27 11:17:04 +08:00
NSLog(@" ------------.------------ 后端验单结果:%@ ",msg);
2024-09-24 18:01:08 +08:00
}
chooseEnv:@"true"
2024-09-27 11:17:04 +08:00
chargeRecordId:orderID
transcationId:tID
2024-09-24 18:01:08 +08:00
uid:[AccountInfoStorage instance].getUid
ticket:[AccountInfoStorage instance].getTicket];
}
2024-09-27 11:17:04 +08:00
//
- (void)backgroundCheckReceiptWithTransactionID:(NSString *)tID
orderID:(NSString *)orderID
next:(void(^)(BOOL isSuccess))next {
NSLog(@" ------------.------------ 尝试后端验单:%@ | %@", tID, orderID);
if (tID.length == 0 || orderID.length == 0) {
//
[self handleCheckReceiptSuccess:tID isFromRecheck:YES];
next(NO);
return;
}
@kWeakify(self);
[Api checkReceipt:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
@kStrongify(self);
if (code == 200) {
[self handleCheckReceiptSuccess:tID isFromRecheck:YES];
} else if (code == 1701) {
//
[self handleCheckReceiptSuccess:tID isFromRecheck:YES];
}
NSLog(@" ------------.------------ 尝试后端验单结果:%ld, %@ ", (long)code, msg);
if (next) {
next(code == 200 || code == 1701);
}
}
chooseEnv:@"true"
chargeRecordId:orderID
transcationId:tID
uid:[AccountInfoStorage instance].getUid
ticket:[AccountInfoStorage instance].getTicket];
}
// transactionID apple
- (void)handleCheckReceiptSuccess:(NSString *)tID
isFromRecheck:(BOOL)isFromRecheck {
2024-09-24 18:01:08 +08:00
if (@available(iOS 15.0, *)) {
@kWeakify(self);
2024-09-27 11:17:04 +08:00
[[PIIAPRegulate shared] verifyBusinessAccomplishWithTransactionID:tID
2024-09-24 18:01:08 +08:00
completionHandler:^(BOOL success, NSError * _Nullable error) {
@kStrongify(self);
if (success) {
2024-09-27 11:17:04 +08:00
NSLog(@" ------------.------------ apple 验单成功");
//
[RechargeStorage delegateTransactionId:tID
uid:[AccountInfoStorage instance].getUid];
2024-09-24 18:01:08 +08:00
} else {
2024-09-27 11:17:04 +08:00
//
NSLog(@" ------------.------------ apple 验单成功:%@ ",error);
if (error == nil) {
// appstore
[RechargeStorage delegateTransactionId:tID
uid:[AccountInfoStorage instance].getUid];
} else {
[self retryCheckAllReceipt];
}
}
if (!isFromRecheck) {
//
self.orderID = @"";
self.transactionID = @"";
2024-09-24 18:01:08 +08:00
}
}];
}
}
2024-09-27 11:17:04 +08:00
- (void)addValueIfNotNil:(id)value
forKey:(NSString *)key
toDictionary:(NSMutableDictionary *)dictionary {
2024-09-24 18:01:08 +08:00
if (value != nil && key != nil) {
dictionary[key] = value;
}
}
@end