From 973577c6ebf9575b3db9df55df11bfacc7981c7b Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Wed, 4 Mar 2026 16:11:13 +0800 Subject: [PATCH] 1 --- .../KeyboardViewController+Theme.m | 7 +- Shared/KBSkinInstallBridge.m | 5 +- keyBoard/Class/Shop/VC/KBSkinDetailVC.m | 104 +++++++++++++----- 3 files changed, 81 insertions(+), 35 deletions(-) diff --git a/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Theme.m b/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Theme.m index a6a3cfa..a3eb0b5 100644 --- a/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Theme.m +++ b/CustomKeyboard/KeyboardViewControllerHelp/KeyboardViewController+Theme.m @@ -166,9 +166,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, [self kb_logSkinDiagnosticsWithTheme:t backgroundImage:img]; self.bgImageView.image = img; - // 触发键区按主题重绘 - if (themeChanged && - [self.keyBoardMainView respondsToSelector:@selector(kb_applyTheme)]) { + // 皮肤资源可能被“重新下载”,即使 skinId 未变也需要刷新按键图标。 + if ([self.keyBoardMainView respondsToSelector:@selector(kb_applyTheme)]) { // method declared in KBKeyBoardMainView.h #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" @@ -177,7 +176,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center, } // 注意:这里不能直接访问 self.functionView,否则会导致功能面板提前创建,占用内存。 KBFunctionView *functionView = [self kb_functionViewIfCreated]; - if (themeChanged && functionView && + if (functionView && [functionView respondsToSelector:@selector(kb_applyTheme)]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" diff --git a/Shared/KBSkinInstallBridge.m b/Shared/KBSkinInstallBridge.m index a44fb63..780ed0b 100644 --- a/Shared/KBSkinInstallBridge.m +++ b/Shared/KBSkinInstallBridge.m @@ -958,12 +958,15 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json"; NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: currentSkin=%@ targetSkin=%@ lang=%@", currentSkinId, targetSkinId, languageCode); + BOOL isDefaultLike = (currentSkinId.length == 0 || + [currentSkinId isEqualToString:@"default"] || + [currentSkinId hasPrefix:@"bundle_skin_default_"]); // 检查目标皮肤是否存在 BOOL hasTargetSkin = [KBSkinManager kb_hasAssetsForSkinId:targetSkinId]; NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: hasTargetSkin=%d", hasTargetSkin); - if (hasTargetSkin) { + if (hasTargetSkin && isDefaultLike) { // 先获取目标皮肤的图标映射 NSDictionary *iconShortNames = [self iconShortNamesForLanguageCode:languageCode]; if (iconShortNames.count == 0) { diff --git a/keyBoard/Class/Shop/VC/KBSkinDetailVC.m b/keyBoard/Class/Shop/VC/KBSkinDetailVC.m index 0b84b9a..4b5f529 100644 --- a/keyBoard/Class/Shop/VC/KBSkinDetailVC.m +++ b/keyBoard/Class/Shop/VC/KBSkinDetailVC.m @@ -38,6 +38,7 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) { @property (nonatomic, strong) KBShopVM *shopVM; @property (nonatomic, strong, nullable) KBShopThemeDetailModel *detailModel; //@property (nonatomic, assign) BOOL isProcessingAction; +- (NSMutableDictionary *)buildSkinPayloadWithDownloadInfo:(NSDictionary *)info; @end @implementation KBSkinDetailVC @@ -296,41 +297,84 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) { - (void)requestDownload { // if (self.isProcessingAction) { return; } // self.isProcessingAction = YES; - + [KBHUD showWithStatus:KBLocalized(@"Downloading...")]; + __weak typeof(self) weakSelf = self; + [self.shopVM fetchThemeDownloadInfoWithId:self.themeId completion:^(NSDictionary * _Nullable info, NSError * _Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + __strong typeof(weakSelf) strongSelf = weakSelf; + if (!strongSelf) { return; } + if (error) { + NSLog(@"[KBSkinDetailVC] fetch download info failed: %@", error); + } + NSMutableDictionary *skin = [strongSelf buildSkinPayloadWithDownloadInfo:info]; + NSString *zipURL = [skin[@"zip_url"] isKindOfClass:NSString.class] ? skin[@"zip_url"] : @""; + if (skin.count == 0 || zipURL.length == 0) { + [KBHUD dismiss]; + [KBHUD showInfo:KBLocalized(@"下载信息缺失")]; + return; + } + NSLog(@"⬇️[SkinDetail] download request id=%@ zip=%@ force=YES", + skin[@"id"], zipURL); + [[KBSkinService shared] applySkinWithJSON:skin + fromViewController:strongSelf + mode:KBSkinSourceModeRemoteZip + completion:^(BOOL success) { + [KBHUD dismiss]; + NSLog(@"%@[SkinDetail] download result id=%@", + (success ? @"✅" : @"❌"), + strongSelf.detailModel.themeId); + if (success) { + NSString *themeId = strongSelf.detailModel.themeId; + if (themeId.length > 0) { + [strongSelf.shopVM restoreThemeWithId:themeId completion:nil]; + } + } else { + [KBHUD showInfo:KBLocalized(@"下载失败")]; + } + }]; + }); + }]; +} + +- (NSMutableDictionary *)buildSkinPayloadWithDownloadInfo:(NSDictionary *)info { NSMutableDictionary *skin = [NSMutableDictionary dictionary]; - if (!skin[@"id"] && self.detailModel.themeId) { - skin[@"id"] = self.detailModel.themeId; + if ([info isKindOfClass:NSDictionary.class]) { + [info enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if (![key isKindOfClass:NSString.class]) { return; } + if (!obj || obj == [NSNull null]) { return; } + skin[key] = obj; + }]; } - if (!skin[@"name"] && self.detailModel.themeName) { - skin[@"name"] = self.detailModel.themeName; + NSString *themeId = self.detailModel.themeId.length > 0 ? self.detailModel.themeId : self.themeId; + if (themeId.length > 0) { + skin[@"id"] = themeId; } - - - skin[@"zip_url"] = self.detailModel.themeDownloadUrl ? self.detailModel.themeDownloadUrl : @""; - if (self.detailModel.themePreviewImageUrl.length > 0) { - skin[@"preview"] = self.detailModel.themePreviewImageUrl; + if (![skin[@"name"] isKindOfClass:NSString.class] || [skin[@"name"] length] == 0) { + if (self.detailModel.themeName.length > 0) { + skin[@"name"] = self.detailModel.themeName; + } else if (themeId.length > 0) { + skin[@"name"] = themeId; + } + } + NSString *zipURL = [skin[@"zip_url"] isKindOfClass:NSString.class] ? skin[@"zip_url"] : @""; + if (zipURL.length == 0) { + id altURL = skin[@"zipUrl"] ?: skin[@"download_url"] ?: skin[@"downloadUrl"]; + if ([altURL isKindOfClass:NSString.class]) { + zipURL = altURL; + } else if (self.detailModel.themeDownloadUrl.length > 0) { + zipURL = self.detailModel.themeDownloadUrl; + } + if (zipURL.length > 0) { + skin[@"zip_url"] = zipURL; + } + } + if (![skin[@"preview"] isKindOfClass:NSString.class] || [skin[@"preview"] length] == 0) { + if (self.detailModel.themePreviewImageUrl.length > 0) { + skin[@"preview"] = self.detailModel.themePreviewImageUrl; + } } skin[@"force_download"] = @(YES); - NSLog(@"⬇️[SkinDetail] download request id=%@ zip=%@ force=YES", - skin[@"id"], skin[@"zip_url"]); - [KBHUD showWithStatus:KBLocalized(@"Downloading...")]; - [[KBSkinService shared] applySkinWithJSON:skin - fromViewController:self - mode:KBSkinSourceModeRemoteZip - completion:^(BOOL success) { - [KBHUD dismiss]; - NSLog(@"%@[SkinDetail] download result id=%@", - (success ? @"✅" : @"❌"), - self.detailModel.themeId); - if (success) { - NSString *themeId = self.detailModel.themeId; - if (themeId.length > 0) { - [self.shopVM restoreThemeWithId:themeId completion:nil]; - } - } else { - [KBHUD showInfo:KBLocalized(@"下载失败")]; - } - }]; + return skin; } - (void)updateBottomBarAppearance {