// // KBUserSessionManager.m // keyBoard // // Created by Mac on 2025/12/1. // #import "KBUserSessionManager.h" #import "KBAuthManager.h" #import "KBUser.h" #import "KBConfig.h" #import /// App Group 里的用户缓存 key static NSString * const kKBSessionUserStoreKey = @"KBSession.currentUser"; /// “本次安装是否已初始化”标记 key(用来识别卸载重装) static NSString * const kKBSessionInstallFlagKey = @"KBSession.installInitialized"; @interface KBUserSessionManager () @property (nonatomic, strong) NSUserDefaults *defaults; @property (atomic, strong, readwrite, nullable) KBUser *currentUser; @property (nonatomic, assign) BOOL didBootstrap; @end @implementation KBUserSessionManager + (instancetype)shared { static KBUserSessionManager *m; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ m = [KBUserSessionManager new]; }); return m; } - (instancetype)init { if (self = [super init]) { // 优先用 App Group 的 UserDefaults,App 和扩展共用一份 NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup]; _defaults = ud ?: [NSUserDefaults standardUserDefaults]; // 监听 token 变化(例如别处调用了 signOut) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_onAuthChanged:) name:KBAuthChangedNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - Public - (void)bootstrapIfNeeded { if (self.didBootstrap) return; self.didBootstrap = YES; BOOL hasInitializedThisInstall = [self.defaults boolForKey:kKBSessionInstallFlagKey]; KBAuthManager *auth = [KBAuthManager shared]; // 内部会 reloadFromKeychain if (!hasInitializedThisInstall) { // 说明是“卸载重装后的第一次运行”(或者真正第一次安装) [self.defaults setBool:YES forKey:kKBSessionInstallFlagKey]; [self.defaults synchronize]; // 若此时 Keychain 里已有 token,多半是上一次安装遗留的;按你的需求清掉 if (auth.current.accessToken.length > 0) { [auth signOut]; } // 清除旧的用户缓存 [self.defaults removeObjectForKey:kKBSessionUserStoreKey]; [self.defaults synchronize]; self.currentUser = nil; } else { // 正常启动:从本地恢复用户信息 [self p_loadUserFromStore]; } } - (BOOL)isLoggedIn { return [[KBAuthManager shared] isLoggedIn]; } - (NSString *)accessToken { return [KBAuthManager shared].current.accessToken; } - (void)handleLoginSuccessWithUser:(KBUser *)user { if (!user) return; // 先写 Keychain(统一走 KBAuthManager) NSString *token = user.token; if (token.length > 0) { [[KBAuthManager shared] saveAccessToken:token refreshToken:nil expiryDate:nil userIdentifier:nil]; } // 再缓存用户信息,供 App/键盘使用 self.currentUser = user; [self p_saveUserToStore:user]; } - (void)logout { // 清 Keychain [[KBAuthManager shared] signOut]; // 清本地用户缓存 self.currentUser = nil; [self.defaults removeObjectForKey:kKBSessionUserStoreKey]; [self.defaults synchronize]; } #pragma mark - Private - (void)p_loadUserFromStore { id obj = [self.defaults objectForKey:kKBSessionUserStoreKey]; if (![obj isKindOfClass:[NSDictionary class]]) { self.currentUser = nil; return; } KBUser *user = [KBUser mj_objectWithKeyValues:(NSDictionary *)obj]; self.currentUser = user; } - (void)p_saveUserToStore:(KBUser *)user { if (!user) { [self.defaults removeObjectForKey:kKBSessionUserStoreKey]; [self.defaults synchronize]; return; } NSDictionary *dict = [user mj_keyValues]; if (dict) { [self.defaults setObject:dict forKey:kKBSessionUserStoreKey]; [self.defaults synchronize]; } } - (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 (![auth isLoggedIn]) { self.currentUser = nil; [self.defaults removeObjectForKey:kKBSessionUserStoreKey]; [self.defaults synchronize]; } } @end