删除storkit 1
This commit is contained in:
@@ -132,10 +132,6 @@
|
|||||||
0498BDDE2EE81508006CC1D5 /* KBShopVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDDD2EE81508006CC1D5 /* KBShopVM.m */; };
|
0498BDDE2EE81508006CC1D5 /* KBShopVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDDD2EE81508006CC1D5 /* KBShopVM.m */; };
|
||||||
0498BDE12EEA87C9006CC1D5 /* KBShopStyleModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */; };
|
0498BDE12EEA87C9006CC1D5 /* KBShopStyleModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */; };
|
||||||
0498BDE42EEA885D006CC1D5 /* KBShopThemeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE32EEA885D006CC1D5 /* KBShopThemeModel.m */; };
|
0498BDE42EEA885D006CC1D5 /* KBShopThemeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE32EEA885D006CC1D5 /* KBShopThemeModel.m */; };
|
||||||
0498BDF02EEC0E56006CC1D5 /* FGIAPManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE72EEC0E56006CC1D5 /* FGIAPManager.m */; };
|
|
||||||
0498BDF12EEC0E56006CC1D5 /* FGIAPProductsFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE92EEC0E56006CC1D5 /* FGIAPProductsFilter.m */; };
|
|
||||||
0498BDF22EEC0E56006CC1D5 /* NSObject+FGIsNullOrEmpty.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDEF2EEC0E56006CC1D5 /* NSObject+FGIsNullOrEmpty.m */; };
|
|
||||||
0498BDF32EEC0E56006CC1D5 /* FGIAPService.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDEB2EEC0E56006CC1D5 /* FGIAPService.m */; };
|
|
||||||
0498BDF52EEC50EE006CC1D5 /* emoji_categories.json in Resources */ = {isa = PBXBuildFile; fileRef = 0498BDF42EEC50EE006CC1D5 /* emoji_categories.json */; };
|
0498BDF52EEC50EE006CC1D5 /* emoji_categories.json in Resources */ = {isa = PBXBuildFile; fileRef = 0498BDF42EEC50EE006CC1D5 /* emoji_categories.json */; };
|
||||||
049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; };
|
049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; };
|
||||||
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; };
|
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; };
|
||||||
@@ -449,16 +445,6 @@
|
|||||||
0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopStyleModel.m; sourceTree = "<group>"; };
|
0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopStyleModel.m; sourceTree = "<group>"; };
|
||||||
0498BDE22EEA885D006CC1D5 /* KBShopThemeModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBShopThemeModel.h; sourceTree = "<group>"; };
|
0498BDE22EEA885D006CC1D5 /* KBShopThemeModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBShopThemeModel.h; sourceTree = "<group>"; };
|
||||||
0498BDE32EEA885D006CC1D5 /* KBShopThemeModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopThemeModel.m; sourceTree = "<group>"; };
|
0498BDE32EEA885D006CC1D5 /* KBShopThemeModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopThemeModel.m; sourceTree = "<group>"; };
|
||||||
0498BDE62EEC0E56006CC1D5 /* FGIAPManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FGIAPManager.h; sourceTree = "<group>"; };
|
|
||||||
0498BDE72EEC0E56006CC1D5 /* FGIAPManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FGIAPManager.m; sourceTree = "<group>"; };
|
|
||||||
0498BDE82EEC0E56006CC1D5 /* FGIAPProductsFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FGIAPProductsFilter.h; sourceTree = "<group>"; };
|
|
||||||
0498BDE92EEC0E56006CC1D5 /* FGIAPProductsFilter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FGIAPProductsFilter.m; sourceTree = "<group>"; };
|
|
||||||
0498BDEA2EEC0E56006CC1D5 /* FGIAPService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FGIAPService.h; sourceTree = "<group>"; };
|
|
||||||
0498BDEB2EEC0E56006CC1D5 /* FGIAPService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FGIAPService.m; sourceTree = "<group>"; };
|
|
||||||
0498BDEC2EEC0E56006CC1D5 /* FGIAPServiceUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FGIAPServiceUtility.h; sourceTree = "<group>"; };
|
|
||||||
0498BDED2EEC0E56006CC1D5 /* FGIAPVerifyTransaction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FGIAPVerifyTransaction.h; sourceTree = "<group>"; };
|
|
||||||
0498BDEE2EEC0E56006CC1D5 /* NSObject+FGIsNullOrEmpty.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+FGIsNullOrEmpty.h"; sourceTree = "<group>"; };
|
|
||||||
0498BDEF2EEC0E56006CC1D5 /* NSObject+FGIsNullOrEmpty.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+FGIsNullOrEmpty.m"; sourceTree = "<group>"; };
|
|
||||||
0498BDF42EEC50EE006CC1D5 /* emoji_categories.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = emoji_categories.json; sourceTree = "<group>"; };
|
0498BDF42EEC50EE006CC1D5 /* emoji_categories.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = emoji_categories.json; sourceTree = "<group>"; };
|
||||||
049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; };
|
049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; };
|
||||||
049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; };
|
049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; };
|
||||||
@@ -693,23 +679,6 @@
|
|||||||
path = VM;
|
path = VM;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
04122F6C2EC5F40800EF7AB3 /* FGIAPService */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
0498BDE62EEC0E56006CC1D5 /* FGIAPManager.h */,
|
|
||||||
0498BDE72EEC0E56006CC1D5 /* FGIAPManager.m */,
|
|
||||||
0498BDE82EEC0E56006CC1D5 /* FGIAPProductsFilter.h */,
|
|
||||||
0498BDE92EEC0E56006CC1D5 /* FGIAPProductsFilter.m */,
|
|
||||||
0498BDEA2EEC0E56006CC1D5 /* FGIAPService.h */,
|
|
||||||
0498BDEB2EEC0E56006CC1D5 /* FGIAPService.m */,
|
|
||||||
0498BDEC2EEC0E56006CC1D5 /* FGIAPServiceUtility.h */,
|
|
||||||
0498BDED2EEC0E56006CC1D5 /* FGIAPVerifyTransaction.h */,
|
|
||||||
0498BDEE2EEC0E56006CC1D5 /* NSObject+FGIsNullOrEmpty.h */,
|
|
||||||
0498BDEF2EEC0E56006CC1D5 /* NSObject+FGIsNullOrEmpty.m */,
|
|
||||||
);
|
|
||||||
path = FGIAPService;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
04122F7D2EC5FC5500EF7AB3 /* V */ = {
|
04122F7D2EC5FC5500EF7AB3 /* V */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -988,7 +957,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
04122F862EC6198C00EF7AB3 /* WMDragView */,
|
04122F862EC6198C00EF7AB3 /* WMDragView */,
|
||||||
04122F6C2EC5F40800EF7AB3 /* FGIAPService */,
|
|
||||||
049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */,
|
049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */,
|
||||||
048908D92EBF61AF00FABA60 /* UICollectionViewLeftAlignedLayout */,
|
048908D92EBF61AF00FABA60 /* UICollectionViewLeftAlignedLayout */,
|
||||||
047920592EDEE1FC004E8522 /* CRBoxInputView */,
|
047920592EDEE1FC004E8522 /* CRBoxInputView */,
|
||||||
@@ -2000,10 +1968,6 @@
|
|||||||
0479205F2EDEE1FC004E8522 /* CRBoxInputCellProperty.m in Sources */,
|
0479205F2EDEE1FC004E8522 /* CRBoxInputCellProperty.m in Sources */,
|
||||||
047920602EDEE1FC004E8522 /* CRLineView.m in Sources */,
|
047920602EDEE1FC004E8522 /* CRLineView.m in Sources */,
|
||||||
047C65502EBCBA9E0035E841 /* KBShopVC.m in Sources */,
|
047C65502EBCBA9E0035E841 /* KBShopVC.m in Sources */,
|
||||||
0498BDF02EEC0E56006CC1D5 /* FGIAPManager.m in Sources */,
|
|
||||||
0498BDF12EEC0E56006CC1D5 /* FGIAPProductsFilter.m in Sources */,
|
|
||||||
0498BDF22EEC0E56006CC1D5 /* NSObject+FGIsNullOrEmpty.m in Sources */,
|
|
||||||
0498BDF32EEC0E56006CC1D5 /* FGIAPService.m in Sources */,
|
|
||||||
0477BE042EBC83130055D639 /* HomeMainVC.m in Sources */,
|
0477BE042EBC83130055D639 /* HomeMainVC.m in Sources */,
|
||||||
0477BDFD2EBC6A170055D639 /* HomeHotVC.m in Sources */,
|
0477BDFD2EBC6A170055D639 /* HomeHotVC.m in Sources */,
|
||||||
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */,
|
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */,
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
#import "KBULBridgeNotification.h" // Darwin 通知常量:用于通知扩展“UL已处理”
|
#import "KBULBridgeNotification.h" // Darwin 通知常量:用于通知扩展“UL已处理”
|
||||||
#import "LSTPopView.h"
|
#import "LSTPopView.h"
|
||||||
#import "KBLoginPopView.h"
|
#import "KBLoginPopView.h"
|
||||||
#import "IAPVerifyTransactionObj.h"
|
|
||||||
#import "FGIAPManager.h"
|
|
||||||
#import "KBSexSelVC.h"
|
#import "KBSexSelVC.h"
|
||||||
#import "KBKeyboardPermissionManager.h"
|
#import "KBKeyboardPermissionManager.h"
|
||||||
#import "KBVipPay.h"
|
#import "KBVipPay.h"
|
||||||
@@ -41,13 +39,6 @@
|
|||||||
/// 2 : 处理token问题(包括卸载重装场景下的 token 清理)
|
/// 2 : 处理token问题(包括卸载重装场景下的 token 清理)
|
||||||
[[KBUserSessionManager shared] bootstrapIfNeeded];
|
[[KBUserSessionManager shared] bootstrapIfNeeded];
|
||||||
|
|
||||||
/// 3:如果当前已经是登录状态,则在启动时初始化一次内购服务。
|
|
||||||
/// 对于“首次登录”的场景,会在登录成功(见 KBLoginVM)后再进行一次配置。
|
|
||||||
if ([KBUserSessionManager shared].isLoggedIn) {
|
|
||||||
// [[FGIAPManager shared] setConfigureWith:[IAPVerifyTransactionObj new]];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 首次安装/升级:重置“完全访问”记录,避免继承旧安装遗留在 Keychain 中的状态
|
// 首次安装/升级:重置“完全访问”记录,避免继承旧安装遗留在 Keychain 中的状态
|
||||||
static NSString *const kKBFullAccessRecordInitializedKey = @"KBFullAccessRecordInitialized";
|
static NSString *const kKBFullAccessRecordInitializedKey = @"KBFullAccessRecordInitialized";
|
||||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
#import "AppleSignInManager.h"
|
#import "AppleSignInManager.h"
|
||||||
#import "KBNetworkManager.h"
|
#import "KBNetworkManager.h"
|
||||||
#import "KBAuthManager.h"
|
#import "KBAuthManager.h"
|
||||||
#import "FGIAPManager.h"
|
|
||||||
#import "IAPVerifyTransactionObj.h"
|
|
||||||
#import "KBAPI.h"
|
#import "KBAPI.h"
|
||||||
#import "KBUser.h"
|
#import "KBUser.h"
|
||||||
#import "KBMyVM.h"
|
#import "KBMyVM.h"
|
||||||
@@ -19,14 +17,6 @@
|
|||||||
|
|
||||||
@implementation KBLoginVM
|
@implementation KBLoginVM
|
||||||
|
|
||||||
/// 统一初始化内购(只执行一次)。既可以在“启动时已登录”的场景调用,也可以在“登录成功回调”里调用。
|
|
||||||
+ (void)kb_configureIAPIfNeeded {
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
// [[FGIAPManager shared] setConfigureWith:[IAPVerifyTransactionObj new]];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)shared {
|
+ (instancetype)shared {
|
||||||
static KBLoginVM *vm; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ vm = [KBLoginVM new]; });
|
static KBLoginVM *vm; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ vm = [KBLoginVM new]; });
|
||||||
return vm;
|
return vm;
|
||||||
@@ -76,7 +66,6 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[[KBUserSessionManager shared] handleLoginSuccessWithUser:user];
|
[[KBUserSessionManager shared] handleLoginSuccessWithUser:user];
|
||||||
[KBLoginVM kb_configureIAPIfNeeded];
|
|
||||||
[self kb_syncKeyboardCharactersAfterLogin];
|
[self kb_syncKeyboardCharactersAfterLogin];
|
||||||
if (completion) completion(YES, nil);
|
if (completion) completion(YES, nil);
|
||||||
// 保存登录态到共享钥匙串;供 App 与扩展共享
|
// 保存登录态到共享钥匙串;供 App 与扩展共享
|
||||||
@@ -113,7 +102,6 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[[KBUserSessionManager shared] handleLoginSuccessWithUser:user];
|
[[KBUserSessionManager shared] handleLoginSuccessWithUser:user];
|
||||||
[KBLoginVM kb_configureIAPIfNeeded];
|
|
||||||
[self kb_syncKeyboardCharactersAfterLogin];
|
[self kb_syncKeyboardCharactersAfterLogin];
|
||||||
if (completion) completion(YES, nil);
|
if (completion) completion(YES, nil);
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -4,14 +4,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <StoreKit/StoreKit.h>
|
|
||||||
#import "FGIAPVerifyTransaction.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSNotificationName const KBIAPDidCompletePurchaseNotification;
|
FOUNDATION_EXPORT NSNotificationName const KBIAPDidCompletePurchaseNotification;
|
||||||
|
|
||||||
@interface IAPVerifyTransactionObj : NSObject <FGIAPVerifyTransaction>
|
@interface IAPVerifyTransactionObj : NSObject
|
||||||
|
|
||||||
/// 校验票据(StoreKit 2 入口)
|
/// 校验票据(StoreKit 2 入口)
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
|
|
||||||
#import "IAPVerifyTransactionObj.h"
|
#import "IAPVerifyTransactionObj.h"
|
||||||
#import "PayVM.h"
|
#import "PayVM.h"
|
||||||
#import "KBAuthManager.h"
|
|
||||||
#import "KBHUD.h"
|
|
||||||
//#import "KBLoginSheetViewController.h"
|
|
||||||
#import "KBBizCode.h"
|
#import "KBBizCode.h"
|
||||||
|
|
||||||
NSNotificationName const KBIAPDidCompletePurchaseNotification = @"KBIAPDidCompletePurchaseNotification";
|
NSNotificationName const KBIAPDidCompletePurchaseNotification = @"KBIAPDidCompletePurchaseNotification";
|
||||||
@@ -69,115 +66,4 @@ NSNotificationName const KBIAPDidCompletePurchaseNotification = @"KBIAPDidComple
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - FGIAPVerifyTransaction
|
|
||||||
|
|
||||||
- (void)pushSuccessTradeReultToServer:(NSString *)receipt
|
|
||||||
transaction:(SKPaymentTransaction *)transaction
|
|
||||||
complete:(FGIAPVerifyTransactionPushCallBack)handler {
|
|
||||||
if (![self checkLogin]) { return; }
|
|
||||||
|
|
||||||
KBLOG(@"receipt = %@", receipt);
|
|
||||||
KBLOG(@"transactionId = %@, originalId = %@", transaction.transactionIdentifier,transaction.originalTransaction.transactionIdentifier);
|
|
||||||
#if DEBUG
|
|
||||||
// [self kb_debugLogReceipt:receipt transaction:transaction];
|
|
||||||
#endif
|
|
||||||
#if DEBUG
|
|
||||||
// [self kb_debugLogReceipt:receipt transaction:transaction];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
__weak typeof(self) weakSelf = self;
|
|
||||||
[KBHUD showWithStatus:@"请稍等..."];
|
|
||||||
[self verifyReceipt:receipt completion:^(BOOL success, NSString * _Nullable message, NSInteger statusCode) {
|
|
||||||
__strong typeof(weakSelf) self = weakSelf;
|
|
||||||
(void)self;
|
|
||||||
if (success) {
|
|
||||||
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
|
||||||
[KBHUD showInfo:@"Success"];
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBIAPDidCompletePurchaseNotification object:nil];
|
|
||||||
if (handler) handler(KBLocalized(@"Success"), nil);
|
|
||||||
} else if (statusCode == KBBizCodeReceiptError) {
|
|
||||||
[KBHUD dismiss];
|
|
||||||
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
|
||||||
} else {
|
|
||||||
[KBHUD showError:message ?: KBLocalized(@"Failed")];
|
|
||||||
if (handler) handler(message ?: KBLocalized(@"Failed"), nil);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Helpers
|
|
||||||
|
|
||||||
- (BOOL)checkLogin {
|
|
||||||
BOOL loggedIn = [[KBUserSessionManager shared] isLoggedIn];
|
|
||||||
if (!loggedIn) {
|
|
||||||
[[KBUserSessionManager shared] goLoginVC];
|
|
||||||
}
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
- (void)kb_debugLogReceipt:(NSString *)receipt transaction:(SKPaymentTransaction *)transaction {
|
|
||||||
if (![receipt isKindOfClass:[NSString class]] || receipt.length == 0) {
|
|
||||||
KBLOG(@"[IAPVerifyTransactionObj] debug receipt empty");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NSURL *url = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
|
|
||||||
if (!url) { return; }
|
|
||||||
|
|
||||||
NSDictionary *payload = @{ @"receipt-data": receipt, @"exclude-old-transactions": @NO };
|
|
||||||
NSError *jsonError = nil;
|
|
||||||
NSData *body = [NSJSONSerialization dataWithJSONObject:payload options:0 error:&jsonError];
|
|
||||||
if (jsonError || !body) {
|
|
||||||
KBLOG(@"[IAPVerifyTransactionObj] debug receipt json error: %@", jsonError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
|
||||||
request.HTTPMethod = @"POST";
|
|
||||||
request.HTTPBody = body;
|
|
||||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
|
||||||
request.timeoutInterval = 30;
|
|
||||||
|
|
||||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
|
||||||
if (error) {
|
|
||||||
KBLOG(@"[IAPVerifyTransactionObj] debug receipt request error: %@", error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (data.length == 0) {
|
|
||||||
KBLOG(@"[IAPVerifyTransactionObj] debug receipt empty response");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSError *parseError = nil;
|
|
||||||
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
|
|
||||||
if (!json || parseError) {
|
|
||||||
KBLOG(@"[IAPVerifyTransactionObj] debug receipt parse error: %@", parseError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSNumber *status = json[@"status"];
|
|
||||||
KBLOG(@"[IAPVerifyTransactionObj] receipt status: %@, env transaction: %@ / %@", status, transaction.transactionIdentifier, transaction.originalTransaction.transactionIdentifier);
|
|
||||||
|
|
||||||
void (^logEntries)(NSArray *entries, NSString *label) = ^(NSArray *entries, NSString *label) {
|
|
||||||
for (NSDictionary *item in entries) {
|
|
||||||
KBLOG(@"[IAPVerifyTransactionObj][%@] product:%@ transaction:%@ original:%@ purchase_date:%@", label, item[@"product_id"], item[@"transaction_id"], item[@"original_transaction_id"], item[@"purchase_date"]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
NSArray *latestInfos = json[@"latest_receipt_info"];
|
|
||||||
if ([latestInfos isKindOfClass:[NSArray class]] && latestInfos.count > 0) {
|
|
||||||
logEntries(latestInfos, @"latest_receipt_info");
|
|
||||||
}
|
|
||||||
|
|
||||||
NSDictionary *receiptDict = json[@"receipt"];
|
|
||||||
NSArray *inAppInfos = receiptDict[@"in_app"];
|
|
||||||
if ([inAppInfos isKindOfClass:[NSArray class]] && inAppInfos.count > 0) {
|
|
||||||
logEntries(inAppInfos, @"receipt.in_app");
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
[task resume];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPManager.h
|
|
||||||
// MaltBaby
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2020/5/11.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import "FGIAPService.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface FGIAPManager : NSObject
|
|
||||||
|
|
||||||
/// FGIAPService
|
|
||||||
@property (nonatomic, strong, readonly) FGIAPService *iap;
|
|
||||||
|
|
||||||
/// Initialize
|
|
||||||
+ (FGIAPManager *)shared;
|
|
||||||
|
|
||||||
/// Configure a server validation object
|
|
||||||
/// @param verifyTransaction a server validation object
|
|
||||||
- (void)setConfigureWith:(id<FGIAPVerifyTransaction>)verifyTransaction;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPManager.m
|
|
||||||
// MaltBaby
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2020/5/11.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "FGIAPManager.h"
|
|
||||||
|
|
||||||
@implementation FGIAPManager
|
|
||||||
|
|
||||||
+ (FGIAPManager *)shared{
|
|
||||||
static FGIAPManager *manager = nil;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
manager = [[FGIAPManager alloc] init];
|
|
||||||
});
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setConfigureWith:(id<FGIAPVerifyTransaction>)verifyTransaction{
|
|
||||||
self->_iap = [[FGIAPService alloc] initWithTransaction:verifyTransaction];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPProductsFilter.h
|
|
||||||
// MaltBaby
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2021/5/8.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <StoreKit/StoreKit.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
typedef void(^FGIAPManagerResponseBlock)(NSArray<SKProduct *> * products);
|
|
||||||
|
|
||||||
@interface FGIAPProductsFilter : NSObject
|
|
||||||
|
|
||||||
/// 获取苹果内购商品列表
|
|
||||||
/// @param productIdentifiers 商品id列表
|
|
||||||
/// @param completion completion
|
|
||||||
- (void)requestProductsWith:(NSSet *)productIdentifiers completion:(nonnull FGIAPManagerResponseBlock)completion;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPProductsFilter.m
|
|
||||||
// MaltBaby
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2021/5/8.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "FGIAPProductsFilter.h"
|
|
||||||
#import "FGIAPServiceUtility.h"
|
|
||||||
|
|
||||||
@interface FGIAPProductsFilter ()<SKProductsRequestDelegate>
|
|
||||||
@property (nonatomic,strong) SKProductsRequest *request;
|
|
||||||
@property (nonatomic, copy) FGIAPManagerResponseBlock requestProductsBlock;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation FGIAPProductsFilter
|
|
||||||
|
|
||||||
- (void)requestProductsWith:(NSSet *)productIdentifiers completion:(nonnull FGIAPManagerResponseBlock)completion{
|
|
||||||
|
|
||||||
if (productIdentifiers.count==0) {
|
|
||||||
if (completion) completion([NSArray array]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
|
|
||||||
self.request.delegate = self;
|
|
||||||
self.requestProductsBlock = completion;
|
|
||||||
[self.request start];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - SKProductsRequestDelegate
|
|
||||||
|
|
||||||
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
|
|
||||||
NSArray *products = [response.products sortedArrayUsingComparator:^NSComparisonResult(SKProduct *obj1, SKProduct *obj2) {
|
|
||||||
return obj1.price.doubleValue < obj2.price.doubleValue ? NSOrderedAscending : NSOrderedDescending;
|
|
||||||
}];
|
|
||||||
if(_requestProductsBlock) {
|
|
||||||
_requestProductsBlock(products);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPManager.h
|
|
||||||
// MaltBaby
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2020/5/7.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <StoreKit/StoreKit.h>
|
|
||||||
#import "FGIAPVerifyTransaction.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, FGIAPManagerPurchaseRusult) {
|
|
||||||
FGIAPManagerPurchaseRusultSuccess = 0, //内购成功
|
|
||||||
FGIAPManagerPurchaseRusultHalfSuccess, //苹果扣款成功,但是验签接口失败了
|
|
||||||
FGIAPManagerPurchaseRusultFail, //内购失败
|
|
||||||
FGIAPManagerPurchaseRusultCancel //用户取消
|
|
||||||
};
|
|
||||||
typedef void(^FGIAPManagerBuyBlock)(NSString *message, FGIAPManagerPurchaseRusult result);
|
|
||||||
|
|
||||||
@interface FGIAPService : NSObject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化支付对象
|
|
||||||
* @param verifyTransaction 一般得到苹果服务器返回的支付结果后,需要通过<verifyTransaction>再次向服务器进行二次确认,来保证整个支付链路闭环
|
|
||||||
*/
|
|
||||||
- (instancetype)initWithTransaction:(id<FGIAPVerifyTransaction>)verifyTransaction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* iap支付
|
|
||||||
* @param product 对应的商品
|
|
||||||
* @param completion 支付回调
|
|
||||||
*/
|
|
||||||
- (void)buyProduct:(SKProduct *)product onCompletion:(FGIAPManagerBuyBlock)completion;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在合适的时间处理从App Store下载页面触发的内购行为
|
|
||||||
*/
|
|
||||||
- (void)tryShouldAddStorePayments;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPManager.m
|
|
||||||
// MaltBaby
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2020/5/7.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "FGIAPService.h"
|
|
||||||
#import "FGIAPServiceUtility.h"
|
|
||||||
#import "NSObject+FGIsNullOrEmpty.h"
|
|
||||||
|
|
||||||
static NSMutableDictionary *FGIAPServiceErrorMapsFromTransaction (SKPaymentTransaction *transaction) {
|
|
||||||
NSMutableDictionary *errorMaps = [NSMutableDictionary dictionary];
|
|
||||||
[errorMaps setValue:transaction.transactionIdentifier?:@"" forKey:@"transactionIdentifier"];
|
|
||||||
[errorMaps setValue:transaction.originalTransaction.transactionIdentifier?:@"" forKey:@"originalTransaction.transactionIdentifier"];
|
|
||||||
[errorMaps setValue:transaction.payment.applicationUsername?:@"" forKey:@"applicationUsername"];
|
|
||||||
[errorMaps setValue:transaction.payment.productIdentifier?:@"" forKey:@"productIdentifier"];
|
|
||||||
return errorMaps;
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface FGIAPService () <SKPaymentTransactionObserver, SKRequestDelegate>
|
|
||||||
@property (nonatomic, strong) id<FGIAPVerifyTransaction> verifyTransaction;
|
|
||||||
@property (nonatomic, copy) FGIAPManagerBuyBlock buyProductCompleteBlock;
|
|
||||||
@property (nonatomic, strong) NSString *productIdentifier;
|
|
||||||
@property (nonatomic, strong) SKPayment *APPStorePayment;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation FGIAPService
|
|
||||||
|
|
||||||
- (instancetype)initWithTransaction:(id<FGIAPVerifyTransaction>)verifyTransaction{
|
|
||||||
if (self = [super init]) {
|
|
||||||
|
|
||||||
_verifyTransaction = verifyTransaction;
|
|
||||||
|
|
||||||
if ([SKPaymentQueue defaultQueue]) {
|
|
||||||
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)buyProduct:(SKProduct *)product onCompletion:(nonnull FGIAPManagerBuyBlock)completion{
|
|
||||||
|
|
||||||
if (![SKPaymentQueue canMakePayments]) {
|
|
||||||
completion(@"Failed to obtain the internal purchase permission", FGIAPManagerPurchaseRusultFail);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ([product.productIdentifier isNSStringAndNotEmpty]) {
|
|
||||||
_productIdentifier = product.productIdentifier;
|
|
||||||
_buyProductCompleteBlock = completion;
|
|
||||||
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
|
|
||||||
if ([SKPaymentQueue defaultQueue]) {
|
|
||||||
[[SKPaymentQueue defaultQueue] addPayment:payment];
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
completion(@"The selected payment does not exist", FGIAPManagerPurchaseRusultFail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tryShouldAddStorePayments{
|
|
||||||
if (_APPStorePayment && [SKPaymentQueue defaultQueue]) {
|
|
||||||
[[SKPaymentQueue defaultQueue] addPayment:self.APPStorePayment];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - SKPaymentTransactionObserver
|
|
||||||
|
|
||||||
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
|
|
||||||
FGLog(@"%s %ld", __func__, [SKPaymentQueue defaultQueue].transactions.count);
|
|
||||||
if (![[SKPaymentQueue defaultQueue].transactions isNSArrayAndNotEmpty]) {
|
|
||||||
/// all transactions finished
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
|
|
||||||
{
|
|
||||||
for (SKPaymentTransaction *transaction in transactions)
|
|
||||||
{
|
|
||||||
switch (transaction.transactionState)
|
|
||||||
{
|
|
||||||
case SKPaymentTransactionStatePurchasing:
|
|
||||||
FGLog(@"Add an payment to the list");
|
|
||||||
break;
|
|
||||||
case SKPaymentTransactionStatePurchased:
|
|
||||||
FGLog(@"Customer paid successfully");
|
|
||||||
[self completeTransaction:transaction retryWhenreceiptURLisEmpty:YES];
|
|
||||||
break;
|
|
||||||
case SKPaymentTransactionStateRestored:
|
|
||||||
FGLog(@"The transaction has been recovered from the user's purchase history");
|
|
||||||
[self completeTransaction:transaction retryWhenreceiptURLisEmpty:YES];
|
|
||||||
break;
|
|
||||||
case SKPaymentTransactionStateFailed:
|
|
||||||
FGLog(@"Failure of commodity transaction");
|
|
||||||
[self failedTransaction:transaction withError:FGIAPServiceErrorTypeNone];
|
|
||||||
break;
|
|
||||||
case SKPaymentTransactionStateDeferred:
|
|
||||||
FGLog(@"Merchandise is suspended");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
///
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product API_AVAILABLE(ios(11.0)){
|
|
||||||
BOOL shouldAddStorePayment = NO;
|
|
||||||
if (_verifyTransaction && [_verifyTransaction respondsToSelector:@selector(paymentQueue:shouldAddStorePayment:forProduct:)]) {
|
|
||||||
shouldAddStorePayment = [_verifyTransaction paymentQueue:queue shouldAddStorePayment:payment forProduct:product];
|
|
||||||
}
|
|
||||||
if (shouldAddStorePayment == NO) {
|
|
||||||
_APPStorePayment = payment;
|
|
||||||
}
|
|
||||||
return shouldAddStorePayment;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - SKRequestDelegate
|
|
||||||
|
|
||||||
- (void)requestDidFinish:(SKRequest *)request{
|
|
||||||
if ([request isKindOfClass:[SKReceiptRefreshRequest class]]) {
|
|
||||||
SKReceiptRefreshRequest *RefreshRequest = (SKReceiptRefreshRequest *)request;
|
|
||||||
SKPaymentTransaction *transaction = [RefreshRequest.receiptProperties valueForKey:@"transaction"];
|
|
||||||
if (transaction) {
|
|
||||||
[self completeTransaction:transaction retryWhenreceiptURLisEmpty:NO];
|
|
||||||
}else{
|
|
||||||
[self failedTransaction:transaction withError:FGIAPServiceErrorTypeReceiptNotExist];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)request:(SKRequest *)request didFailWithError:(nonnull NSError *)error{
|
|
||||||
if ([request isKindOfClass:[SKReceiptRefreshRequest class]]) {
|
|
||||||
SKReceiptRefreshRequest *RefreshRequest = (SKReceiptRefreshRequest *)request;
|
|
||||||
SKPaymentTransaction *transaction = [RefreshRequest.receiptProperties valueForKey:@"transaction"];
|
|
||||||
[self failedTransaction:transaction withError:FGIAPServiceErrorTypeReceiptNotExist];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - private method
|
|
||||||
|
|
||||||
- (void)completeTransaction:(SKPaymentTransaction *)transaction retryWhenreceiptURLisEmpty:(BOOL)retry{
|
|
||||||
FGLog(@"%s %@ %@", __func__, transaction.transactionIdentifier, transaction.originalTransaction.transactionIdentifier);
|
|
||||||
|
|
||||||
if (![transaction.transactionIdentifier isNSStringAndNotEmpty]) {
|
|
||||||
[self failedTransaction:transaction withError:FGIAPServiceErrorTypeTransactionIdentifierNotExist];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
|
|
||||||
if ([[NSFileManager defaultManager] fileExistsAtPath:receiptURL.path]) {
|
|
||||||
|
|
||||||
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
|
|
||||||
NSString *receiptDataText = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
|
|
||||||
[self checkReceipt:receiptDataText withTransaction:transaction handler:nil];
|
|
||||||
|
|
||||||
}else if (retry){
|
|
||||||
|
|
||||||
SKReceiptRefreshRequest *receiptRefreshRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{@"transaction":transaction}];
|
|
||||||
receiptRefreshRequest.delegate = self;
|
|
||||||
[receiptRefreshRequest start];
|
|
||||||
|
|
||||||
}else{
|
|
||||||
[self failedTransaction:transaction withError:FGIAPServiceErrorTypeReceiptNotExist];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)failedTransaction:(SKPaymentTransaction *)transaction withError:(FGIAPServiceErrorType)error{
|
|
||||||
FGLog(@"%s Transaction error:%@ code:%ld", __func__, transaction.error.localizedDescription, transaction.error.code);
|
|
||||||
|
|
||||||
BOOL finish = error == FGIAPServiceErrorTypeNone;
|
|
||||||
|
|
||||||
if (finish && [SKPaymentQueue defaultQueue]) {
|
|
||||||
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSMutableDictionary *logStatistics = [NSMutableDictionary dictionaryWithDictionary:FGIAPServiceErrorMapsFromTransaction(transaction)];
|
|
||||||
if (self.verifyTransaction && [self.verifyTransaction respondsToSelector:@selector(pushServiceErrorLogStatistics:error:)]) {
|
|
||||||
[logStatistics setValue:@(error) forKey:@"error"];
|
|
||||||
[self.verifyTransaction pushServiceErrorLogStatistics:logStatistics error:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_buyProductCompleteBlock) {
|
|
||||||
FGIAPManagerPurchaseRusult result = FGIAPManagerPurchaseRusultHalfSuccess;
|
|
||||||
if (error == FGIAPServiceErrorTypeNone) {
|
|
||||||
result = transaction.error.code == SKErrorPaymentCancelled ? FGIAPManagerPurchaseRusultCancel : FGIAPManagerPurchaseRusultFail;
|
|
||||||
}
|
|
||||||
_buyProductCompleteBlock(transaction.error.localizedDescription, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- (void)checkReceipt:(NSString *)receipt withTransaction:(SKPaymentTransaction *)transaction handler:(FGIAPVerifyTransactionBlock)handler{
|
|
||||||
|
|
||||||
WS(wSelf);
|
|
||||||
if (_verifyTransaction && [_verifyTransaction respondsToSelector:@selector(pushSuccessTradeReultToServer:transaction:complete:)]) {
|
|
||||||
[_verifyTransaction pushSuccessTradeReultToServer:receipt transaction:transaction complete:^(NSString * _Nonnull message, NSError * _Nullable requestErr) {
|
|
||||||
|
|
||||||
//polling verify transaction
|
|
||||||
if (requestErr && requestErr.code != FGIAPServerOverdueErrorCode) {
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
||||||
[wSelf checkReceipt:receipt withTransaction:transaction handler:handler];
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[wSelf finishTransaction:transaction result: FGIAPManagerPurchaseRusultSuccess message:message];
|
|
||||||
}];
|
|
||||||
}else{
|
|
||||||
NSAssert(NO, @"You must configure the method: - pushSuccessTradeReultToServer:transaction:complete:");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)finishTransaction:(SKPaymentTransaction *)transaction result:(FGIAPManagerPurchaseRusult)result message:(NSString *)msg{
|
|
||||||
|
|
||||||
FGLog(@"%s finishTransaction:%@", __func__, transaction.transactionIdentifier);
|
|
||||||
|
|
||||||
if ([SKPaymentQueue defaultQueue]) {
|
|
||||||
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction.originalTransaction == nil && [transaction.payment.productIdentifier isEqualToString:self.productIdentifier]) {
|
|
||||||
self.productIdentifier = nil;
|
|
||||||
if (_buyProductCompleteBlock) {
|
|
||||||
_buyProductCompleteBlock(msg, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPServiceUtility.h
|
|
||||||
// Pods
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2021/5/10.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef FGIAPServiceUtility_h
|
|
||||||
#define FGIAPServiceUtility_h
|
|
||||||
|
|
||||||
#define FGDEBUG
|
|
||||||
|
|
||||||
#if defined (FGDEBUG) && defined (DEBUG)
|
|
||||||
#define FGLog(...) NSLog(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define FGLog(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define WS(wSelf) __weak typeof(self) wSelf = self
|
|
||||||
#define FGIAPServerOverdueErrorCode 11000007 //预留code:订单提交无效,需要删除本地的订单
|
|
||||||
|
|
||||||
#endif /* FGIAPServiceUtility_h */
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
//
|
|
||||||
// FGIAPVerifyTransaction.h
|
|
||||||
// MaltBaby
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2021/5/8.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <StoreKit/StoreKit.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, FGIAPVerifyTransactionRusult) {
|
|
||||||
FGIAPManagerVerifyRusultCREATED = 0,
|
|
||||||
FGIAPManagerVerifyRusultFail,
|
|
||||||
FGIAPManagerVerifyRusultSuccess,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, FGIAPServiceErrorType) {
|
|
||||||
FGIAPServiceErrorTypeNone,
|
|
||||||
///Failed to validate receipt
|
|
||||||
FGIAPServiceErrorTypeTransactionIdentifierNotExist,
|
|
||||||
///No matching receipt data was found
|
|
||||||
FGIAPServiceErrorTypeReceiptNotExist,
|
|
||||||
///Failed to validate receipt
|
|
||||||
FGIAPServiceErrorTypeVerifyTradeFail,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void(^FGIAPVerifyTransactionBlock)(NSString *message, FGIAPVerifyTransactionRusult result);
|
|
||||||
typedef void(^FGIAPVerifyTransactionPushCallBack)(NSString *message, NSError * _Nullable result);
|
|
||||||
|
|
||||||
@protocol FGIAPVerifyTransaction <NSObject>
|
|
||||||
|
|
||||||
/// 苹果支付流程结束后,需要根据返回的票据等数据去自己的服务器校验
|
|
||||||
/// @param receipt 票据
|
|
||||||
/// @param transaction 支付事务
|
|
||||||
/// @param handler 检验回调
|
|
||||||
- (void)pushSuccessTradeReultToServer:(NSString *)receipt transaction:(SKPaymentTransaction *)transaction complete:(FGIAPVerifyTransactionPushCallBack)handler;
|
|
||||||
|
|
||||||
|
|
||||||
@optional
|
|
||||||
|
|
||||||
/// 推送失败日志
|
|
||||||
/// @param logStatistics 日志
|
|
||||||
- (void)pushServiceErrorLogStatistics:(NSDictionary *)logStatistics error:(FGIAPServiceErrorType)error;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Promoting In-App Purchases
|
|
||||||
|
|
||||||
用户如果在 App下载页面点击购买你推广的内购商品,如果用户已经安装过你的 App 则会直接跳转你的App并调用上述代理方法;如果用户还没有安装你的 App 那么就会去下载你的 App,下载完成之后系统会推送一个通知,如果用户点击该通知就会跳转到你的App并且调用上面的代理方法
|
|
||||||
|
|
||||||
上面的代理方法返回 true 则表示跳转到你的 App,IAP 继续完成交易,如果返回 false 则表示推迟或者取消购买,实际开发中因为可能还需要用户登录自己的账号、生成订单等,一般都是返回 false,之后通过 FGIAPService 的. -tryShouldAddStorePayments 在合适的时机触发。
|
|
||||||
*/
|
|
||||||
- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product API_AVAILABLE(ios(11.0));
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
//
|
|
||||||
// NSObject+FGIsNullOrEmpty.h
|
|
||||||
// FGIAPService
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2021/5/10.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface NSObject (FGIsNullOrEmpty)
|
|
||||||
|
|
||||||
- (BOOL)isNSStringAndNotEmpty;
|
|
||||||
- (BOOL)isNSArrayAndNotEmpty;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
//
|
|
||||||
// NSObject+FGIsNullOrEmpty.m
|
|
||||||
// FGIAPService
|
|
||||||
//
|
|
||||||
// Created by FoneG on 2021/5/10.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "NSObject+FGIsNullOrEmpty.h"
|
|
||||||
|
|
||||||
@implementation NSObject (FGIsNullOrEmpty)
|
|
||||||
|
|
||||||
- (BOOL)isNSStringAndNotEmpty
|
|
||||||
{
|
|
||||||
if (nil == self) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ([self isKindOfClass:[NSString class]]) {
|
|
||||||
NSString *str = (NSString*)self;
|
|
||||||
str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
||||||
if ([str isEqualToString:@"<null>"]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ([str isEqualToString:@"(null)"]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (str.length == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if ([self isKindOfClass:[NSAttributedString class]]) {
|
|
||||||
NSString *str = ((NSAttributedString *)self).string;
|
|
||||||
str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
||||||
if (str.length > 0) {
|
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)isNSArrayAndNotEmpty
|
|
||||||
{
|
|
||||||
if ([self isKindOfClass:[NSArray class]]) {
|
|
||||||
NSArray *temp = (NSArray *)self;
|
|
||||||
if (temp.count > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
Reference in New Issue
Block a user