diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index 06ef2bf..7962b58 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 04286A132ECDEBF900CE730C /* KBSkinIconMap.strings in Resources */ = {isa = PBXBuildFile; fileRef = 04286A122ECDEBF900CE730C /* KBSkinIconMap.strings */; }; 043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; }; 0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */; }; + 0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */; }; 0459D1B42EBA284C00F2D189 /* KBSkinCenterVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B32EBA284C00F2D189 /* KBSkinCenterVC.m */; }; 0459D1B72EBA287900F2D189 /* KBSkinManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B62EBA287900F2D189 /* KBSkinManager.m */; }; 0459D1B82EBA287900F2D189 /* KBSkinManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B62EBA287900F2D189 /* KBSkinManager.m */; }; @@ -265,6 +266,8 @@ 04286A122ECDEBF900CE730C /* KBSkinIconMap.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = KBSkinIconMap.strings; sourceTree = ""; }; 0450AA722EF013D000B6AF06 /* KBEmojiCollectionCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBEmojiCollectionCell.h; sourceTree = ""; }; 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBEmojiCollectionCell.m; sourceTree = ""; }; + 0450AAE02EF03D5100B6AF06 /* keyBoard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "keyBoard-Bridging-Header.h"; sourceTree = ""; }; + 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KBPerson.swift; sourceTree = ""; }; 0459D1B22EBA284C00F2D189 /* KBSkinCenterVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinCenterVC.h; sourceTree = ""; }; 0459D1B32EBA284C00F2D189 /* KBSkinCenterVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinCenterVC.m; sourceTree = ""; }; 0459D1B52EBA287900F2D189 /* KBSkinManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinManager.h; sourceTree = ""; }; @@ -642,6 +645,8 @@ 04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */, 04B5A1A02EEFA12300AAAAAA /* KBPayProductModel.h */, 04B5A1A12EEFA12300AAAAAA /* KBPayProductModel.m */, + 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */, + 0450AAE02EF03D5100B6AF06 /* keyBoard-Bridging-Header.h */, ); path = M; sourceTree = ""; @@ -1603,6 +1608,7 @@ }; 727EC7522EAF848B00B36487 = { CreatedOnToolsVersion = 26.0.1; + LastSwiftMigration = 1640; }; }; }; @@ -1816,6 +1822,7 @@ 04FC95D72EB1EA16007BD342 /* BaseTableView.m in Sources */, 0498BD712EE02A41006CC1D5 /* KBForgetPwdNewPwdVC.m in Sources */, 048908EF2EBF861800FABA60 /* KBSkinSectionTitleCell.m in Sources */, + 0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */, 048908E32EBF821700FABA60 /* KBSkinDetailVC.m in Sources */, 0477BDF32EBB7B850055D639 /* KBDirectionIndicatorView.m in Sources */, 049FB21A2EC20A9E00FAB05D /* KBMyKeyBoardVC.m in Sources */, @@ -2030,6 +2037,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = keyBoard/keyBoard.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -2064,6 +2072,9 @@ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "keyBoard/Class/Pay/M/keyBoard-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 1; }; name = Debug; @@ -2074,6 +2085,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = keyBoard/keyBoard.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -2108,6 +2120,8 @@ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "keyBoard/Class/Pay/M/keyBoard-Bridging-Header.h"; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 1; }; name = Release; diff --git a/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m b/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m index e73e6bf..8a15104 100644 --- a/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m +++ b/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m @@ -32,6 +32,12 @@ NSString * const KBIAPDidCompletePurchaseNotification = @"KBIAPDidCompletePurcha 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 @@ -55,6 +61,7 @@ NSString * const KBIAPDidCompletePurchaseNotification = @"KBIAPDidCompletePurcha [[NSNotificationCenter defaultCenter] postNotificationName:KBIAPDidCompletePurchaseNotification object:nil]; if (handler) handler(KBLocalized(@"Success"), nil); }else if(sta == KBBizCodeReceiptError){ + [KBHUD dismiss]; [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; }else { [KBHUD showError:@"Failed"]; @@ -74,4 +81,68 @@ NSString * const KBIAPDidCompletePurchaseNotification = @"KBIAPDidCompletePurcha 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 diff --git a/keyBoard/Class/Pay/M/KBPerson.swift b/keyBoard/Class/Pay/M/KBPerson.swift new file mode 100644 index 0000000..1b3ccbf --- /dev/null +++ b/keyBoard/Class/Pay/M/KBPerson.swift @@ -0,0 +1,12 @@ +// +// KBPerson.swift +// keyBoard +// +// Created by Mac on 2025/12/15. +// + +import UIKit + +class KBPerson: NSObject { + +} diff --git a/keyBoard/Class/Pay/M/keyBoard-Bridging-Header.h b/keyBoard/Class/Pay/M/keyBoard-Bridging-Header.h new file mode 100644 index 0000000..1b2cb5d --- /dev/null +++ b/keyBoard/Class/Pay/M/keyBoard-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// +