X-Git-Url: https://git.saurik.com/uikittools.git/blobdiff_plain/37e55bd3ab15f915e0b7860ded1b6f6e5aefd249..85a77f07b23019c3adfc990f653a3abfbb741e28:/uicache.mm diff --git a/uicache.mm b/uicache.mm index 91609b7..e5235f2 100644 --- a/uicache.mm +++ b/uicache.mm @@ -46,7 +46,7 @@ #include -#include +#include "csstore.hpp" @interface NSMutableArray (Cydia) - (void) addInfoDictionary:(NSDictionary *)info; @@ -58,6 +58,10 @@ [self addObject:info]; } +- (NSArray *) allInfoDictionaries { + return self; +} + @end @interface NSMutableDictionary (Cydia) @@ -71,18 +75,52 @@ [self setObject:info forKey:bundle]; } +- (NSArray *) allInfoDictionaries { + return [self allValues]; +} + +@end + +@interface LSApplicationWorkspace : NSObject ++ (id) defaultWorkspace; +- (BOOL) registerApplication:(id)application; +- (BOOL) unregisterApplication:(id)application; +- (BOOL) invalidateIconCache:(id)bundle; +- (BOOL) registerApplicationDictionary:(id)application; +- (BOOL) installApplication:(id)application withOptions:(id)options; +- (BOOL) _LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)system internal:(BOOL)internal user:(BOOL)user; @end int main(int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Class $LSApplicationWorkspace(objc_getClass("LSApplicationWorkspace")); + LSApplicationWorkspace *workspace($LSApplicationWorkspace == nil ? nil : [$LSApplicationWorkspace defaultWorkspace]); + + if (kCFCoreFoundationVersionNumber > 1000) // this API is on iOS 7 but invaliding the icon cache is harder there + if ([workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) { + if (![workspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:NO]) + fprintf(stderr, "failed to rebuild application databases"); + return 0; + } + bool respring(false); NSString *home(NSHomeDirectory()); NSString *path([NSString stringWithFormat:@"%@/Library/Caches/com.apple.mobile.installation.plist", home]); - Class $LSApplicationWorkspace(objc_getClass("LSApplicationWorkspace")); - LSApplicationWorkspace *workspace($LSApplicationWorkspace == nil ? nil : [$LSApplicationWorkspace defaultWorkspace]); + system("killall -SIGSTOP SpringBoard"); + sleep(1); + + @try { + + DeleteCSStores([home UTF8String]); + + system("killall lsd"); + + if ([workspace respondsToSelector:@selector(invalidateIconCache:)]) + while (![workspace invalidateIconCache:nil]) + sleep(1); if (NSMutableDictionary *cache = [NSMutableDictionary dictionaryWithContentsOfFile:path]) { NSFileManager *manager = [NSFileManager defaultManager]; @@ -90,11 +128,21 @@ int main(int argc, const char *argv[]) { NSMutableDictionary *bundles([NSMutableDictionary dictionaryWithCapacity:16]); - id system = [cache objectForKey:@"System"]; - if (system == nil) - goto error; + id after = [cache objectForKey:@"System"]; + if (after == nil) { error: + fprintf(stderr, "%s\n", error == nil ? strerror(errno) : [[error localizedDescription] UTF8String]); + goto cached; + } + + id before([[after copy] autorelease]); + [after removeAllObjects]; + + NSArray *cached([cache objectForKey:@"InfoPlistCachedKeys"]); - [system removeAllObjects]; + NSMutableSet *removed([NSMutableSet set]); + for (NSDictionary *info in [before allInfoDictionaries]) + if (NSString *path = [info objectForKey:@"Path"]) + [removed addObject:path]; if (NSArray *apps = [manager contentsOfDirectoryAtPath:@"/Applications" error:&error]) { for (NSString *app in apps) @@ -105,9 +153,27 @@ int main(int argc, const char *argv[]) { if (NSMutableDictionary *info = [NSMutableDictionary dictionaryWithContentsOfFile:plist]) { if (NSString *identifier = [info objectForKey:@"CFBundleIdentifier"]) { [bundles setObject:path forKey:identifier]; + [removed removeObject:path]; + + if (cached != nil) { + NSMutableDictionary *merged([before objectForKey:identifier]); + if (merged == nil) + merged = [NSMutableDictionary dictionary]; + else + merged = [[merged mutableCopy] autorelease]; + + for (NSString *key in cached) + if (NSObject *value = [info objectForKey:key]) + [merged setObject:value forKey:key]; + else + [merged removeObjectForKey:key]; + + info = merged; + } + [info setObject:path forKey:@"Path"]; [info setObject:@"System" forKey:@"ApplicationType"]; - [system addInfoDictionary:info]; + [after addInfoDictionary:info]; } else fprintf(stderr, "%s missing CFBundleIdentifier", [app UTF8String]); } @@ -117,24 +183,29 @@ int main(int argc, const char *argv[]) { [cache writeToFile:path atomically:YES]; if (workspace != nil) { - for (NSString *identifier in bundles) { - NSString *path([bundles objectForKey:identifier]); - [workspace unregisterApplication:[NSURL fileURLWithPath:path]]; - } - - for (NSString *identifier in bundles) - if ([workspace respondsToSelector:@selector(invalidateIconCache:)]) + if ([workspace respondsToSelector:@selector(invalidateIconCache:)]) { + for (NSString *identifier in bundles) [workspace invalidateIconCache:identifier]; + } else { + for (NSString *identifier in bundles) { + NSString *path([bundles objectForKey:identifier]); + [workspace unregisterApplication:[NSURL fileURLWithPath:path]]; + } + } for (NSString *identifier in bundles) { NSString *path([bundles objectForKey:identifier]); - [workspace registerApplication:[NSURL fileURLWithPath:path]]; + if (kCFCoreFoundationVersionNumber >= 800) + [workspace registerApplicationDictionary:[after objectForKey:identifier]]; + else + [workspace registerApplication:[NSURL fileURLWithPath:path]]; } - } - if (false) error: - fprintf(stderr, "%s\n", error == nil ? strerror(errno) : [[error localizedDescription] UTF8String]); + for (NSString *path in removed) + [workspace unregisterApplication:[NSURL fileURLWithPath:path]]; + } } else fprintf(stderr, "cannot open cache file. incorrect user?\n"); + cached: if (respring || kCFCoreFoundationVersionNumber >= 550.32) { unlink([[NSString stringWithFormat:@"%@/Library/Caches/com.apple.springboard-imagecache-icons", home] UTF8String]); @@ -151,6 +222,10 @@ int main(int argc, const char *argv[]) { system("killall installd"); + } @finally { + system("killall -SIGCONT SpringBoard"); + } + if (respring) system("launchctl stop com.apple.SpringBoard"); else