优化下载皮肤❤️
This commit is contained in:
@@ -589,6 +589,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
|||||||
- (void)kb_applyTheme {
|
- (void)kb_applyTheme {
|
||||||
KBSkinTheme *t = [KBSkinManager shared].current;
|
KBSkinTheme *t = [KBSkinManager shared].current;
|
||||||
UIImage *img = [[KBSkinManager shared] currentBackgroundImage];
|
UIImage *img = [[KBSkinManager shared] currentBackgroundImage];
|
||||||
|
NSLog(@"⌨️[Keyboard] apply theme id=%@ hasBg=%d", t.skinId, (img != nil));
|
||||||
self.bgImageView.image = img;
|
self.bgImageView.image = img;
|
||||||
BOOL hasImg = (img != nil);
|
BOOL hasImg = (img != nil);
|
||||||
self.view.backgroundColor = hasImg ? [UIColor clearColor] : t.keyboardBackground;
|
self.view.backgroundColor = hasImg ? [UIColor clearColor] : t.keyboardBackground;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ static NSString * const kKBSkinPendingKindKey = @"kind";
|
|||||||
static NSString * const kKBSkinPendingTimestampKey = @"timestamp";
|
static NSString * const kKBSkinPendingTimestampKey = @"timestamp";
|
||||||
static NSString * const kKBSkinPendingIconShortKey = @"iconShortNames";
|
static NSString * const kKBSkinPendingIconShortKey = @"iconShortNames";
|
||||||
static NSString * const kKBSkinMetadataFileName = @"metadata.plist";
|
static NSString * const kKBSkinMetadataFileName = @"metadata.plist";
|
||||||
|
static NSString * const kKBSkinForceDownloadKey = @"force_download";
|
||||||
static NSString * const kKBSkinMetadataNameKey = @"name";
|
static NSString * const kKBSkinMetadataNameKey = @"name";
|
||||||
static NSString * const kKBSkinMetadataPreviewKey = @"preview";
|
static NSString * const kKBSkinMetadataPreviewKey = @"preview";
|
||||||
static NSString * const kKBSkinMetadataZipKey = @"zip_url";
|
static NSString * const kKBSkinMetadataZipKey = @"zip_url";
|
||||||
@@ -220,6 +221,11 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
NSString *skinId = skinJSON[@"id"] ?: @"remote";
|
NSString *skinId = skinJSON[@"id"] ?: @"remote";
|
||||||
NSString *name = skinJSON[@"name"] ?: skinId;
|
NSString *name = skinJSON[@"name"] ?: skinId;
|
||||||
NSString *zipURL = skinJSON[@"zip_url"] ?: @"";
|
NSString *zipURL = skinJSON[@"zip_url"] ?: @"";
|
||||||
|
BOOL forceDownload = NO;
|
||||||
|
id forceValue = skinJSON[kKBSkinForceDownloadKey];
|
||||||
|
if ([forceValue respondsToSelector:@selector(boolValue)]) {
|
||||||
|
forceDownload = [forceValue boolValue];
|
||||||
|
}
|
||||||
|
|
||||||
// key_icons 可选:
|
// key_icons 可选:
|
||||||
// - 若后端提供 key_icons,则优先使用服务端映射;
|
// - 若后端提供 key_icons,则优先使用服务端映射;
|
||||||
@@ -258,6 +264,21 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
BOOL hasCachedAssets = (contents.count > 0);
|
BOOL hasCachedAssets = (contents.count > 0);
|
||||||
|
|
||||||
NSString *bgPath = [skinRoot stringByAppendingPathComponent:@"background.png"];
|
NSString *bgPath = [skinRoot stringByAppendingPathComponent:@"background.png"];
|
||||||
|
BOOL useTempRoot = forceDownload;
|
||||||
|
NSString *tempToken = nil;
|
||||||
|
NSString *workingRoot = skinRoot;
|
||||||
|
NSString *workingIconsDir = iconsDir;
|
||||||
|
NSString *workingBgPath = bgPath;
|
||||||
|
if (useTempRoot) {
|
||||||
|
tempToken = [NSString stringWithFormat:@"%lld", (long long)([[NSDate date] timeIntervalSince1970] * 1000)];
|
||||||
|
NSString *tmpName = [NSString stringWithFormat:@"%@__tmp_%@", skinId, tempToken];
|
||||||
|
workingRoot = [skinsRoot stringByAppendingPathComponent:tmpName];
|
||||||
|
workingIconsDir = [workingRoot stringByAppendingPathComponent:@"icons"];
|
||||||
|
workingBgPath = [workingRoot stringByAppendingPathComponent:@"background.png"];
|
||||||
|
[fm removeItemAtPath:workingRoot error:nil];
|
||||||
|
}
|
||||||
|
NSLog(@"⬇️[SkinBridge] request id=%@ force=%d cached=%d zip=%@",
|
||||||
|
skinId, forceDownload, hasCachedAssets, zipURL);
|
||||||
|
|
||||||
dispatch_group_t group = dispatch_group_create();
|
dispatch_group_t group = dispatch_group_create();
|
||||||
__block BOOL zipOK = YES;
|
__block BOOL zipOK = YES;
|
||||||
@@ -265,8 +286,8 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
__block NSError *innerError = nil;
|
__block NSError *innerError = nil;
|
||||||
|
|
||||||
#if __has_include(<SSZipArchive/SSZipArchive.h>)
|
#if __has_include(<SSZipArchive/SSZipArchive.h>)
|
||||||
// 若本地尚未缓存该皮肤资源且提供了 zip_url,则通过网络下载并解压 Zip 包。
|
// 若需要强制下载,或本地尚未缓存该皮肤资源且提供了 zip_url,则下载并解压 Zip 包。
|
||||||
if (!hasCachedAssets && zipURL.length > 0) {
|
if ((forceDownload || !hasCachedAssets) && zipURL.length > 0) {
|
||||||
dispatch_group_enter(group);
|
dispatch_group_enter(group);
|
||||||
|
|
||||||
void (^handleZipData)(NSData *) = ^(NSData *data) {
|
void (^handleZipData)(NSData *) = ^(NSData *data) {
|
||||||
@@ -277,15 +298,17 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
code:KBSkinBridgeErrorZipMissing
|
code:KBSkinBridgeErrorZipMissing
|
||||||
userInfo:@{NSLocalizedDescriptionKey: @"Zip data is empty"}];
|
userInfo:@{NSLocalizedDescriptionKey: @"Zip data is empty"}];
|
||||||
}
|
}
|
||||||
|
NSLog(@"❌[SkinBridge] zip data empty id=%@", skinId);
|
||||||
dispatch_group_leave(group);
|
dispatch_group_leave(group);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
NSLog(@"📦[SkinBridge] unzip start id=%@ temp=%d", skinId, useTempRoot);
|
||||||
// 将 Zip 写入临时路径再解压
|
// 将 Zip 写入临时路径再解压
|
||||||
[fm createDirectoryAtPath:skinRoot
|
[fm createDirectoryAtPath:workingRoot
|
||||||
withIntermediateDirectories:YES
|
withIntermediateDirectories:YES
|
||||||
attributes:nil
|
attributes:nil
|
||||||
error:NULL];
|
error:NULL];
|
||||||
NSString *zipPath = [skinRoot stringByAppendingPathComponent:@"skin.zip"];
|
NSString *zipPath = [workingRoot stringByAppendingPathComponent:@"skin.zip"];
|
||||||
if (![data writeToFile:zipPath atomically:YES]) {
|
if (![data writeToFile:zipPath atomically:YES]) {
|
||||||
zipOK = NO;
|
zipOK = NO;
|
||||||
if (!innerError) {
|
if (!innerError) {
|
||||||
@@ -293,13 +316,14 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
code:KBSkinBridgeErrorUnzipFailed
|
code:KBSkinBridgeErrorUnzipFailed
|
||||||
userInfo:@{NSLocalizedDescriptionKey: @"Failed to write zip file"}];
|
userInfo:@{NSLocalizedDescriptionKey: @"Failed to write zip file"}];
|
||||||
}
|
}
|
||||||
|
NSLog(@"❌[SkinBridge] zip write failed id=%@", skinId);
|
||||||
dispatch_group_leave(group);
|
dispatch_group_leave(group);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSError *unzipError = nil;
|
NSError *unzipError = nil;
|
||||||
BOOL ok = [SSZipArchive unzipFileAtPath:zipPath
|
BOOL ok = [SSZipArchive unzipFileAtPath:zipPath
|
||||||
toDestination:skinRoot
|
toDestination:workingRoot
|
||||||
overwrite:YES
|
overwrite:YES
|
||||||
password:nil
|
password:nil
|
||||||
error:&unzipError];
|
error:&unzipError];
|
||||||
@@ -311,24 +335,22 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
code:KBSkinBridgeErrorUnzipFailed
|
code:KBSkinBridgeErrorUnzipFailed
|
||||||
userInfo:nil];
|
userInfo:nil];
|
||||||
}
|
}
|
||||||
|
NSLog(@"❌[SkinBridge] unzip failed id=%@ error=%@", skinId, unzipError);
|
||||||
dispatch_group_leave(group);
|
dispatch_group_leave(group);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记已成功解压一次(即使 icons 目录结构需要后续整理)。
|
|
||||||
didUnzip = YES;
|
|
||||||
|
|
||||||
// 兼容“额外包一层目录”的压缩结构:
|
// 兼容“额外包一层目录”的压缩结构:
|
||||||
// 若 Skins/<skinId>/icons 为空,但存在 Skins/<skinId>/<子目录>/icons,
|
// 若 Skins/<skinId>/icons 为空,但存在 Skins/<skinId>/<子目录>/icons,
|
||||||
// 则将实际 icons 与 background.png 上移到预期位置。
|
// 则将实际 icons 与 background.png 上移到预期位置。
|
||||||
BOOL isDir2 = NO;
|
BOOL isDir2 = NO;
|
||||||
NSArray *iconsContent = [fm contentsOfDirectoryAtPath:iconsDir error:NULL];
|
NSArray *iconsContent = [fm contentsOfDirectoryAtPath:workingIconsDir error:NULL];
|
||||||
BOOL iconsValid = ([fm fileExistsAtPath:iconsDir isDirectory:&isDir2] && isDir2 && iconsContent.count > 0);
|
BOOL iconsValid = ([fm fileExistsAtPath:workingIconsDir isDirectory:&isDir2] && isDir2 && iconsContent.count > 0);
|
||||||
if (!iconsValid) {
|
if (!iconsValid) {
|
||||||
NSArray<NSString *> *subItems = [fm contentsOfDirectoryAtPath:skinRoot error:NULL];
|
NSArray<NSString *> *subItems = [fm contentsOfDirectoryAtPath:workingRoot error:NULL];
|
||||||
for (NSString *subName in subItems) {
|
for (NSString *subName in subItems) {
|
||||||
if ([subName isEqualToString:@"icons"] || [subName isEqualToString:@"__MACOSX"]) continue;
|
if ([subName isEqualToString:@"icons"] || [subName isEqualToString:@"__MACOSX"]) continue;
|
||||||
NSString *nestedRoot = [skinRoot stringByAppendingPathComponent:subName];
|
NSString *nestedRoot = [workingRoot stringByAppendingPathComponent:subName];
|
||||||
BOOL isDirNested = NO;
|
BOOL isDirNested = NO;
|
||||||
if (![fm fileExistsAtPath:nestedRoot isDirectory:&isDirNested] || !isDirNested) continue;
|
if (![fm fileExistsAtPath:nestedRoot isDirectory:&isDirNested] || !isDirNested) continue;
|
||||||
|
|
||||||
@@ -338,14 +360,14 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
NSArray *nestedFiles = [fm contentsOfDirectoryAtPath:nestedIcons error:NULL];
|
NSArray *nestedFiles = [fm contentsOfDirectoryAtPath:nestedIcons error:NULL];
|
||||||
if (nestedFiles.count > 0) {
|
if (nestedFiles.count > 0) {
|
||||||
// 确保目标 icons 目录存在
|
// 确保目标 icons 目录存在
|
||||||
[fm createDirectoryAtPath:iconsDir
|
[fm createDirectoryAtPath:workingIconsDir
|
||||||
withIntermediateDirectories:YES
|
withIntermediateDirectories:YES
|
||||||
attributes:nil
|
attributes:nil
|
||||||
error:NULL];
|
error:NULL];
|
||||||
// 将 icons 下所有文件上移一层
|
// 将 icons 下所有文件上移一层
|
||||||
for (NSString *fn in nestedFiles) {
|
for (NSString *fn in nestedFiles) {
|
||||||
NSString *from = [nestedIcons stringByAppendingPathComponent:fn];
|
NSString *from = [nestedIcons stringByAppendingPathComponent:fn];
|
||||||
NSString *to = [iconsDir stringByAppendingPathComponent:fn];
|
NSString *to = [workingIconsDir stringByAppendingPathComponent:fn];
|
||||||
[fm removeItemAtPath:to error:nil];
|
[fm removeItemAtPath:to error:nil];
|
||||||
[fm moveItemAtPath:from toPath:to error:nil];
|
[fm moveItemAtPath:from toPath:to error:nil];
|
||||||
}
|
}
|
||||||
@@ -355,20 +377,65 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
// 处理 background.png:若在子目录下存在,则上移到 skinRoot
|
// 处理 background.png:若在子目录下存在,则上移到 skinRoot
|
||||||
NSString *nestedBg = [nestedRoot stringByAppendingPathComponent:@"background.png"];
|
NSString *nestedBg = [nestedRoot stringByAppendingPathComponent:@"background.png"];
|
||||||
if ([fm fileExistsAtPath:nestedBg]) {
|
if ([fm fileExistsAtPath:nestedBg]) {
|
||||||
[fm removeItemAtPath:bgPath error:nil];
|
[fm removeItemAtPath:workingBgPath error:nil];
|
||||||
[fm moveItemAtPath:nestedBg toPath:bgPath error:nil];
|
[fm moveItemAtPath:nestedBg toPath:workingBgPath error:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useTempRoot) {
|
||||||
|
NSString *backupName = [NSString stringWithFormat:@"%@__bak_%@", skinId, (tempToken ?: @"0")];
|
||||||
|
NSString *backupRoot = [skinsRoot stringByAppendingPathComponent:backupName];
|
||||||
|
[fm removeItemAtPath:backupRoot error:nil];
|
||||||
|
NSError *swapError = nil;
|
||||||
|
BOOL movedOld = NO;
|
||||||
|
if ([fm fileExistsAtPath:skinRoot]) {
|
||||||
|
movedOld = [fm moveItemAtPath:skinRoot toPath:backupRoot error:&swapError];
|
||||||
|
if (!movedOld && swapError) {
|
||||||
|
zipOK = NO;
|
||||||
|
if (!innerError) {
|
||||||
|
innerError = [NSError errorWithDomain:KBSkinBridgeErrorDomain
|
||||||
|
code:KBSkinBridgeErrorUnzipFailed
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey: @"Failed to backup old skin"}];
|
||||||
|
}
|
||||||
|
NSLog(@"❌[SkinBridge] backup failed id=%@ error=%@", skinId, swapError);
|
||||||
|
dispatch_group_leave(group);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOOL movedNew = [fm moveItemAtPath:workingRoot toPath:skinRoot error:&swapError];
|
||||||
|
if (!movedNew || swapError) {
|
||||||
|
zipOK = NO;
|
||||||
|
if (!innerError) {
|
||||||
|
innerError = [NSError errorWithDomain:KBSkinBridgeErrorDomain
|
||||||
|
code:KBSkinBridgeErrorUnzipFailed
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey: @"Failed to replace skin assets"}];
|
||||||
|
}
|
||||||
|
if (movedOld) {
|
||||||
|
[fm moveItemAtPath:backupRoot toPath:skinRoot error:nil];
|
||||||
|
}
|
||||||
|
NSLog(@"❌[SkinBridge] replace failed id=%@ error=%@", skinId, swapError);
|
||||||
|
dispatch_group_leave(group);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (movedOld) {
|
||||||
|
[fm removeItemAtPath:backupRoot error:nil];
|
||||||
|
}
|
||||||
|
NSLog(@"🧹[SkinBridge] replaced old skin id=%@", skinId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记已成功解压一次(即使 icons 目录结构需要后续整理)。
|
||||||
|
didUnzip = YES;
|
||||||
|
NSLog(@"✅[SkinBridge] unzip done id=%@", skinId);
|
||||||
dispatch_group_leave(group);
|
dispatch_group_leave(group);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if __has_include("KBNetworkManager.h")
|
#if __has_include("KBNetworkManager.h")
|
||||||
// 远程下载(http/https)
|
// 远程下载(http/https)
|
||||||
NSLog(@"[SkinBridge] will GET zip: %@", zipURL);
|
NSLog(@"🌐[SkinBridge] will GET zip: %@", zipURL);
|
||||||
[KBHUD showWithStatus:@"正在下载..."];
|
[KBHUD showWithStatus:@"正在下载..."];
|
||||||
[[KBNetworkManager shared] GETData:zipURL parameters:nil headers:nil completion:^(NSData *data, NSURLResponse *response, NSError *error) {
|
[[KBNetworkManager shared] GETData:zipURL parameters:nil headers:nil completion:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||||
NSLog(@"[SkinBridge] GET finished, error = %@", error);
|
NSLog(@"🌐[SkinBridge] GET finished id=%@ error=%@", skinId, error);
|
||||||
if (error || data.length == 0) {
|
if (error || data.length == 0) {
|
||||||
zipOK = NO;
|
zipOK = NO;
|
||||||
if (!innerError) {
|
if (!innerError) {
|
||||||
@@ -399,6 +466,9 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
NSLog(@"ℹ️[SkinBridge] skip download id=%@ force=%d cached=%d zip=%@",
|
||||||
|
skinId, forceDownload, hasCachedAssets, zipURL);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
zipOK = NO;
|
zipOK = NO;
|
||||||
@@ -411,11 +481,12 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||||
// 若既没有预先存在的缓存资源,也没有在本次流程中成功解压出资源,
|
// 若既没有预先存在的缓存资源,也没有在本次流程中成功解压出资源,
|
||||||
// 说明当前皮肤 B 的资源完全不可用,此时不应覆盖现有皮肤主题。
|
// 说明当前皮肤 B 的资源完全不可用,此时不应覆盖现有皮肤主题。
|
||||||
BOOL hasAssets = (hasCachedAssets || didUnzip);
|
BOOL hasAssets = (didUnzip || (!forceDownload && hasCachedAssets));
|
||||||
if (!hasAssets) {
|
if (!hasAssets) {
|
||||||
NSError *finalError = innerError ?: [NSError errorWithDomain:KBSkinBridgeErrorDomain
|
NSError *finalError = innerError ?: [NSError errorWithDomain:KBSkinBridgeErrorDomain
|
||||||
code:KBSkinBridgeErrorZipMissing
|
code:KBSkinBridgeErrorZipMissing
|
||||||
userInfo:@{NSLocalizedDescriptionKey: @"Zip resource not available"}];
|
userInfo:@{NSLocalizedDescriptionKey: @"Zip resource not available"}];
|
||||||
|
NSLog(@"❌[SkinBridge] apply aborted id=%@ error=%@", skinId, finalError);
|
||||||
if (completion) completion(NO, finalError);
|
if (completion) completion(NO, finalError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -459,6 +530,10 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
|
|||||||
userInfo:nil];
|
userInfo:nil];
|
||||||
}
|
}
|
||||||
if (completion) completion(ok, finalError);
|
if (completion) completion(ok, finalError);
|
||||||
|
NSLog(@"%@ [SkinBridge] apply %@ id=%@",
|
||||||
|
(ok ? @"✅" : @"❌"),
|
||||||
|
(ok ? @"ok" : @"failed"),
|
||||||
|
skinId);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
NSString *preview = [skinJSON[@"preview"] isKindOfClass:NSString.class] ? skinJSON[@"preview"] : nil;
|
NSString *preview = [skinJSON[@"preview"] isKindOfClass:NSString.class] ? skinJSON[@"preview"] : nil;
|
||||||
[self recordInstalledSkinWithId:skinId
|
[self recordInstalledSkinWithId:skinId
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer,
|
|||||||
|
|
||||||
- (BOOL)applyTheme:(KBSkinTheme *)theme {
|
- (BOOL)applyTheme:(KBSkinTheme *)theme {
|
||||||
if (!theme) return NO;
|
if (!theme) return NO;
|
||||||
|
NSLog(@"🎨[SkinManager] apply theme id=%@ name=%@", theme.skinId, theme.name);
|
||||||
// 将主题写入 App Group 存储(失败也不影响本次进程内的使用)
|
// 将主题写入 App Group 存储(失败也不影响本次进程内的使用)
|
||||||
[self p_saveToStore:theme];
|
[self p_saveToStore:theme];
|
||||||
// 始终更新当前主题并广播通知,确保当前进程和扩展之间保持同步。
|
// 始终更新当前主题并广播通知,确保当前进程和扩展之间保持同步。
|
||||||
|
|||||||
@@ -42,6 +42,13 @@
|
|||||||
if (completion) completion(NO);
|
if (completion) completion(NO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
BOOL forceDownload = NO;
|
||||||
|
id forceValue = skinJSON[@"force_download"];
|
||||||
|
if ([forceValue respondsToSelector:@selector(boolValue)]) {
|
||||||
|
forceDownload = [forceValue boolValue];
|
||||||
|
}
|
||||||
|
NSLog(@"🧩[SkinService] apply mode=%lu id=%@ force=%d",
|
||||||
|
(unsigned long)mode, skinJSON[@"id"], forceDownload);
|
||||||
|
|
||||||
// // 1. 点击应用皮肤时,检查键盘启用 & 完全访问状态,并尽量给出友好提示。
|
// // 1. 点击应用皮肤时,检查键盘启用 & 完全访问状态,并尽量给出友好提示。
|
||||||
// KBKeyboardPermissionManager *perm = [KBKeyboardPermissionManager shared];
|
// KBKeyboardPermissionManager *perm = [KBKeyboardPermissionManager shared];
|
||||||
|
|||||||
@@ -242,6 +242,7 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) {
|
|||||||
[KBHUD showInfo:KBLocalized(@"正在加载主题详情")];
|
[KBHUD showInfo:KBLocalized(@"正在加载主题详情")];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
NSLog(@"🧩[SkinDetail] action themeId=%@ purchased=%d", self.themeId, self.detailModel.isPurchased);
|
||||||
if (self.detailModel.isPurchased) {
|
if (self.detailModel.isPurchased) {
|
||||||
[self requestDownload];
|
[self requestDownload];
|
||||||
} else {
|
} else {
|
||||||
@@ -287,11 +288,17 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) {
|
|||||||
if (self.detailModel.themePreviewImageUrl.length > 0) {
|
if (self.detailModel.themePreviewImageUrl.length > 0) {
|
||||||
skin[@"preview"] = self.detailModel.themePreviewImageUrl;
|
skin[@"preview"] = self.detailModel.themePreviewImageUrl;
|
||||||
}
|
}
|
||||||
|
skin[@"force_download"] = @(YES);
|
||||||
|
NSLog(@"⬇️[SkinDetail] download request id=%@ zip=%@ force=YES",
|
||||||
|
skin[@"id"], skin[@"zip_url"]);
|
||||||
[KBHUD showWithStatus:@"正在下载..."];
|
[KBHUD showWithStatus:@"正在下载..."];
|
||||||
[[KBSkinService shared] applySkinWithJSON:skin
|
[[KBSkinService shared] applySkinWithJSON:skin
|
||||||
fromViewController:self
|
fromViewController:self
|
||||||
mode:KBSkinSourceModeRemoteZip
|
mode:KBSkinSourceModeRemoteZip
|
||||||
completion:^(BOOL success) {
|
completion:^(BOOL success) {
|
||||||
|
NSLog(@"%@[SkinDetail] download result id=%@",
|
||||||
|
(success ? @"✅" : @"❌"),
|
||||||
|
self.detailModel.themeId);
|
||||||
if (success) {
|
if (success) {
|
||||||
NSString *themeId = self.detailModel.themeId;
|
NSString *themeId = self.detailModel.themeId;
|
||||||
if (themeId.length > 0) {
|
if (themeId.length > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user