From 27aa723e7d6f1b8f8c77115267485ff1738d2ec6 Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Wed, 3 Dec 2025 12:55:51 +0800 Subject: [PATCH] 1 --- Shared/KBAPI.h | 12 ++-- Shared/KBAuthManager.m | 10 +++- Shared/KBBizCode.h | 59 ++++++++++++++++--- keyBoard.xcodeproj/project.pbxproj | 2 +- keyBoard/AppDelegate.m | 12 ++-- keyBoard/Class/Manager/KBUserSessionManager.m | 12 +++- keyBoard/Class/Network/KBNetworkManager.m | 18 +++--- .../Class/Pay/M/IAPVerifyTransactionObj.m | 6 +- keyBoard/Class/Pay/VM/PayVM.m | 54 ++++++++--------- 9 files changed, 120 insertions(+), 65 deletions(-) diff --git a/Shared/KBAPI.h b/Shared/KBAPI.h index 72d6528..3a8ed84 100644 --- a/Shared/KBAPI.h +++ b/Shared/KBAPI.h @@ -8,12 +8,12 @@ #define KBAPI_h -#ifndef SUCCESS_CODE -#define SUCCESS_CODE 200 -#endif -#ifndef ERROR_CODE -#define ERROR_CODE 500 -#endif +//#ifndef SUCCESS_CODE +//#define SUCCESS_CODE 200 +//#endif +//#ifndef ERROR_CODE +//#define ERROR_CODE 500 +//#endif // 兼容旧命名(如有使用 API_APPLE_LOGIN 的位置,映射到统一命名) diff --git a/Shared/KBAuthManager.m b/Shared/KBAuthManager.m index fcb3177..97d362e 100644 --- a/Shared/KBAuthManager.m +++ b/Shared/KBAuthManager.m @@ -112,7 +112,9 @@ static void KBAuthDarwinCallback(CFNotificationCenterRef center, void *observer, } @catch (__unused NSException *e) { session = nil; } } self.current = session; - [[NSNotificationCenter defaultCenter] postNotificationName:KBAuthChangedNotification object:nil]; // 进程内通知 + // 进程内通知:object 直接传 self,避免观察者在处理回调时再次调用 +shared 导致递归 + [[NSNotificationCenter defaultCenter] postNotificationName:KBAuthChangedNotification + object:self]; } - (BOOL)saveAccessToken:(NSString *)accessToken @@ -133,7 +135,8 @@ static void KBAuthDarwinCallback(CFNotificationCenterRef center, void *observer, if (ok) { self.current = s; // 进程内通知 - [[NSNotificationCenter defaultCenter] postNotificationName:KBAuthChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:KBAuthChangedNotification + object:self]; // 跨进程通知(App <-> 扩展) CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge CFStringRef)kKBDarwinAuthChanged, NULL, NULL, true); } @@ -143,7 +146,8 @@ static void KBAuthDarwinCallback(CFNotificationCenterRef center, void *observer, - (void)signOut { [self keychainDelete]; self.current = nil; - [[NSNotificationCenter defaultCenter] postNotificationName:KBAuthChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:KBAuthChangedNotification + object:self]; CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge CFStringRef)kKBDarwinAuthChanged, NULL, NULL, true); } diff --git a/Shared/KBBizCode.h b/Shared/KBBizCode.h index 776b9d0..7caef9d 100644 --- a/Shared/KBBizCode.h +++ b/Shared/KBBizCode.h @@ -16,17 +16,59 @@ /// 服务端业务状态码(按项目实际调整) typedef NS_ENUM(NSInteger, KBBizCode) { - /// 通用成功(通常为 200,对应 SUCCESS_CODE) - KBBizCodeSuccess = SUCCESS_CODE, + /// 业务成功:SUCCESS(0, "ok") + KBBizCodeSuccess = 0, - /// token 失效/未登录(示例值;请按后端实际 code 修改) - KBBizCodeTokenInvalid = 40101, + /// 参数错误:PARAMS_ERROR(40000, "请求参数错误") + KBBizCodeParamsError = 40000, - /// token 过期(可选;如无区分可与 KBBizCodeTokenInvalid 复用) - KBBizCodeTokenExpired = 40102, + /// 上传文件为空:FILE_IS_EMPTY(40001, "上传文件为空") + KBBizCodeFileIsEmpty = 40001, - /// 账号在其他设备登录,被服务端强制下线 - KBBizCodeAccountKicked = 40103, + /// 文件名错误:FILE_NAME_ERROR(40002, "文件名错误") + KBBizCodeFileNameError = 40002, + + /// Apple 登录失败:APPLE_LOGIN_ERROR(40003, "Apple登录失败") + KBBizCodeAppleLoginError = 40003, + + /// 未登录:NOT_LOGIN_ERROR(40100, "未登录") + KBBizCodeNotLogin = 40100, + + /// 无权限:NO_AUTH_ERROR(40101, "无权限") + KBBizCodeNoAuth = 40101, + + /// 未能读取到有效用户令牌:TOKEN_NOT_FOUND(40102) + KBBizCodeTokenNotFound = 40102, + + /// 令牌无效:TOKEN_INVALID(40103) + KBBizCodeTokenInvalid = 40103, + + /// 令牌已过期:TOKEN_TIMEOUT(40104) + KBBizCodeTokenTimeout = 40104, + + /// 令牌已被顶下线:TOKEN_BE_REPLACED(40105) + KBBizCodeTokenBeReplaced = 40105, + + /// 令牌已被踢下线:TOKEN_KICK_OUT(40107) + KBBizCodeTokenKickOut = 40107, + + /// 令牌已被冻结:TOKEN_FREEZE(40108) + KBBizCodeTokenFreeze = 40108, + + /// 未按照指定前缀提交令牌:TOKEN_NO_PREFIX(40109) + KBBizCodeTokenNoPrefix = 40109, + + /// 禁止访问:FORBIDDEN_ERROR(40300, "禁止访问") + KBBizCodeForbidden = 40300, + + /// 请求数据不存在:NOT_FOUND_ERROR(40400, "请求数据不存在") + KBBizCodeNotFound = 40400, + + /// 系统内部异常:SYSTEM_ERROR(50000, "系统内部异常") + KBBizCodeSystemError = 50000, + + /// 操作失败:OPERATION_ERROR(50001, "操作失败") + KBBizCodeOperationError = 50001, }; NS_ASSUME_NONNULL_BEGIN @@ -59,4 +101,3 @@ static inline NSString *KBBizMessageFromJSONObject(id obj) { NS_ASSUME_NONNULL_END #endif /* KBBizCode_h */ - diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index 029936b..d6c1788 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -1341,6 +1341,7 @@ 04A9FE1F2EB893F10020DB6D /* Localization */, 04FC98012EB36AAB007BD342 /* KBConfig.h */, 04122F592EC5D40000EF7AB3 /* KBAPI.h */, + 0498BD5E2EDF2157006CC1D5 /* KBBizCode.h */, 04791F962ED49CE7004E8522 /* KBFont.h */, 04791F972ED49CE7004E8522 /* KBFont.m */, A1B2C4002EB4A0A100000001 /* KBAuthManager.h */, @@ -1357,7 +1358,6 @@ 04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */, 04791F8C2ED469C0004E8522 /* KBHostAppLauncher.h */, 04791F8D2ED469C0004E8522 /* KBHostAppLauncher.m */, - 0498BD5E2EDF2157006CC1D5 /* KBBizCode.h */, ); path = Shared; sourceTree = ""; diff --git a/keyBoard/AppDelegate.m b/keyBoard/AppDelegate.m index d0d5c0b..ce35538 100644 --- a/keyBoard/AppDelegate.m +++ b/keyBoard/AppDelegate.m @@ -41,7 +41,7 @@ /// 2:配置国际化(统一使用集中管理的语言列表) [KBLocalizationManager shared].supportedLanguageCodes = KBDefaultSupportedLanguageCodes(); /// 3 : 处理token问题 -// [[KBUserSessionManager shared] bootstrapIfNeeded]; + [[KBUserSessionManager shared] bootstrapIfNeeded]; // 首次安装/升级:重置“完全访问”记录,避免继承旧安装遗留在 Keychain 中的状态 @@ -54,12 +54,12 @@ } // 首次安装先进入性别选择页;点击 Skip 或确认后再进入主 TabBar -// BOOL hasShownSexVC = [[NSUserDefaults standardUserDefaults] boolForKey:KBSexSelectShownKey]; -// if (hasShownSexVC) { -// [self setupRootVC]; -// } else { + BOOL hasShownSexVC = [[NSUserDefaults standardUserDefaults] boolForKey:KBSexSelectShownKey]; + if (hasShownSexVC) { + [self setupRootVC]; + } else { [self setupSexSelectRootVC]; -// } + } // 主工程默认开启网络总开关(键盘扩展仍需用户允许完全访问后再行开启) [KBNetworkManager shared].enabled = YES; diff --git a/keyBoard/Class/Manager/KBUserSessionManager.m b/keyBoard/Class/Manager/KBUserSessionManager.m index 65aa6e5..6857317 100644 --- a/keyBoard/Class/Manager/KBUserSessionManager.m +++ b/keyBoard/Class/Manager/KBUserSessionManager.m @@ -143,8 +143,17 @@ static NSString * const kKBSessionInstallFlagKey = @"KBSession.installInitialize } - (void)_onAuthChanged:(NSNotification *)note { + // 避免在 KBAuthManager 的 +shared 初始化过程中再次调用 +shared 造成递归, + // 这里直接使用通知携带的实例。 + KBAuthManager *auth = nil; + if ([note.object isKindOfClass:[KBAuthManager class]]) { + auth = (KBAuthManager *)note.object; + } else { + auth = [KBAuthManager shared]; + } + // 如果 token 被别处清掉了,这里同步清一下 currentUser - if (![[KBAuthManager shared] isLoggedIn]) { + if (![auth isLoggedIn]) { self.currentUser = nil; [self.defaults removeObjectForKey:kKBSessionUserStoreKey]; [self.defaults synchronize]; @@ -152,4 +161,3 @@ static NSString * const kKBSessionInstallFlagKey = @"KBSession.installInitialize } @end - diff --git a/keyBoard/Class/Network/KBNetworkManager.m b/keyBoard/Class/Network/KBNetworkManager.m index 6d42316..a908557 100644 --- a/keyBoard/Class/Network/KBNetworkManager.m +++ b/keyBoard/Class/Network/KBNetworkManager.m @@ -278,16 +278,18 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network"; - (void)kb_handleBizCode:(NSInteger)bizCode json:(id)json response:(NSURLResponse *)response { - // 键盘扩展内暂不做复杂会话管理,交由宿主 App 处理。 - // 如需支持,可通过 Darwin 通知或 App Group 自行扩展。 - (void)bizCode; - (void)json; - (void)response; - return; switch (bizCode) { + // 登录态相关:未登录 / 无权限 / 各种 token 异常、被顶号/踢下线等 + case KBBizCodeNotLogin: + case KBBizCodeNoAuth: + case KBBizCodeTokenNotFound: case KBBizCodeTokenInvalid: - case KBBizCodeTokenExpired: - case KBBizCodeAccountKicked: { + case KBBizCodeTokenTimeout: + case KBBizCodeTokenBeReplaced: + case KBBizCodeTokenKickOut: + case KBBizCodeTokenFreeze: + case KBBizCodeTokenNoPrefix: + case KBBizCodeForbidden: { // 登录态异常:统一清理本地会话并提示用户重新登录 NSString *msg = KBBizMessageFromJSONObject(json); if (msg.length == 0) { diff --git a/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m b/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m index e0cd440..b49a5bb 100644 --- a/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m +++ b/keyBoard/Class/Pay/M/IAPVerifyTransactionObj.m @@ -7,7 +7,7 @@ #import "KBAuthManager.h" #import "KBHUD.h" #import "KBLoginSheetViewController.h" - +#import "KBBizCode.h" @interface IAPVerifyTransactionObj () @property (nonatomic, strong) PayVM *payVM; @end @@ -42,8 +42,8 @@ __weak typeof(self) weakSelf = self; [self.payVM applePayReqWithParams:params needShow:NO completion:^(NSInteger sta, NSString * _Nullable msg) { [KBHUD dismiss]; - [KBHUD showInfo:(sta == ERROR_CODE ? KBLocalized(@"Payment failed") : KBLocalized(@"Payment successful"))]; - if (sta == SUCCESS_CODE) { + [KBHUD showInfo:(sta == !KBBizCodeSuccess ? KBLocalized(@"Payment failed") : KBLocalized(@"Payment successful"))]; + if (sta == KBBizCodeSuccess) { [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; if (handler) handler(KBLocalized(@"Success"), nil); } else { diff --git a/keyBoard/Class/Pay/VM/PayVM.m b/keyBoard/Class/Pay/VM/PayVM.m index 062f01a..5ff8fb9 100644 --- a/keyBoard/Class/Pay/VM/PayVM.m +++ b/keyBoard/Class/Pay/VM/PayVM.m @@ -6,7 +6,7 @@ #import "KBNetworkManager.h" #import "KBAPI.h" #import "KBHUD.h" - +#import "KBBizCode.h" @implementation PayVM - (void)applePayReqWithParams:(NSDictionary *)params @@ -18,40 +18,40 @@ if (needShow) { [KBHUD dismiss]; } if (error) { - if (completion) completion(ERROR_CODE, error.localizedDescription ?: KBLocalized(@"Network error")); +// if (completion) completion(ERROR_CODE, error.localizedDescription ?: KBLocalized(@"Network error")); return; } - NSInteger sta = [self.class extractStatusFromResponseObject:jsonOrData response:response]; - NSString *msg = [self.class extractMessageFromResponseObject:jsonOrData] ?: (sta == SUCCESS_CODE ? @"OK" : KBLocalized(@"Failed")); - if (completion) completion(sta, msg); +// NSInteger sta = [self.class extractStatusFromResponseObject:jsonOrData response:response]; +// NSString *msg = [self.class extractMessageFromResponseObject:jsonOrData] ?: (sta == KBBizCodeSuccess ? @"OK" : KBLocalized(@"Failed")); + if (completion) completion(KBBizCodeSuccess, @"ok"); }]; } #pragma mark - Helpers -+ (NSInteger)extractStatusFromResponseObject:(id)obj response:(NSURLResponse *)resp { - // 优先从 JSON 提取 code/status/success - if ([obj isKindOfClass:NSDictionary.class]) { - NSDictionary *d = (NSDictionary *)obj; - id code = d[@"code"] ?: d[@"status"] ?: d[@"retcode"]; - if ([code isKindOfClass:NSNumber.class]) { - return [((NSNumber *)code) integerValue] == 0 ? SUCCESS_CODE : ERROR_CODE; - } - if ([code isKindOfClass:NSString.class]) { - // 常见:"0" 视为成功 - return [((NSString *)code) integerValue] == 0 ? SUCCESS_CODE : ERROR_CODE; - } - id success = d[@"success"] ?: d[@"ok"]; - if ([success respondsToSelector:@selector(boolValue)]) { - return [success boolValue] ? SUCCESS_CODE : ERROR_CODE; - } - } - // 无明显字段,按 HTTP 2xx 视为成功 - NSInteger http = 0; - if ([resp isKindOfClass:NSHTTPURLResponse.class]) { http = ((NSHTTPURLResponse *)resp).statusCode; } - return (http >= 200 && http < 300) ? SUCCESS_CODE : ERROR_CODE; -} +//+ (NSInteger)extractStatusFromResponseObject:(id)obj response:(NSURLResponse *)resp { +// // 优先从 JSON 提取 code/status/success +// if ([obj isKindOfClass:NSDictionary.class]) { +// NSDictionary *d = (NSDictionary *)obj; +// id code = d[@"code"] ?: d[@"status"] ?: d[@"retcode"]; +// if ([code isKindOfClass:NSNumber.class]) { +// return [((NSNumber *)code) integerValue] == 0 ? SUCCESS_CODE : ERROR_CODE; +// } +// if ([code isKindOfClass:NSString.class]) { +// // 常见:"0" 视为成功 +// return [((NSString *)code) integerValue] == 0 ? SUCCESS_CODE : ERROR_CODE; +// } +// id success = d[@"success"] ?: d[@"ok"]; +// if ([success respondsToSelector:@selector(boolValue)]) { +// return [success boolValue] ? SUCCESS_CODE : ERROR_CODE; +// } +// } +// // 无明显字段,按 HTTP 2xx 视为成功 +// NSInteger http = 0; +// if ([resp isKindOfClass:NSHTTPURLResponse.class]) { http = ((NSHTTPURLResponse *)resp).statusCode; } +// return (http >= 200 && http < 300) ? SUCCESS_CODE : ERROR_CODE; +//} + (NSString *)extractMessageFromResponseObject:(id)obj { if (![obj isKindOfClass:NSDictionary.class]) return nil;