mirror of
https://github.com/opa334/TrollStore.git
synced 2026-02-22 12:12:24 +08:00
Merge 48ba54ca67 into d11c04666a
This commit is contained in:
commit
d16ac30312
@ -807,7 +807,13 @@ int signApp(NSString* appPath)
|
||||
}
|
||||
#endif
|
||||
|
||||
void applyPatchesToInfoDictionary(NSString* appPath)
|
||||
NSString* randomStealthBundleIdentifierSuffix(void)
|
||||
{
|
||||
uint64_t randomValue = ((uint64_t)arc4random() << 32) | arc4random();
|
||||
return [NSString stringWithFormat:@"TS_%016llX", randomValue];
|
||||
}
|
||||
|
||||
void applyPatchesToInfoDictionary(NSString* appPath, BOOL stealthInstall, BOOL stripURLSchemesInStealth)
|
||||
{
|
||||
NSURL* appURL = [NSURL fileURLWithPath:appPath];
|
||||
NSURL* infoPlistURL = [appURL URLByAppendingPathComponent:@"Info.plist"];
|
||||
@ -817,41 +823,84 @@ void applyPatchesToInfoDictionary(NSString* appPath)
|
||||
// Enable Notifications
|
||||
infoDictM[@"SBAppUsesLocalNotifications"] = @1;
|
||||
|
||||
// Remove system claimed URL schemes if existant
|
||||
NSSet* appleSchemes = systemURLSchemes();
|
||||
NSArray* CFBundleURLTypes = infoDictM[@"CFBundleURLTypes"];
|
||||
if([CFBundleURLTypes isKindOfClass:[NSArray class]])
|
||||
if(stealthInstall)
|
||||
{
|
||||
NSMutableArray* CFBundleURLTypesM = [NSMutableArray new];
|
||||
|
||||
for(NSDictionary* URLType in CFBundleURLTypes)
|
||||
NSString* originalAppId = infoDictM[@"TSOriginalBundleIdentifier"];
|
||||
if(![originalAppId isKindOfClass:NSString.class] || originalAppId.length == 0)
|
||||
{
|
||||
if(![URLType isKindOfClass:[NSDictionary class]]) continue;
|
||||
|
||||
NSMutableDictionary* modifiedURLType = URLType.mutableCopy;
|
||||
NSArray* URLSchemes = URLType[@"CFBundleURLSchemes"];
|
||||
if(URLSchemes)
|
||||
{
|
||||
NSMutableSet* URLSchemesSet = [NSMutableSet setWithArray:URLSchemes];
|
||||
for(NSString* existingURLScheme in [URLSchemesSet copy])
|
||||
{
|
||||
if(![existingURLScheme isKindOfClass:[NSString class]])
|
||||
{
|
||||
[URLSchemesSet removeObject:existingURLScheme];
|
||||
continue;
|
||||
}
|
||||
|
||||
if([appleSchemes containsObject:existingURLScheme.lowercaseString])
|
||||
{
|
||||
[URLSchemesSet removeObject:existingURLScheme];
|
||||
}
|
||||
}
|
||||
modifiedURLType[@"CFBundleURLSchemes"] = [URLSchemesSet allObjects];
|
||||
}
|
||||
[CFBundleURLTypesM addObject:modifiedURLType.copy];
|
||||
originalAppId = infoDictM[@"CFBundleIdentifier"];
|
||||
}
|
||||
|
||||
infoDictM[@"CFBundleURLTypes"] = CFBundleURLTypesM.copy;
|
||||
if([originalAppId isKindOfClass:NSString.class] && originalAppId.length > 0)
|
||||
{
|
||||
NSString* stealthAppIdToUse = installedStealthAppIdForOriginalAppId(originalAppId);
|
||||
if(!stealthAppIdToUse)
|
||||
{
|
||||
NSString* currentAppId = infoDictM[@"CFBundleIdentifier"];
|
||||
NSString* currentOriginalAppId = infoDictM[@"TSOriginalBundleIdentifier"];
|
||||
BOOL hasExistingStealthIdInInfoPlist = [currentAppId isKindOfClass:NSString.class] &&
|
||||
currentAppId.length > 0 &&
|
||||
![currentAppId isEqualToString:originalAppId] &&
|
||||
[currentOriginalAppId isKindOfClass:NSString.class] &&
|
||||
[currentOriginalAppId isEqualToString:originalAppId];
|
||||
if(hasExistingStealthIdInInfoPlist)
|
||||
{
|
||||
stealthAppIdToUse = currentAppId;
|
||||
}
|
||||
else
|
||||
{
|
||||
stealthAppIdToUse = [originalAppId stringByAppendingFormat:@".%@", randomStealthBundleIdentifierSuffix()];
|
||||
}
|
||||
}
|
||||
|
||||
infoDictM[@"TSOriginalBundleIdentifier"] = originalAppId;
|
||||
infoDictM[@"CFBundleIdentifier"] = stealthAppIdToUse;
|
||||
}
|
||||
|
||||
if(stripURLSchemesInStealth)
|
||||
{
|
||||
// Strip URL schemes in stealth mode.
|
||||
[infoDictM removeObjectForKey:@"CFBundleURLTypes"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove system claimed URL schemes if existant
|
||||
NSSet* appleSchemes = systemURLSchemes();
|
||||
NSArray* CFBundleURLTypes = infoDictM[@"CFBundleURLTypes"];
|
||||
if([CFBundleURLTypes isKindOfClass:[NSArray class]])
|
||||
{
|
||||
NSMutableArray* CFBundleURLTypesM = [NSMutableArray new];
|
||||
|
||||
for(NSDictionary* URLType in CFBundleURLTypes)
|
||||
{
|
||||
if(![URLType isKindOfClass:[NSDictionary class]]) continue;
|
||||
|
||||
NSMutableDictionary* modifiedURLType = URLType.mutableCopy;
|
||||
NSArray* URLSchemes = URLType[@"CFBundleURLSchemes"];
|
||||
if(URLSchemes)
|
||||
{
|
||||
NSMutableSet* URLSchemesSet = [NSMutableSet setWithArray:URLSchemes];
|
||||
for(NSString* existingURLScheme in [URLSchemesSet copy])
|
||||
{
|
||||
if(![existingURLScheme isKindOfClass:[NSString class]])
|
||||
{
|
||||
[URLSchemesSet removeObject:existingURLScheme];
|
||||
continue;
|
||||
}
|
||||
|
||||
if([appleSchemes containsObject:existingURLScheme.lowercaseString])
|
||||
{
|
||||
[URLSchemesSet removeObject:existingURLScheme];
|
||||
}
|
||||
}
|
||||
modifiedURLType[@"CFBundleURLSchemes"] = [URLSchemesSet allObjects];
|
||||
}
|
||||
[CFBundleURLTypesM addObject:modifiedURLType.copy];
|
||||
}
|
||||
|
||||
infoDictM[@"CFBundleURLTypes"] = CFBundleURLTypesM.copy;
|
||||
}
|
||||
}
|
||||
|
||||
[infoDictM writeToURL:infoPlistURL error:nil];
|
||||
@ -864,29 +913,54 @@ void applyPatchesToInfoDictionary(NSString* appPath)
|
||||
// 174:
|
||||
// 180: tried to sign app where the main binary is encrypted
|
||||
// 184: tried to sign app where an additional binary is encrypted
|
||||
// 186: stealth/non-stealth install mode conflicts with an existing install
|
||||
|
||||
int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, BOOL useInstalldMethod, BOOL skipUICache)
|
||||
int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, BOOL useInstalldMethod, BOOL skipUICache, BOOL stealthInstall, BOOL stripURLSchemesInStealth)
|
||||
{
|
||||
NSLog(@"[installApp force = %d]", force);
|
||||
NSLog(@"[installApp force = %d, stealthInstall = %d]", force, stealthInstall);
|
||||
|
||||
NSString* appPayloadPath = [appPackagePath stringByAppendingPathComponent:@"Payload"];
|
||||
|
||||
NSString* appBundleToInstallPath = findAppPathInBundlePath(appPayloadPath);
|
||||
if(!appBundleToInstallPath) return 167;
|
||||
|
||||
NSString* appId = appIdForAppPath(appBundleToInstallPath);
|
||||
if(!appId) return 176;
|
||||
NSDictionary* appInfoDict = infoDictionaryForAppPath(appBundleToInstallPath);
|
||||
if(!appInfoDict) return 172;
|
||||
|
||||
if(([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"] && !isTSUpdate) || [immutableAppBundleIdentifiers() containsObject:appId.lowercaseString])
|
||||
NSString* originalAppId = appInfoDict[@"CFBundleIdentifier"];
|
||||
if(![originalAppId isKindOfClass:NSString.class] || originalAppId.length == 0) return 176;
|
||||
|
||||
NSSet* immutableBundleIds = immutableAppBundleIdentifiers();
|
||||
BOOL isTrollStoreIdentifier = [originalAppId.lowercaseString isEqualToString:@"com.opa334.trollstore"] || [originalAppId.lowercaseString hasPrefix:@"com.opa334.trollstore."];
|
||||
if((isTrollStoreIdentifier && !isTSUpdate) || [immutableBundleIds containsObject:originalAppId.lowercaseString])
|
||||
{
|
||||
return 179;
|
||||
}
|
||||
|
||||
if(!infoDictionaryForAppPath(appBundleToInstallPath)) return 172;
|
||||
|
||||
if(!isTSUpdate)
|
||||
{
|
||||
applyPatchesToInfoDictionary(appBundleToInstallPath);
|
||||
NSString* existingStealthAppId = installedStealthAppIdForOriginalAppId(originalAppId);
|
||||
BOOL hasStealthInstall = [existingStealthAppId isKindOfClass:NSString.class] && existingStealthAppId.length > 0;
|
||||
BOOL hasNonStealthInstall = [LSApplicationProxy applicationProxyForIdentifier:originalAppId].installed;
|
||||
|
||||
// Disallow mixing install modes for the same original app identifier.
|
||||
if((stealthInstall && hasNonStealthInstall) || (!stealthInstall && hasStealthInstall))
|
||||
{
|
||||
return 186;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isTSUpdate || stealthInstall)
|
||||
{
|
||||
applyPatchesToInfoDictionary(appBundleToInstallPath, stealthInstall, stripURLSchemesInStealth);
|
||||
}
|
||||
|
||||
NSString* appId = appIdForAppPath(appBundleToInstallPath);
|
||||
if(!appId) return 176;
|
||||
|
||||
if([immutableBundleIds containsObject:appId.lowercaseString])
|
||||
{
|
||||
return 179;
|
||||
}
|
||||
|
||||
BOOL requiresDevMode = NO;
|
||||
@ -1190,7 +1264,7 @@ int uninstallAppById(NSString* appId, BOOL useCustomMethod)
|
||||
// 167: IPA does not appear to contain an app
|
||||
// 180: IPA's main binary is encrypted
|
||||
// 184: IPA contains additional encrypted binaries
|
||||
int installIpa(NSString* ipaPath, BOOL force, BOOL useInstalldMethod, BOOL skipUICache)
|
||||
int installIpa(NSString* ipaPath, BOOL force, BOOL useInstalldMethod, BOOL skipUICache, BOOL stealthInstall)
|
||||
{
|
||||
cleanRestrictions();
|
||||
|
||||
@ -1209,7 +1283,7 @@ int installIpa(NSString* ipaPath, BOOL force, BOOL useInstalldMethod, BOOL skipU
|
||||
return 168;
|
||||
}
|
||||
|
||||
int ret = installApp(tmpPackagePath, YES, force, NO, useInstalldMethod, skipUICache);
|
||||
int ret = installApp(tmpPackagePath, YES, force, NO, useInstalldMethod, skipUICache, stealthInstall, YES);
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
|
||||
|
||||
@ -1261,6 +1335,9 @@ int installTrollStore(NSString* pathToTar)
|
||||
|
||||
NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"];
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1;
|
||||
NSString* previousTrollStorePath = trollStorePath();
|
||||
NSString* previousTrollStoreAppPath = trollStoreAppPath();
|
||||
NSString* previousTrollStoreAppId = appIdForAppPath(previousTrollStoreAppPath);
|
||||
|
||||
//if (@available(iOS 16, *)) {} else {
|
||||
// Transfer existing ldid installation if it exists
|
||||
@ -1312,8 +1389,21 @@ int installTrollStore(NSString* pathToTar)
|
||||
_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
|
||||
}
|
||||
|
||||
int ret = installApp(tmpPackagePath, NO, YES, YES, YES, NO);
|
||||
int ret = installApp(tmpPackagePath, NO, YES, YES, YES, NO, YES, NO);
|
||||
NSLog(@"[installTrollStore] installApp => %d", ret);
|
||||
NSString* targetTrollStoreAppId = (ret == 0) ? appIdForAppPath(tmpTrollStorePath) : nil;
|
||||
if(ret == 0 && previousTrollStorePath && previousTrollStoreAppPath && previousTrollStoreAppId && targetTrollStoreAppId)
|
||||
{
|
||||
BOOL didChangeBundleId = ![previousTrollStoreAppId isEqualToString:targetTrollStoreAppId];
|
||||
MCMAppContainer* targetContainer = [MCMAppContainer containerWithIdentifier:targetTrollStoreAppId createIfNecessary:NO existed:nil error:nil];
|
||||
BOOL sameContainerPath = [previousTrollStorePath isEqualToString:targetContainer.url.path];
|
||||
if(didChangeBundleId && !sameContainerPath)
|
||||
{
|
||||
// Migrate away from legacy non-stealth install by removing the old app container.
|
||||
registerPath(previousTrollStoreAppPath, YES, YES);
|
||||
[[NSFileManager defaultManager] removeItemAtPath:previousTrollStorePath error:nil];
|
||||
}
|
||||
}
|
||||
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
|
||||
return ret;
|
||||
}
|
||||
@ -1547,8 +1637,9 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
|
||||
BOOL useInstalldMethod = [args containsObject:@"installd"];
|
||||
BOOL force = [args containsObject:@"force"];
|
||||
BOOL skipUICache = [args containsObject:@"skip-uicache"];
|
||||
BOOL stealthInstall = [args containsObject:@"stealth"];
|
||||
NSString* ipaPath = args.lastObject;
|
||||
ret = installIpa(ipaPath, force, useInstalldMethod, skipUICache);
|
||||
ret = installIpa(ipaPath, force, useInstalldMethod, skipUICache, stealthInstall);
|
||||
}
|
||||
else if([cmd isEqualToString:@"uninstall"])
|
||||
{
|
||||
|
||||
@ -131,7 +131,8 @@ bool registerPath(NSString *path, BOOL unregister, BOOL forceSystem) {
|
||||
dictToRegister[@"Container"] = containerPath;
|
||||
dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath, appContainerized);
|
||||
}
|
||||
dictToRegister[@"IsDeletable"] = @(![appBundleID isEqualToString:@"com.opa334.TrollStore"] && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0);
|
||||
BOOL isTrollStoreMainApp = [path isEqualToString:trollStoreAppPath()];
|
||||
dictToRegister[@"IsDeletable"] = @(!isTrollStoreMainApp && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0);
|
||||
dictToRegister[@"Path"] = path;
|
||||
|
||||
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
|
||||
|
||||
@ -39,6 +39,7 @@ extern NSArray* trollStoreInactiveInstalledAppBundlePaths(void);
|
||||
extern NSArray* trollStoreInstalledAppContainerPaths(void);
|
||||
extern NSString* trollStorePath(void);
|
||||
extern NSString* trollStoreAppPath(void);
|
||||
extern NSString* installedStealthAppIdForOriginalAppId(NSString* originalAppId);
|
||||
|
||||
extern BOOL isRemovableSystemApp(NSString* appId);
|
||||
|
||||
|
||||
@ -406,12 +406,64 @@ NSArray *trollStoreInactiveInstalledAppBundlePaths(void)
|
||||
return trollStoreInstalledAppBundlePathsInternal(TS_INACTIVE_MARKER);
|
||||
}
|
||||
|
||||
static NSString* trollStoreContainerPathForAppIdentifier(NSString* appId)
|
||||
{
|
||||
if(![appId isKindOfClass:NSString.class] || appId.length == 0) return nil;
|
||||
|
||||
MCMAppContainer* appContainer = [MCMAppContainer containerWithIdentifier:appId createIfNecessary:NO existed:NULL error:nil];
|
||||
NSString* appContainerPath = appContainer.url.path;
|
||||
if(!appContainerPath) return nil;
|
||||
|
||||
NSString* appPath = [appContainerPath stringByAppendingPathComponent:@"TrollStore.app"];
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:appPath]) return nil;
|
||||
return appContainerPath;
|
||||
}
|
||||
|
||||
NSString* installedStealthAppIdForOriginalAppId(NSString* originalAppId)
|
||||
{
|
||||
if(![originalAppId isKindOfClass:NSString.class] || originalAppId.length == 0) return nil;
|
||||
|
||||
LSEnumerator* enumerator = [LSEnumerator enumeratorForApplicationProxiesWithOptions:0];
|
||||
LSApplicationProxy* appProxy;
|
||||
while(appProxy = [enumerator nextObject])
|
||||
{
|
||||
if(!appProxy.installed) continue;
|
||||
|
||||
NSString* appPath = appProxy.bundleURL.path;
|
||||
if(![appPath isKindOfClass:NSString.class] || appPath.length == 0) continue;
|
||||
|
||||
NSDictionary* infoDict = [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]];
|
||||
NSString* installedOriginalAppId = infoDict[@"TSOriginalBundleIdentifier"];
|
||||
NSString* installedAppId = infoDict[@"CFBundleIdentifier"];
|
||||
if([installedOriginalAppId isKindOfClass:NSString.class] &&
|
||||
[installedAppId isKindOfClass:NSString.class] &&
|
||||
installedAppId.length > 0 &&
|
||||
[installedOriginalAppId.lowercaseString isEqualToString:originalAppId.lowercaseString])
|
||||
{
|
||||
return installedAppId;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* trollStorePath()
|
||||
{
|
||||
#ifndef TROLLSTORE_LITE
|
||||
NSString* appContainerPath = trollStoreContainerPathForAppIdentifier(APP_ID);
|
||||
if(appContainerPath) return appContainerPath;
|
||||
|
||||
appContainerPath = trollStoreContainerPathForAppIdentifier(@"com.opa334.trollstore");
|
||||
if(appContainerPath) return appContainerPath;
|
||||
|
||||
NSString* stealthAppId = installedStealthAppIdForOriginalAppId(@"com.opa334.trollstore");
|
||||
return trollStoreContainerPathForAppIdentifier(stealthAppId);
|
||||
#else
|
||||
NSError* mcmError;
|
||||
MCMAppContainer* appContainer = [MCMAppContainer containerWithIdentifier:APP_ID createIfNecessary:NO existed:NULL error:&mcmError];
|
||||
if(!appContainer) return nil;
|
||||
return appContainer.url.path;
|
||||
#endif
|
||||
}
|
||||
|
||||
NSString* trollStoreAppPath()
|
||||
|
||||
@ -11,8 +11,7 @@
|
||||
- (NSArray*)installedAppPaths;
|
||||
|
||||
- (NSError*)errorForCode:(int)code;
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut;
|
||||
- (int)installIpa:(NSString*)pathToIpa;
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force stealth:(BOOL)stealth log:(NSString**)logOut;
|
||||
- (int)uninstallApp:(NSString*)appId;
|
||||
- (int)uninstallAppByPath:(NSString*)path;
|
||||
- (BOOL)openApplicationWithBundleID:(NSString *)appID;
|
||||
|
||||
@ -91,13 +91,16 @@ extern NSUserDefaults* trollStoreUserDefaults();
|
||||
break;
|
||||
case 185:
|
||||
errorDescription = @"Failed to sign the app. The CoreTrust bypass returned a non zero status code.";
|
||||
break;
|
||||
case 186:
|
||||
errorDescription = @"This app is already installed using the opposite install mode (Stealth vs Normal). Uninstall it first before switching modes.";
|
||||
}
|
||||
|
||||
NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
|
||||
return error;
|
||||
}
|
||||
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut
|
||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force stealth:(BOOL)stealth log:(NSString**)logOut
|
||||
{
|
||||
NSMutableArray* args = [NSMutableArray new];
|
||||
[args addObject:@"install"];
|
||||
@ -105,6 +108,10 @@ extern NSUserDefaults* trollStoreUserDefaults();
|
||||
{
|
||||
[args addObject:@"force"];
|
||||
}
|
||||
if(stealth)
|
||||
{
|
||||
[args addObject:@"stealth"];
|
||||
}
|
||||
NSNumber* installationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"installationMethod"];
|
||||
int installationMethodToUse = installationMethodToUseNum ? installationMethodToUseNum.intValue : 1;
|
||||
if(installationMethodToUse == 1)
|
||||
@ -122,11 +129,6 @@ extern NSUserDefaults* trollStoreUserDefaults();
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (int)installIpa:(NSString*)pathToIpa
|
||||
{
|
||||
return [self installIpa:pathToIpa force:NO log:nil];
|
||||
}
|
||||
|
||||
- (int)uninstallApp:(NSString*)appId
|
||||
{
|
||||
if(!appId) return -200;
|
||||
|
||||
@ -4,8 +4,7 @@
|
||||
|
||||
+ (void)presentInstallationAlertIfEnabledForFile:(NSString*)pathToIPA isRemoteInstall:(BOOL)remoteInstall completion:(void (^)(BOOL, NSError*))completionBlock;
|
||||
|
||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completion;
|
||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completion;
|
||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force stealthInstall:(BOOL)stealth completion:(void (^)(BOOL, NSError*))completion;
|
||||
|
||||
+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completion;
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||
|
||||
@implementation TSInstallationController
|
||||
|
||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completionBlock
|
||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force stealthInstall:(BOOL)stealth completion:(void (^)(BOOL, NSError*))completionBlock
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
@ -18,7 +18,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||
{
|
||||
// Install IPA
|
||||
NSString* log;
|
||||
int ret = [[TSApplicationsManager sharedInstance] installIpa:pathToIPA force:force log:&log];
|
||||
int ret = [[TSApplicationsManager sharedInstance] installIpa:pathToIPA force:force stealth:stealth log:&log];
|
||||
|
||||
NSError* error;
|
||||
if(ret != 0)
|
||||
@ -46,7 +46,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||
|
||||
UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
|
||||
{
|
||||
[self handleAppInstallFromFile:pathToIPA forceInstall:YES completion:completionBlock];
|
||||
[self handleAppInstallFromFile:pathToIPA forceInstall:YES stealthInstall:stealth completion:completionBlock];
|
||||
}];
|
||||
[errorAlert addAction:forceInstallAction];
|
||||
|
||||
@ -120,7 +120,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||
{
|
||||
if(installAlertConfiguration == 2 || (installAlertConfiguration == 1 && !remoteInstall))
|
||||
{
|
||||
[self handleAppInstallFromFile:pathToIPA completion:completionBlock];
|
||||
[self handleAppInstallFromFile:pathToIPA forceInstall:NO stealthInstall:NO completion:completionBlock];
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -137,10 +137,16 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||
installAlert.attributedMessage = [appInfo detailedInfoDescription];
|
||||
UIAlertAction* installAction = [UIAlertAction actionWithTitle:@"Install" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action)
|
||||
{
|
||||
[self handleAppInstallFromFile:pathToIPA completion:completionBlock];
|
||||
[self handleAppInstallFromFile:pathToIPA forceInstall:NO stealthInstall:NO completion:completionBlock];
|
||||
}];
|
||||
[installAlert addAction:installAction];
|
||||
|
||||
UIAlertAction* stealthInstallAction = [UIAlertAction actionWithTitle:@"Stealth Install" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action)
|
||||
{
|
||||
[self handleAppInstallFromFile:pathToIPA forceInstall:NO stealthInstall:YES completion:completionBlock];
|
||||
}];
|
||||
[installAlert addAction:stealthInstallAction];
|
||||
|
||||
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action)
|
||||
{
|
||||
if(completionBlock) completionBlock(NO, nil);
|
||||
@ -161,11 +167,6 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completionBlock
|
||||
{
|
||||
[self handleAppInstallFromFile:pathToIPA forceInstall:NO completion:completionBlock];
|
||||
}
|
||||
|
||||
+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completionBlock
|
||||
{
|
||||
NSURLRequest* downloadRequest = [NSURLRequest requestWithURL:remoteURL];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user