This commit is contained in:
2025-11-20 15:35:22 +08:00
parent c27fd099f6
commit b23927968f

View File

@@ -3,14 +3,13 @@
//
#import "KBSkinManager.h"
#import <Security/Security.h>
#import "KBConfig.h"
NSString * const KBSkinDidChangeNotification = @"KBSkinDidChangeNotification";
NSString * const KBDarwinSkinChanged = @"com.loveKey.nyx.skin.changed";
static NSString * const kKBSkinService = @"com.loveKey.nyx.skin"; // Keychain service
static NSString * const kKBSkinAccount = @"current"; // Keychain account
// 使 App Group NSUserDefaults Keychain
static NSString * const kKBSkinThemeStoreKey = @"KBSkinThemeCurrent";
@implementation KBSkinTheme
@@ -81,8 +80,8 @@ static NSString * const kKBSkinAccount = @"current"; // Keychain ac
- (instancetype)init {
if (self = [super init]) {
KBSkinTheme *t = [self p_loadFromKeychain];
// Keychain App Group / 退
KBSkinTheme *t = [self p_loadFromStore];
// App Group / 退
if (!t || ![self.class kb_hasAssetsForSkinId:t.skinId]) {
t = [self.class defaultTheme];
}
@@ -100,7 +99,7 @@ static NSString * const kKBSkinAccount = @"current"; // Keychain ac
static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
KBSkinManager *self = (__bridge KBSkinManager *)observer;
[self p_reloadFromKeychainAndBroadcast:YES];
[self p_reloadFromStoreAndBroadcast:YES];
}
- (void)dealloc {
@@ -134,13 +133,17 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer,
- (BOOL)applyTheme:(KBSkinTheme *)theme {
if (!theme) return NO;
if ([self p_saveToKeychain:theme]) {
// App Group 使
[self p_saveToStore:theme];
// 广
self.current = theme;
[[NSNotificationCenter defaultCenter] postNotificationName:KBSkinDidChangeNotification object:nil];
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge CFStringRef)KBDarwinSkinChanged, NULL, NULL, true);
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge CFStringRef)KBDarwinSkinChanged,
NULL,
NULL,
true);
return YES;
}
return NO;
}
- (void)resetToDefault {
@@ -329,44 +332,40 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer,
return t;
}
#pragma mark - Keychain
#pragma mark - Persistence (App Group)
- (NSMutableDictionary *)baseKCQuery {
NSMutableDictionary *q = [@{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: kKBSkinService,
(__bridge id)kSecAttrAccount: kKBSkinAccount } mutableCopy];
q[(__bridge id)kSecAttrAccessGroup] = KB_KEYCHAIN_ACCESS_GROUP;
return q;
}
- (BOOL)p_saveToKeychain:(KBSkinTheme *)theme {
/// App Group NSUserDefaults
- (BOOL)p_saveToStore:(KBSkinTheme *)theme {
if (!theme) return NO;
NSError *err = nil;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:theme requiringSecureCoding:YES error:&err];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:theme
requiringSecureCoding:YES
error:&err];
if (err || data.length == 0) return NO;
NSMutableDictionary *q = [self baseKCQuery];
SecItemDelete((__bridge CFDictionaryRef)q);
q[(__bridge id)kSecValueData] = data;
q[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
OSStatus st = SecItemAdd((__bridge CFDictionaryRef)q, NULL);
return (st == errSecSuccess);
NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
if (!ud) return NO;
[ud setObject:data forKey:kKBSkinThemeStoreKey];
return [ud synchronize];
}
- (KBSkinTheme *)p_loadFromKeychain {
NSMutableDictionary *q = [self baseKCQuery];
q[(__bridge id)kSecReturnData] = @YES;
q[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
CFTypeRef dataRef = NULL; OSStatus st = SecItemCopyMatching((__bridge CFDictionaryRef)q, &dataRef);
if (st != errSecSuccess || !dataRef) return nil;
NSData *data = (__bridge_transfer NSData *)dataRef;
if (data.length == 0) return nil;
/// App Group NSUserDefaults
- (KBSkinTheme *)p_loadFromStore {
NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
if (!ud) return nil;
NSData *data = [ud objectForKey:kKBSkinThemeStoreKey];
if (![data isKindOfClass:NSData.class] || data.length == 0) return nil;
@try {
KBSkinTheme *t = [NSKeyedUnarchiver unarchivedObjectOfClass:KBSkinTheme.class fromData:data error:NULL];
KBSkinTheme *t = [NSKeyedUnarchiver unarchivedObjectOfClass:KBSkinTheme.class
fromData:data
error:NULL];
return t;
} @catch (__unused NSException *e) { return nil; }
} @catch (__unused NSException *e) {
return nil;
}
}
- (void)p_reloadFromKeychainAndBroadcast:(BOOL)broadcast {
KBSkinTheme *t = [self p_loadFromKeychain];
- (void)p_reloadFromStoreAndBroadcast:(BOOL)broadcast {
KBSkinTheme *t = [self p_loadFromStore];
if (!t || ![self.class kb_hasAssetsForSkinId:t.skinId]) {
t = [self.class defaultTheme];
}