diff --git a/Helper/control b/Helper/control index ad89a46..1c45e31 100644 --- a/Helper/control +++ b/Helper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstoreroothelper Name: trollstoreroothelper -Version: 1.0.1 +Version: 1.0.2 Architecture: iphoneos-arm Description: An awesome tool of some sort!! Maintainer: opa334 diff --git a/Helper/main.m b/Helper/main.m index 2daa446..924261f 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -200,6 +200,16 @@ NSString* dumpEntitlements(NSString* binaryPath) return output; } +NSDictionary* dumpEntitlementsDict(NSString* binaryPath) +{ + NSString* entitlementsString = dumpEntitlements(binaryPath); + NSData* plistData = [entitlementsString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSPropertyListFormat format; + NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable format:&format error:&error]; + return plist; +} + BOOL signApp(NSString* appPath, NSError** error) { if(!isLdidInstalled()) return NO; @@ -246,8 +256,10 @@ BOOL signApp(NSString* appPath, NSError** error) // 170: failed to create container for app bundle // 171: a non trollstore app with the same identifier is already installled // 172: no info.plist found in app -int installApp(NSString* appPath, BOOL sign, NSError** error) +int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) { + NSLog(@"[installApp force = %d]", force); + NSString* appId = appIdForAppPath(appPath); if(!appId) return 172; @@ -281,12 +293,15 @@ int installApp(NSString* appPath, BOOL sign, NSError** error) // Make sure there isn't already an app store app installed with the same identifier NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"]; - if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil]) + if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force) { NSLog(@"[installApp] already installed and not a TrollStore app... bailing out"); return 171; } + // Mark app as TrollStore app + [[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil]; + // Apply correct permissions NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil]; NSURL* fileURL; @@ -342,7 +357,7 @@ int installApp(NSString* appPath, BOOL sign, NSError** error) while(fileURL = [enumerator nextObject]) { // do not under any circumstance delete this file as it makes iOS loose the app registration - if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"]) + if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] || [fileURL.lastPathComponent isEqualToString:@"_TrollStore"]) { NSLog(@"[installApp] skip removal of %@", fileURL); continue; @@ -359,9 +374,6 @@ int installApp(NSString* appPath, BOOL sign, NSError** error) BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appPath toPath:newAppPath error:error]; if(suc) { - // Mark app as TrollStore app - [[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil]; - NSLog(@"[installApp] app installed, adding to icon cache now..."); registerPath((char*)newAppPath.UTF8String, 0); return 0; @@ -382,6 +394,7 @@ int uninstallApp(NSString* appId, NSError** error) MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil]; + NSLog(@"1"); NSString *containerPath = [appContainer url].path; if(containerPath) { @@ -391,11 +404,11 @@ int uninstallApp(NSString* appId, NSError** error) } // delete group container paths - for(NSURL* groupURL in [appProxy groupContainerURLs]) + [[appProxy groupContainerURLs] enumerateKeysAndObjectsUsingBlock:^(NSString* groupID, NSURL* groupURL, BOOL* stop) { - [[NSFileManager defaultManager] removeItemAtPath:groupURL.path error:error]; - NSLog(@"deleting %@", groupURL.path); - } + [[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil]; + NSLog(@"deleting %@", groupURL); + }]; // delete app plugin paths for(LSPlugInKitProxy* pluginProxy in appProxy.plugInKitPlugins) @@ -427,7 +440,7 @@ int uninstallApp(NSString* appId, NSError** error) // 166: IPA does not exist or is not accessible // 167: IPA does not appear to contain an app -int installIpa(NSString* ipaPath, NSError** error) +int installIpa(NSString* ipaPath, BOOL force, NSError** error) { if(![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) return 166; @@ -455,7 +468,7 @@ int installIpa(NSString* ipaPath, NSError** error) } if(!tmpAppPath) return 167; - int ret = installApp(tmpAppPath, YES, error); + int ret = installApp(tmpAppPath, YES, force, error); [[NSFileManager defaultManager] removeItemAtPath:tmpAppPath error:nil]; @@ -530,7 +543,7 @@ BOOL installTrollStore(NSString* pathToTar) _installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper); } - return installApp(tmpTrollStore, NO, nil);; + return installApp(tmpTrollStore, NO, YES, nil);; } void refreshAppRegistrations() @@ -663,9 +676,19 @@ int main(int argc, char *argv[], char *envp[]) { NSString* cmd = [NSString stringWithUTF8String:argv[1]]; if([cmd isEqualToString:@"install"]) { + NSLog(@"argc = %d", argc); + BOOL force = NO; if(argc <= 2) return -3; + if(argc > 3) + { + NSLog(@"argv3 = %s", argv[3]); + if(!strcmp(argv[3], "force")) + { + force = YES; + } + } NSString* ipaPath = [NSString stringWithUTF8String:argv[2]]; - ret = installIpa(ipaPath, &error); + ret = installIpa(ipaPath, force, &error); } else if([cmd isEqualToString:@"uninstall"]) { if(argc <= 2) return -3; diff --git a/Helper/uicache.m b/Helper/uicache.m index f5fbb27..7199274 100644 --- a/Helper/uicache.m +++ b/Helper/uicache.m @@ -4,89 +4,247 @@ #import #import "dlfcn.h" -void registerPath(char *path, int unregister) +// uicache on steroids + +extern NSDictionary* dumpEntitlementsDict(NSString* binaryPath); + +NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups) { - if(!path) return; + if(!entitlements) return nil; - LSApplicationWorkspace *workspace = - [LSApplicationWorkspace defaultWorkspace]; - if (unregister && ![[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithUTF8String:path]]) { - LSApplicationProxy *app = [LSApplicationProxy - applicationProxyForIdentifier:[NSString stringWithUTF8String:path]]; - if (app.bundleURL) - path = (char *)[[app bundleURL] fileSystemRepresentation]; - } + NSString* entitlementForGroups; + NSString* mcmClass; + if(systemGroups) + { + entitlementForGroups = @"com.apple.security.system-groups"; + mcmClass = @"MCMSystemDataContainer"; + } + else + { + entitlementForGroups = @"com.apple.security.application-groups"; + mcmClass = @"MCMSharedDataContainer"; + } - NSString *rawPath = [NSString stringWithUTF8String:path]; - rawPath = [rawPath stringByResolvingSymlinksInPath]; + NSArray* groupIDs = entitlements[entitlementForGroups]; + if(groupIDs && [groupIDs isKindOfClass:[NSArray class]]) + { + NSMutableDictionary* groupContainers = [NSMutableDictionary new]; - NSDictionary *infoPlist = [NSDictionary - dictionaryWithContentsOfFile: - [rawPath stringByAppendingPathComponent:@"Info.plist"]]; - NSString *bundleID = [infoPlist objectForKey:@"CFBundleIdentifier"]; + for(NSString* groupID in groupIDs) + { + MCMContainer* container = [NSClassFromString(mcmClass) containerWithIdentifier:groupID createIfNecessary:YES existed:nil error:nil]; + if(container.url) + { + groupContainers[groupID] = container.url.path; + } + } - NSURL *url = [NSURL fileURLWithPath:rawPath]; + return groupContainers.copy; + } - if (bundleID && !unregister) { - MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") - containerWithIdentifier:bundleID - createIfNecessary:YES - existed:nil - error:nil]; - NSString *containerPath = [appContainer url].path; + return nil; +} - NSMutableDictionary *plist = [NSMutableDictionary dictionary]; - [plist setObject:@"System" forKey:@"ApplicationType"]; - [plist setObject:@1 forKey:@"BundleNameIsLocalized"]; - [plist setObject:bundleID forKey:@"CFBundleIdentifier"]; - [plist setObject:@0 forKey:@"CompatibilityState"]; - if (containerPath) [plist setObject:containerPath forKey:@"Container"]; - [plist setObject:@0 forKey:@"IsDeletable"]; - [plist setObject:rawPath forKey:@"Path"]; +BOOL constructContainerizationForEntitlements(NSDictionary* entitlements) +{ + NSNumber* noContainer = entitlements[@"com.apple.private.security.no-container"]; + if(noContainer && [noContainer isKindOfClass:[NSNumber class]]) + { + if(noContainer.boolValue) + { + return NO; + } + } - NSString *pluginsPath = - [rawPath stringByAppendingPathComponent:@"PlugIns"]; - NSArray *plugins = [[NSFileManager defaultManager] - contentsOfDirectoryAtPath:pluginsPath - error:nil]; + NSNumber* containerRequired = entitlements[@"com.apple.private.security.container-required"]; + if(containerRequired && [containerRequired isKindOfClass:[NSNumber class]]) + { + if(!containerRequired.boolValue) + { + return NO; + } + } - NSMutableDictionary *bundlePlugins = [NSMutableDictionary dictionary]; - for (NSString *pluginName in plugins) { - NSString *fullPath = - [pluginsPath stringByAppendingPathComponent:pluginName]; + return YES; +} - NSDictionary *infoPlist = [NSDictionary - dictionaryWithContentsOfFile: - [fullPath stringByAppendingPathComponent:@"Info.plist"]]; - NSString *pluginBundleID = - [infoPlist objectForKey:@"CFBundleIdentifier"]; - if (!pluginBundleID) continue; - MCMContainer *pluginContainer = - [objc_getClass("MCMPluginKitPluginDataContainer") - containerWithIdentifier:pluginBundleID - createIfNecessary:YES - existed:nil - error:nil]; - NSString *pluginContainerPath = [pluginContainer url].path; +NSString* constructTeamIdentifierForEntitlements(NSDictionary* entitlements) +{ + NSString* teamIdentifier = entitlements[@"com.apple.developer.team-identifier"]; + if(teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]]) + { + return teamIdentifier; + } + return nil; +} - NSMutableDictionary *pluginPlist = [NSMutableDictionary dictionary]; - [pluginPlist setObject:@"PluginKitPlugin" - forKey:@"ApplicationType"]; - [pluginPlist setObject:@1 forKey:@"BundleNameIsLocalized"]; - [pluginPlist setObject:pluginBundleID forKey:@"CFBundleIdentifier"]; - [pluginPlist setObject:@0 forKey:@"CompatibilityState"]; - [pluginPlist setObject:pluginContainerPath forKey:@"Container"]; - [pluginPlist setObject:fullPath forKey:@"Path"]; - [pluginPlist setObject:bundleID forKey:@"PluginOwnerBundleID"]; - [bundlePlugins setObject:pluginPlist forKey:pluginBundleID]; - } - [plist setObject:bundlePlugins forKey:@"_LSBundlePlugins"]; - if (![workspace registerApplicationDictionary:plist]) { - fprintf(stderr, "Error: Unable to register %s\n", path); - } - } else { - if (![workspace unregisterApplication:url]) { - fprintf(stderr, "Error: Unable to unregister %s\n", path); - } - } +NSDictionary* constructEnvironmentVariablesForContainerPath(NSString* containerPath) +{ + NSString* tmpDir = [containerPath stringByAppendingPathComponent:@"tmp"]; + return @{ + @"CFFIXED_USER_HOME" : containerPath, + @"HOME" : containerPath, + @"TMPDIR" : tmpDir + }; +} + +void registerPath(char* cPath, int unregister) +{ + if(!cPath) return; + NSString* path = [NSString stringWithUTF8String:cPath]; + + LSApplicationWorkspace* workspace = [LSApplicationWorkspace defaultWorkspace]; + if(unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path]) + { + LSApplicationProxy* app = [LSApplicationProxy applicationProxyForIdentifier:path]; + if(app.bundleURL) + { + path = [app bundleURL].path; + } + } + + path = [path stringByResolvingSymlinksInPath]; + + NSDictionary* appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]]; + NSString* appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"]; + + if(appBundleID && !unregister) + { + MCMContainer* appContainer = [NSClassFromString(@"MCMAppDataContainer") containerWithIdentifier:appBundleID createIfNecessary:YES existed:nil error:nil]; + NSString* containerPath = [appContainer url].path; + + NSMutableDictionary* dictToRegister = [NSMutableDictionary dictionary]; + + // Add entitlements + + NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]]; + NSDictionary* entitlements = dumpEntitlementsDict(appExecutablePath); + if(entitlements) + { + dictToRegister[@"Entitlements"] = entitlements; + } + + // Misc + + dictToRegister[@"ApplicationType"] = @"System"; + dictToRegister[@"BundleNameIsLocalized"] = @1; + dictToRegister[@"CFBundleIdentifier"] = appBundleID; + dictToRegister[@"CodeInfoIdentifier"] = appBundleID; + dictToRegister[@"CompatibilityState"] = @0; + if(containerPath) + { + dictToRegister[@"Container"] = containerPath; + dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath); + } + dictToRegister[@"IsDeletable"] = @0; + dictToRegister[@"Path"] = path; + dictToRegister[@"IsContainerized"] = @(constructContainerizationForEntitlements(entitlements)); + + NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements); + if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier; + + // Add group containers + + NSDictionary* appGroupContainers = constructGroupsContainersForEntitlements(entitlements, NO); + NSDictionary* systemGroupContainers = constructGroupsContainersForEntitlements(entitlements, NO); + NSMutableDictionary* groupContainers = [NSMutableDictionary new]; + [groupContainers addEntriesFromDictionary:appGroupContainers]; + [groupContainers addEntriesFromDictionary:systemGroupContainers]; + if(groupContainers.count) + { + if(appGroupContainers.count) + { + dictToRegister[@"HasAppGroupContainers"] = @YES; + } + if(systemGroupContainers.count) + { + dictToRegister[@"HasSystemGroupContainers"] = @YES; + } + dictToRegister[@"GroupContainers"] = groupContainers.copy; + } + + // Add plugins + + NSString* pluginsPath = [path stringByAppendingPathComponent:@"PlugIns"]; + NSArray* plugins = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginsPath error:nil]; + + NSMutableDictionary* bundlePlugins = [NSMutableDictionary dictionary]; + for (NSString* pluginName in plugins) + { + NSString* pluginPath = [pluginsPath stringByAppendingPathComponent:pluginName]; + + NSDictionary* pluginInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[pluginPath stringByAppendingPathComponent:@"Info.plist"]]; + NSString* pluginBundleID = [pluginInfoPlist objectForKey:@"CFBundleIdentifier"]; + + if(!pluginBundleID) continue; + MCMContainer* pluginContainer = [NSClassFromString(@"MCMPluginKitPluginDataContainer") containerWithIdentifier:pluginBundleID createIfNecessary:YES existed:nil error:nil]; + NSString* pluginContainerPath = [pluginContainer url].path; + + NSMutableDictionary* pluginDict = [NSMutableDictionary dictionary]; + + // Add entitlements + + NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]]; + NSDictionary* pluginEntitlements = dumpEntitlementsDict(pluginExecutablePath); + if(pluginEntitlements) + { + pluginDict[@"Entitlements"] = pluginEntitlements; + } + + // Misc + + pluginDict[@"ApplicationType"] = @"PluginKitPlugin"; + pluginDict[@"BundleNameIsLocalized"] = @1; + pluginDict[@"CFBundleIdentifier"] = pluginBundleID; + pluginDict[@"CodeInfoIdentifier"] = pluginBundleID; + pluginDict[@"CompatibilityState"] = @0; + if(pluginContainerPath) + { + pluginDict[@"Container"] = pluginContainerPath; + pluginDict[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(pluginContainerPath); + } + pluginDict[@"Path"] = pluginPath; + pluginDict[@"PluginOwnerBundleID"] = appBundleID; + pluginDict[@"IsContainerized"] = @(constructContainerizationForEntitlements(pluginEntitlements)); + + NSString* pluginTeamIdentifier = constructTeamIdentifierForEntitlements(pluginEntitlements); + if(pluginTeamIdentifier) pluginDict[@"TeamIdentifier"] = pluginTeamIdentifier; + + // Add plugin group containers + + NSDictionary* pluginAppGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO); + NSDictionary* pluginSystemGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO); + NSMutableDictionary* pluginGroupContainers = [NSMutableDictionary new]; + [pluginGroupContainers addEntriesFromDictionary:pluginAppGroupContainers]; + [pluginGroupContainers addEntriesFromDictionary:pluginSystemGroupContainers]; + if(pluginGroupContainers.count) + { + if(pluginAppGroupContainers.count) + { + pluginDict[@"HasAppGroupContainers"] = @YES; + } + if(pluginSystemGroupContainers.count) + { + pluginDict[@"HasSystemGroupContainers"] = @YES; + } + pluginDict[@"GroupContainers"] = pluginGroupContainers.copy; + } + + [bundlePlugins setObject:pluginDict forKey:pluginBundleID]; + } + [dictToRegister setObject:bundlePlugins forKey:@"_LSBundlePlugins"]; + + if(![workspace registerApplicationDictionary:dictToRegister]) + { + NSLog(@"Error: Unable to register %@", path); + } + } + else + { + NSURL* url = [NSURL fileURLWithPath:path]; + if(![workspace unregisterApplication:url]) + { + NSLog(@"Error: Unable to unregister %@", path); + } + } } \ No newline at end of file diff --git a/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c b/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c index d858d94..1dc0c93 100644 --- a/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c +++ b/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c @@ -65,6 +65,7 @@ int IOGPU_get_command_queue_extra_refills_needed(void) || strstr(u.machine, "iPhone14,") || strstr(u.machine, "iPad13,") || strstr(u.machine, "iPad7,") + || strstr(u.machine, "iPad12,") ) { return 1; @@ -72,10 +73,12 @@ int IOGPU_get_command_queue_extra_refills_needed(void) // iPhone 8, X // iPhone XS, XR // iPad Pro A12Z + // iPad 8 A12 else if ( strstr(u.machine, "iPhone10,") || strstr(u.machine, "iPhone11,") || strstr(u.machine, "iPad8,") + || strstr(u.machine, "iPad11,") ) { return 3; diff --git a/PersistenceHelper/Resources/Info.plist b/PersistenceHelper/Resources/Info.plist index d5c96d0..ca48dbd 100644 --- a/PersistenceHelper/Resources/Info.plist +++ b/PersistenceHelper/Resources/Info.plist @@ -52,7 +52,7 @@ iPhoneOS CFBundleVersion - 1.0 + 1.0.2 LSRequiresIPhoneOS UIDeviceFamily diff --git a/PersistenceHelper/Resources/trollstorehelper b/PersistenceHelper/Resources/trollstorehelper deleted file mode 100755 index 7d5533e..0000000 Binary files a/PersistenceHelper/Resources/trollstorehelper and /dev/null differ diff --git a/PersistenceHelper/control b/PersistenceHelper/control index 618e6b7..e805279 100644 --- a/PersistenceHelper/control +++ b/PersistenceHelper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstorehelper Name: TrollStore Helper -Version: 1.0 +Version: 1.0.2 Architecture: iphoneos-arm Description: Helper app to install and manage TrollStore! Maintainer: opa334 diff --git a/Store/Resources/Info.plist b/Store/Resources/Info.plist index 16d3172..639658b 100644 --- a/Store/Resources/Info.plist +++ b/Store/Resources/Info.plist @@ -50,7 +50,7 @@ iPhoneOS CFBundleVersion - 1.0.1 + 1.0.2 LSRequiresIPhoneOS UIDeviceFamily diff --git a/Store/TSApplicationsManager.h b/Store/TSApplicationsManager.h index 2d4220f..2b238f7 100644 --- a/Store/TSApplicationsManager.h +++ b/Store/TSApplicationsManager.h @@ -14,6 +14,7 @@ - (NSString*)displayNameForAppPath:(NSString*)appPath; - (NSError*)errorForCode:(int)code; +- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force; - (int)installIpa:(NSString*)pathToIpa; - (int)uninstallApp:(NSString*)appId; diff --git a/Store/TSApplicationsManager.m b/Store/TSApplicationsManager.m index 979ca7d..957a3eb 100644 --- a/Store/TSApplicationsManager.m +++ b/Store/TSApplicationsManager.m @@ -67,7 +67,7 @@ errorDescription = @"Failed to create container for app bundle."; break; case 171: - errorDescription = @"A non-TrollStore app with the same identifier is already installed. If you are absolutely sure it is not, try refreshing icon cache in TrollStore settings or try rebooting your device."; + errorDescription = @"A non-TrollStore app with the same identifier is already installed. If you are absolutely sure it is not, you can force install it."; break; case 172: errorDescription = @"The app does not seem to contain an Info.plist"; @@ -78,13 +78,26 @@ return error; } -- (int)installIpa:(NSString*)pathToIpa +- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force { - int ret = spawnRoot(helperPath(), @[@"install", pathToIpa]); + int ret; + if(force) + { + ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"]); + } + else + { + ret = spawnRoot(helperPath(), @[@"install", pathToIpa]); + } [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; return ret; } +- (int)installIpa:(NSString*)pathToIpa +{ + return [self installIpa:pathToIpa force:NO]; +} + - (int)uninstallApp:(NSString*)appId { int ret = spawnRoot(helperPath(), @[@"uninstall", appId]); diff --git a/Store/TSSceneDelegate.m b/Store/TSSceneDelegate.m index ae0db64..55b1a1d 100644 --- a/Store/TSSceneDelegate.m +++ b/Store/TSSceneDelegate.m @@ -5,7 +5,7 @@ @implementation TSSceneDelegate -- (void)handleURLContexts:(NSSet *)URLContexts scene:(UIWindowScene*)scene +- (void)doIPAInstall:(NSString*)ipaPath scene:(UIWindowScene*)scene force:(BOOL)force completion:(void (^)(void))completion { UIWindow* keyWindow = nil; for(UIWindow* window in scene.windows) @@ -17,6 +17,60 @@ } } + UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert]; + UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)]; + activityIndicator.hidesWhenStopped = YES; + activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium; + [activityIndicator startAnimating]; + [infoAlert.view addSubview:activityIndicator]; + + [keyWindow.rootViewController presentViewController:infoAlert animated:YES completion:nil]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ + { + // Install IPA + int ret = [[TSApplicationsManager sharedInstance] installIpa:ipaPath force:force]; + NSError* error = [[TSApplicationsManager sharedInstance] errorForCode:ret]; + + NSLog(@"installed app! ret:%d, error: %@", ret, error); + dispatch_async(dispatch_get_main_queue(), ^ + { + [infoAlert dismissViewControllerAnimated:YES completion:^ + { + if(ret != 0) + { + UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) + { + if(ret == 171) + { + completion(); + } + }]; + if(ret == 171) + { + UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) + { + [self doIPAInstall:ipaPath scene:scene force:YES completion:completion]; + }]; + [errorAlert addAction:forceInstallAction]; + } + [errorAlert addAction:closeAction]; + + [keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil]; + } + + if(ret != 171) + { + completion(); + } + }]; + }); + }); +} + +- (void)handleURLContexts:(NSSet *)URLContexts scene:(UIWindowScene*)scene +{ for(UIOpenURLContext* context in URLContexts) { NSLog(@"openURLContexts %@", context.URL); @@ -39,43 +93,13 @@ respring(); exit(0); } - }; + }; if ([url.pathExtension isEqualToString:@"ipa"]) { - UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert]; - UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)]; - activityIndicator.hidesWhenStopped = YES; - activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium; - [activityIndicator startAnimating]; - [infoAlert.view addSubview:activityIndicator]; - - [keyWindow.rootViewController presentViewController:infoAlert animated:YES completion:nil]; - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ - { - // Install IPA - int ret = [[TSApplicationsManager sharedInstance] installIpa:tmpCopyURL.path]; - NSError* error = [[TSApplicationsManager sharedInstance] errorForCode:ret]; - - NSLog(@"installed app! ret:%d, error: %@", ret, error); - dispatch_async(dispatch_get_main_queue(), ^ - { - [infoAlert dismissViewControllerAnimated:YES completion:^ - { - if(ret != 0) - { - UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; - [errorAlert addAction:closeAction]; - - [keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil]; - } - - doneBlock(NO); - }]; - }); - }); + [self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{ + doneBlock(NO); + }]; } else if([url.pathExtension isEqualToString:@"tar"]) { diff --git a/Store/control b/Store/control index 0238953..b69c4ba 100644 --- a/Store/control +++ b/Store/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstore Name: TrollStore -Version: 1.0.1 +Version: 1.0.2 Architecture: iphoneos-arm Description: An awesome application! Maintainer: opa334