删除storkit 1

This commit is contained in:
2025-12-16 14:29:47 +08:00
parent f10ddd9a31
commit c898d16688
15 changed files with 1 additions and 727 deletions

View File

@@ -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 */,

View File

@@ -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];

View File

@@ -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);
}]; }];

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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 则表示跳转到你的 AppIAP 继续完成交易,如果返回 false 则表示推迟或者取消购买,实际开发中因为可能还需要用户登录自己的账号、生成订单等,一般都是返回 false之后通过 FGIAPService 的. -tryShouldAddStorePayments 在合适的时机触发。
*/
- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product API_AVAILABLE(ios(11.0));
@end
NS_ASSUME_NONNULL_END

View File

@@ -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

View File

@@ -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