mirror of
https://github.com/opa334/TrollStore.git
synced 2026-07-02 03:00:39 +08:00
1.0.8
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
<string>iPhoneOS</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0.7</string>
|
||||
<string>1.0.8</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIDeviceFamily</key>
|
||||
|
||||
@@ -28,6 +28,48 @@
|
||||
self.tableView.allowsMultipleSelectionDuringEditing = NO;
|
||||
}
|
||||
|
||||
- (void)showError:(NSError*)error
|
||||
{
|
||||
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Error %ld", error.code] message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert];
|
||||
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
|
||||
[errorAlert addAction:closeAction];
|
||||
[self presentViewController:errorAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)uninstallPressedForRowAtIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
TSApplicationsManager* appsManager = [TSApplicationsManager sharedInstance];
|
||||
|
||||
NSString* appPath = [appsManager installedAppPaths][indexPath.row];
|
||||
NSString* appId = [appsManager appIdForAppPath:appPath];
|
||||
NSString* appName = [appsManager displayNameForAppPath:appPath];
|
||||
|
||||
UIAlertController* confirmAlert = [UIAlertController alertControllerWithTitle:@"Confirm Uninstallation" message:[NSString stringWithFormat:@"Uninstalling the app '%@' will delete the app and all data associated to it.", appName] preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* uninstallAction = [UIAlertAction actionWithTitle:@"Uninstall" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
|
||||
{
|
||||
if(appId)
|
||||
{
|
||||
[appsManager uninstallApp:appId];
|
||||
}
|
||||
else
|
||||
{
|
||||
[appsManager uninstallAppByPath:appPath];
|
||||
}
|
||||
}];
|
||||
[confirmAlert addAction:uninstallAction];
|
||||
|
||||
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
|
||||
[confirmAlert addAction:cancelAction];
|
||||
|
||||
[self presentViewController:confirmAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)deselectRow
|
||||
{
|
||||
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
@@ -51,20 +93,50 @@
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||
if(editingStyle == UITableViewCellEditingStyleDelete)
|
||||
{
|
||||
NSString* appPath = [[TSApplicationsManager sharedInstance] installedAppPaths][indexPath.row];
|
||||
NSString* appId = [[TSApplicationsManager sharedInstance] appIdForAppPath:appPath];
|
||||
|
||||
if(appId)
|
||||
{
|
||||
[[TSApplicationsManager sharedInstance] uninstallApp:appId];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[TSApplicationsManager sharedInstance] uninstallAppByPath:appPath];
|
||||
}
|
||||
[self uninstallPressedForRowAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TSApplicationsManager* appsManager = [TSApplicationsManager sharedInstance];
|
||||
|
||||
NSString* appPath = [appsManager installedAppPaths][indexPath.row];
|
||||
NSString* appId = [appsManager appIdForAppPath:appPath];
|
||||
NSString* appName = [appsManager displayNameForAppPath:appPath];
|
||||
|
||||
UIAlertController* appSelectAlert = [UIAlertController alertControllerWithTitle:appName message:appId preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
/*UIAlertAction* detachAction = [UIAlertAction actionWithTitle:@"Detach from TrollStore" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
|
||||
{
|
||||
int detachRet = [appsManager detachFromApp:appId];
|
||||
if(detachRet != 0)
|
||||
{
|
||||
[self showError:[appsManager errorForCode:detachRet]];
|
||||
}
|
||||
[self deselectRow];
|
||||
}];
|
||||
[appSelectAlert addAction:detachAction];*/
|
||||
|
||||
UIAlertAction* uninstallAction = [UIAlertAction actionWithTitle:@"Uninstall App" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
|
||||
{
|
||||
[self uninstallPressedForRowAtIndexPath:indexPath];
|
||||
[self deselectRow];
|
||||
}];
|
||||
[appSelectAlert addAction:uninstallAction];
|
||||
|
||||
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action)
|
||||
{
|
||||
[self deselectRow];
|
||||
}];
|
||||
[appSelectAlert addAction:cancelAction];
|
||||
|
||||
appSelectAlert.popoverPresentationController.sourceView = tableView;
|
||||
appSelectAlert.popoverPresentationController.sourceRect = [tableView rectForRowAtIndexPath:indexPath];
|
||||
|
||||
[self presentViewController:appSelectAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -14,9 +14,10 @@
|
||||
- (NSString*)displayNameForAppPath:(NSString*)appPath;
|
||||
|
||||
- (NSError*)errorForCode:(int)code;
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force;
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut;
|
||||
- (int)installIpa:(NSString*)pathToIpa;
|
||||
- (int)uninstallApp:(NSString*)appId;
|
||||
- (int)uninstallAppByPath:(NSString*)path;
|
||||
//- (int)detachFromApp:(NSString*)appId;
|
||||
|
||||
@end
|
||||
@@ -24,7 +24,13 @@
|
||||
- (NSDictionary*)infoDictionaryForAppPath:(NSString*)appPath
|
||||
{
|
||||
NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"];
|
||||
return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
|
||||
NSError* error;
|
||||
NSDictionary* infoDict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:infoPlistPath] error:&error];
|
||||
if(error)
|
||||
{
|
||||
NSLog(@"error getting info dict: %@", error);
|
||||
}
|
||||
return infoDict;
|
||||
}
|
||||
|
||||
- (NSString*)appIdForAppPath:(NSString*)appPath
|
||||
@@ -35,7 +41,6 @@
|
||||
- (NSString*)displayNameForAppPath:(NSString*)appPath
|
||||
{
|
||||
NSDictionary* infoDict = [self infoDictionaryForAppPath:appPath];
|
||||
|
||||
NSString* displayName = infoDict[@"CFBundleDisplayName"];
|
||||
if(![displayName isKindOfClass:[NSString class]]) displayName = nil;
|
||||
if(!displayName || [displayName isEqualToString:@""])
|
||||
@@ -57,12 +62,14 @@
|
||||
NSString* errorDescription = @"Unknown Error";
|
||||
switch(code)
|
||||
{
|
||||
// IPA install errors
|
||||
case 166:
|
||||
errorDescription = @"The IPA file does not exist or is not accessible.";
|
||||
break;
|
||||
case 167:
|
||||
errorDescription = @"The IPA file does not appear to contain an app.";
|
||||
break;
|
||||
// App install errors
|
||||
case 170:
|
||||
errorDescription = @"Failed to create container for app bundle.";
|
||||
break;
|
||||
@@ -70,27 +77,46 @@
|
||||
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";
|
||||
errorDescription = @"The app does not contain an Info.plist file.";
|
||||
break;
|
||||
case 173:
|
||||
errorDescription = @"The app is not signed with a fake CoreTrust certificate and ldid does not seem to be installed. Make sure ldid is installed in the settings tab and try again.";
|
||||
errorDescription = @"The app is not signed with a fake CoreTrust certificate and ldid is not installed. Install ldid in the settings tab and try again.";
|
||||
break;
|
||||
case 174:
|
||||
errorDescription = @"The apps main executable does not exists.";
|
||||
break;
|
||||
case 175:
|
||||
errorDescription = @"Failed to sign the app. ldid returned a non zero status code.";
|
||||
break;
|
||||
case 176:
|
||||
errorDescription = @"The apps Info.plist is missing required values.";
|
||||
break;
|
||||
case 177:
|
||||
errorDescription = @"Failed to mark app as TrollStore app.";
|
||||
break;
|
||||
case 178:
|
||||
errorDescription = @"Failed to copy app bundle.";
|
||||
break;
|
||||
// App detach errors
|
||||
/*case 184:
|
||||
errorDescription = @"Refusing to detach, the app is still signed with a fake root certificate. The detach option is only for when you have installed an App Store app on top of a TrollStore app.";
|
||||
break;*/
|
||||
}
|
||||
|
||||
NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
|
||||
return error;
|
||||
}
|
||||
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut
|
||||
{
|
||||
int ret;
|
||||
if(force)
|
||||
{
|
||||
ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"]);
|
||||
ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"], nil, logOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = spawnRoot(helperPath(), @[@"install", pathToIpa]);
|
||||
ret = spawnRoot(helperPath(), @[@"install", pathToIpa], nil, logOut);
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
|
||||
return ret;
|
||||
@@ -98,13 +124,13 @@
|
||||
|
||||
- (int)installIpa:(NSString*)pathToIpa
|
||||
{
|
||||
return [self installIpa:pathToIpa force:NO];
|
||||
return [self installIpa:pathToIpa force:NO log:nil];
|
||||
}
|
||||
|
||||
- (int)uninstallApp:(NSString*)appId
|
||||
{
|
||||
if(!appId) return -200;
|
||||
int ret = spawnRoot(helperPath(), @[@"uninstall", appId]);
|
||||
int ret = spawnRoot(helperPath(), @[@"uninstall", appId], nil, nil);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
|
||||
return ret;
|
||||
}
|
||||
@@ -112,9 +138,17 @@
|
||||
- (int)uninstallAppByPath:(NSString*)path
|
||||
{
|
||||
if(!path) return -200;
|
||||
int ret = spawnRoot(helperPath(), @[@"uninstall-path", path]);
|
||||
int ret = spawnRoot(helperPath(), @[@"uninstall-path", path], nil, nil);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*- (int)detachFromApp:(NSString*)appId
|
||||
{
|
||||
if(!appId) return -200;
|
||||
int ret = spawnRoot(helperPath(), @[@"detach", appId], nil, nil);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
|
||||
return ret;
|
||||
}*/
|
||||
|
||||
@end
|
||||
+133
-116
@@ -7,163 +7,180 @@
|
||||
|
||||
- (void)doIPAInstall:(NSString*)ipaPath scene:(UIWindowScene*)scene force:(BOOL)force completion:(void (^)(void))completion
|
||||
{
|
||||
UIWindow* keyWindow = nil;
|
||||
for(UIWindow* window in scene.windows)
|
||||
{
|
||||
if(window.isKeyWindow)
|
||||
{
|
||||
keyWindow = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
UIWindow* keyWindow = nil;
|
||||
for(UIWindow* window in scene.windows)
|
||||
{
|
||||
if(window.isKeyWindow)
|
||||
{
|
||||
keyWindow = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
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];
|
||||
[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];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
||||
{
|
||||
// Install IPA
|
||||
//NSString* log;
|
||||
int ret = [[TSApplicationsManager sharedInstance] installIpa:ipaPath force:force log:nil];
|
||||
|
||||
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];
|
||||
NSError* error;
|
||||
if(ret != 0)
|
||||
{
|
||||
error = [[TSApplicationsManager sharedInstance] errorForCode:ret];
|
||||
}
|
||||
|
||||
[keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil];
|
||||
}
|
||||
NSLog(@"installed app! ret:%d, error: %@", ret, error);
|
||||
|
||||
if(ret != 171)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
}];
|
||||
});
|
||||
});
|
||||
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();
|
||||
}
|
||||
}];
|
||||
[errorAlert addAction:closeAction];
|
||||
|
||||
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];
|
||||
}
|
||||
else
|
||||
{
|
||||
/*UIAlertAction* copyLogAction = [UIAlertAction actionWithTitle:@"Copy Log" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
|
||||
{
|
||||
UIPasteboard* pasteboard = [UIPasteboard generalPasteboard];
|
||||
pasteboard.string = log;
|
||||
}];
|
||||
[errorAlert addAction:copyLogAction];*/
|
||||
}
|
||||
|
||||
[keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
if(ret != 171)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
}];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
- (void)handleURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts scene:(UIWindowScene*)scene
|
||||
{
|
||||
for(UIOpenURLContext* context in URLContexts)
|
||||
{
|
||||
NSLog(@"openURLContexts %@", context.URL);
|
||||
NSURL* url = context.URL;
|
||||
if (url != nil && [url isFileURL]) {
|
||||
[url startAccessingSecurityScopedResource];
|
||||
void (^doneBlock)(BOOL) = ^(BOOL shouldExit)
|
||||
{
|
||||
[url stopAccessingSecurityScopedResource];
|
||||
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
|
||||
for(UIOpenURLContext* context in URLContexts)
|
||||
{
|
||||
NSLog(@"openURLContexts %@", context.URL);
|
||||
NSURL* url = context.URL;
|
||||
if (url != nil && [url isFileURL]) {
|
||||
[url startAccessingSecurityScopedResource];
|
||||
void (^doneBlock)(BOOL) = ^(BOOL shouldExit)
|
||||
{
|
||||
[url stopAccessingSecurityScopedResource];
|
||||
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
|
||||
|
||||
if(shouldExit)
|
||||
{
|
||||
NSLog(@"Respring + Exit");
|
||||
respring();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
if ([url.pathExtension isEqualToString:@"ipa"])
|
||||
{
|
||||
[self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{
|
||||
doneBlock(NO);
|
||||
}];
|
||||
}
|
||||
else if([url.pathExtension isEqualToString:@"tar"])
|
||||
{
|
||||
// Update TrollStore itself
|
||||
NSLog(@"Updating TrollStore...");
|
||||
int ret = spawnRoot(helperPath(), @[@"install-trollstore", url.path]);
|
||||
doneBlock(ret == 0);
|
||||
NSLog(@"Updated TrollStore!");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(shouldExit)
|
||||
{
|
||||
NSLog(@"Respring + Exit");
|
||||
respring();
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
if ([url.pathExtension isEqualToString:@"ipa"])
|
||||
{
|
||||
[self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{
|
||||
doneBlock(NO);
|
||||
}];
|
||||
}
|
||||
else if([url.pathExtension isEqualToString:@"tar"])
|
||||
{
|
||||
// Update TrollStore itself
|
||||
NSLog(@"Updating TrollStore...");
|
||||
int ret = spawnRoot(helperPath(), @[@"install-trollstore", url.path], nil, nil);
|
||||
doneBlock(ret == 0);
|
||||
NSLog(@"Updated TrollStore!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
|
||||
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
|
||||
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
|
||||
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
|
||||
|
||||
NSLog(@"scene:%@ willConnectToSession:%@ options:%@", scene, session, connectionOptions);
|
||||
UIWindowScene* windowScene = (UIWindowScene*)scene;
|
||||
_window = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
_rootViewController = [[TSRootViewController alloc] init];
|
||||
_window.rootViewController = _rootViewController;
|
||||
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
|
||||
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
|
||||
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
|
||||
|
||||
NSLog(@"scene:%@ willConnectToSession:%@ options:%@", scene, session, connectionOptions);
|
||||
UIWindowScene* windowScene = (UIWindowScene*)scene;
|
||||
_window = [[UIWindow alloc] initWithWindowScene:windowScene];
|
||||
_rootViewController = [[TSRootViewController alloc] init];
|
||||
_window.rootViewController = _rootViewController;
|
||||
[_window makeKeyAndVisible];
|
||||
|
||||
if(connectionOptions.URLContexts.count)
|
||||
{
|
||||
[self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene];
|
||||
}
|
||||
if(connectionOptions.URLContexts.count)
|
||||
{
|
||||
[self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)sceneDidDisconnect:(UIScene *)scene {
|
||||
// Called as the scene is being released by the system.
|
||||
// This occurs shortly after the scene enters the background, or when its session is discarded.
|
||||
// Release any resources associated with this scene that can be re-created the next time the scene connects.
|
||||
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
|
||||
// Called as the scene is being released by the system.
|
||||
// This occurs shortly after the scene enters the background, or when its session is discarded.
|
||||
// Release any resources associated with this scene that can be re-created the next time the scene connects.
|
||||
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
|
||||
}
|
||||
|
||||
|
||||
- (void)sceneDidBecomeActive:(UIScene *)scene {
|
||||
// Called when the scene has moved from an inactive state to an active state.
|
||||
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
|
||||
// Called when the scene has moved from an inactive state to an active state.
|
||||
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
|
||||
}
|
||||
|
||||
|
||||
- (void)sceneWillResignActive:(UIScene *)scene {
|
||||
// Called when the scene will move from an active state to an inactive state.
|
||||
// This may occur due to temporary interruptions (ex. an incoming phone call).
|
||||
// Called when the scene will move from an active state to an inactive state.
|
||||
// This may occur due to temporary interruptions (ex. an incoming phone call).
|
||||
}
|
||||
|
||||
|
||||
- (void)sceneWillEnterForeground:(UIScene *)scene {
|
||||
// Called as the scene transitions from the background to the foreground.
|
||||
// Use this method to undo the changes made on entering the background.
|
||||
// Called as the scene transitions from the background to the foreground.
|
||||
// Use this method to undo the changes made on entering the background.
|
||||
}
|
||||
|
||||
|
||||
- (void)sceneDidEnterBackground:(UIScene *)scene {
|
||||
// Called as the scene transitions from the foreground to the background.
|
||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
||||
// to restore the scene back to its current state.
|
||||
// Called as the scene transitions from the foreground to the background.
|
||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
||||
// to restore the scene back to its current state.
|
||||
}
|
||||
|
||||
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
|
||||
{
|
||||
NSLog(@"scene:%@ openURLContexts:%@", scene, URLContexts);
|
||||
[self handleURLContexts:URLContexts scene:(UIWindowScene*)scene];
|
||||
NSLog(@"scene:%@ openURLContexts:%@", scene, URLContexts);
|
||||
[self handleURLContexts:URLContexts scene:(UIWindowScene*)scene];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -225,7 +225,7 @@
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
||||
{
|
||||
spawnRoot(helperPath(), @[@"refresh-all"]);
|
||||
spawnRoot(helperPath(), @[@"refresh-all"], nil, nil);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
@@ -259,7 +259,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnRoot(helperPath(), @[@"install-ldid", location.path]);
|
||||
spawnRoot(helperPath(), @[@"install-ldid", location.path], nil, nil);
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
[self stopActivityWithCompletion:nil];
|
||||
@@ -294,7 +294,7 @@
|
||||
{
|
||||
UIAlertAction* installAction = [UIAlertAction actionWithTitle:[appProxy localizedName] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
|
||||
{
|
||||
spawnRoot(helperPath(), @[@"install-persistence-helper", appProxy.bundleIdentifier]);
|
||||
spawnRoot(helperPath(), @[@"install-persistence-helper", appProxy.bundleIdentifier], nil, nil);
|
||||
[self reloadSpecifiers];
|
||||
}];
|
||||
|
||||
@@ -314,7 +314,7 @@
|
||||
|
||||
- (void)uninstallPersistenceHelperPressed
|
||||
{
|
||||
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"]);
|
||||
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
|
||||
[self reloadSpecifiers];
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@
|
||||
|
||||
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
|
||||
{
|
||||
spawnRoot(helperPath(), @[@"uninstall-trollstore"]);
|
||||
spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
|
||||
exit(0);
|
||||
}];
|
||||
[uninstallWarningAlert addAction:continueAction];
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
@import Foundation;
|
||||
|
||||
extern NSString* helperPath(void);
|
||||
extern int spawnRoot(NSString* path, NSArray* args);
|
||||
extern void printMultilineNSString(NSString* stringToPrint);
|
||||
extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr);
|
||||
extern void respring(void);
|
||||
extern NSString* getTrollStoreVersion(void);
|
||||
+58
-5
@@ -14,7 +14,29 @@ NSString* helperPath(void)
|
||||
return [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"trollstorehelper"];
|
||||
}
|
||||
|
||||
int spawnRoot(NSString* path, NSArray* args)
|
||||
NSString* getNSStringFromFile(int fd)
|
||||
{
|
||||
NSMutableString* ms = [NSMutableString new];
|
||||
ssize_t num_read;
|
||||
char c;
|
||||
while((num_read = read(fd, &c, sizeof(c))))
|
||||
{
|
||||
[ms appendString:[NSString stringWithFormat:@"%c", c]];
|
||||
}
|
||||
return ms.copy;
|
||||
}
|
||||
|
||||
void printMultilineNSString(NSString* stringToPrint)
|
||||
{
|
||||
NSCharacterSet *separator = [NSCharacterSet newlineCharacterSet];
|
||||
NSArray* lines = [stringToPrint componentsSeparatedByCharactersInSet:separator];
|
||||
for(NSString* line in lines)
|
||||
{
|
||||
NSLog(@"%@", line);
|
||||
}
|
||||
}
|
||||
|
||||
int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr)
|
||||
{
|
||||
NSMutableArray* argsM = args.mutableCopy ?: [NSMutableArray new];
|
||||
[argsM insertObject:path.lastPathComponent atIndex:0];
|
||||
@@ -28,18 +50,35 @@ int spawnRoot(NSString* path, NSArray* args)
|
||||
}
|
||||
argsC[argCount] = NULL;
|
||||
|
||||
int rv;
|
||||
posix_spawnattr_t attr;
|
||||
rv = posix_spawnattr_init(&attr);
|
||||
if(rv != 0) return rv;
|
||||
posix_spawnattr_init(&attr);
|
||||
|
||||
posix_spawnattr_set_persona_np(&attr, 99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE);
|
||||
posix_spawnattr_set_persona_uid_np(&attr, 0);
|
||||
posix_spawnattr_set_persona_gid_np(&attr, 0);
|
||||
|
||||
posix_spawn_file_actions_t action;
|
||||
posix_spawn_file_actions_init(&action);
|
||||
|
||||
int outErr[2];
|
||||
if(stdErr)
|
||||
{
|
||||
pipe(outErr);
|
||||
posix_spawn_file_actions_adddup2(&action, outErr[1], STDERR_FILENO);
|
||||
posix_spawn_file_actions_addclose(&action, outErr[0]);
|
||||
}
|
||||
|
||||
int out[2];
|
||||
if(stdOut)
|
||||
{
|
||||
pipe(out);
|
||||
posix_spawn_file_actions_adddup2(&action, out[1], STDOUT_FILENO);
|
||||
posix_spawn_file_actions_addclose(&action, out[0]);
|
||||
}
|
||||
|
||||
pid_t task_pid;
|
||||
int status = -200;
|
||||
int spawnError = posix_spawn(&task_pid, [path UTF8String], NULL, &attr, (char* const*)argsC, NULL);
|
||||
int spawnError = posix_spawn(&task_pid, [path UTF8String], &action, &attr, (char* const*)argsC, NULL);
|
||||
posix_spawnattr_destroy(&attr);
|
||||
for (NSUInteger i = 0; i < argCount; i++)
|
||||
{
|
||||
@@ -63,6 +102,20 @@ int spawnRoot(NSString* path, NSArray* args)
|
||||
return -222;
|
||||
}
|
||||
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||
|
||||
if(stdOut)
|
||||
{
|
||||
close(out[1]);
|
||||
NSString* output = getNSStringFromFile(out[0]);
|
||||
*stdOut = output;
|
||||
}
|
||||
|
||||
if(stdErr)
|
||||
{
|
||||
close(outErr[1]);
|
||||
NSString* errorOutput = getNSStringFromFile(outErr[0]);
|
||||
*stdErr = errorOutput;
|
||||
}
|
||||
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Package: com.opa334.trollstore
|
||||
Name: TrollStore
|
||||
Version: 1.0.7
|
||||
Version: 1.0.8
|
||||
Architecture: iphoneos-arm
|
||||
Description: An awesome application!
|
||||
Maintainer: opa334
|
||||
|
||||
Reference in New Issue
Block a user