1、环境

  1、OS X EI Caption 10.11.1 & Xcode 7

  2、Xcode安装Command Line Tools

  3、iPhone 安装AppSync

2、MobileInstallation.framework 私有API

/*!*  @brief  Mobile Installation 的回调定义*/typedef void (*MobileInstallationCallback)(CFDictionaryRef information);/*!*  @brief  Mobile Installation 安装App (8.0)*  @param  bundlePath          IPA文件路径*  @param  parameters          unknown*  @param  unknown1            unknown*  @param  unknown2            unknown*/extern int MobileInstallationInstallForLaunchServices(CFStringRef bundlePath, CFDictionaryRef parameters, void *unknown1, void *unknown2) NS_AVAILABLE_IOS(8_0);
/*!*  @brief  Mobile Installation 卸载App (8.0)*  @param  bundleIdentifier    App的Bundle ID*  @param  parameters          unknown*  @param  callback            Mobile Installation 的回调*  @param  unknown             unknown*/extern int MobileInstallationUninstallForLaunchServices(CFStringRef bundleIdentifier, CFDictionaryRef parameters, MobileInstallationCallback callback, void *unknown) NS_AVAILABLE_IOS(8_0);

  以上是函数符号

3、关键代码

    void *lib = dlopen([frameworkPath UTF8String], RTLD_LAZY);if (lib){MobileInstallationInstall pMobileInstallationInstall = (MobileInstallationInstall)dlsym(lib, "MobileInstallationInstall");if (pMobileInstallationInstall){NSString* temp = [NSTemporaryDirectory() stringByAppendingPathComponent:[@"Temp_" stringByAppendingString:ipaPath.lastPathComponent]];if (![[NSFileManager defaultManager] copyItemAtPath:ipaPath toPath:temp error:nil]) {[self showAlertMessage:@"检查要安装的IPA路径是否正确!" Title:@"复制IPA文件失败"];[SVProgressHUD dismiss];return NO;}int ret = pMobileInstallationInstall(temp, [NSDictionary dictionaryWithObject:@"User" forKey:@"ApplicationType"], 0, temp);[[NSFileManager defaultManager] removeItemAtPath:temp error:nil];if (ret == 0)   {[self showAlertMessage:@"请退出桌面确定是否有个HelloIPA的程序!" Title:@"安装成功"];[SVProgressHUD dismiss];return YES;}else {[self showAlertMessage:@"若为真机,确定该设备已经jailbreak!" Title:@"安装失败"];[SVProgressHUD dismiss];return NO;}}}else {[self showAlertMessage:@"检查MobileInstallation.framework路径是否正确!" Title:@"无法连接到MobileInstallation"];[SVProgressHUD dismiss];return NO;}return NO;

  以上代码可以在App中使用

4、使用ldid签名

  上面的函数如果没有经过签名,会返回-1

<dict><key>application-identifier</key><string>com.q2q.testIPAInstall222</string><key>com.apple.private.mobileinstall.allowedSPI</key><array><string>Install</string><string>Browse</string><string>Uninstall</string><string>InstallForLaunchServices</string><string>UninstallForLaunchServices</string></array><key>com.apple.springboard.debugapplications</key><true/><key>get-task-allow</key><true/><key>task_for_pid-allow</key><true/></dict>

  直接使用ldid签名可执行文件后,重新打包成ipa就可以了。

  如果觉得复杂,也可以在Xcode中设置

使用普通的账号就可以了

https://github.com/kryhear/IPAInstaller/tree/master/testIPAInstall.xcodeproj 工程中的代码没有设置签名,导致调用是不成功的

5、ipainstaller源码

#include <dlfcn.h>
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
#import "ZipArchive/ZipArchive.h"
#import "UIDevice-Capabilities/UIDevice-Capabilities.h"#define EXECUTABLE_VERSION @"3.4.1"#define KEY_INSTALL_TYPE @"User"
#define KEY_SDKPATH "/System/Library/PrivateFrameworks/MobileInstallation.framework/MobileInstallation"#define IPA_FAILED -1typedef int (*MobileInstallationInstall)(NSString *path, NSDictionary *dict, void *na, NSString *backpath);
typedef int (*MobileInstallationUninstall)(NSString *bundleID, NSDictionary *dict, void *na);@interface LSApplicationWorkspace : NSObject
+ (LSApplicationWorkspace *)defaultWorkspace;
- (BOOL)installApplication:(NSURL *)path withOptions:(NSDictionary *)options;
- (BOOL)uninstallApplication:(NSString *)identifier withOptions:(NSDictionary *)options;
- (BOOL)applicationIsInstalled:(NSString *)appIdentifier;
- (NSArray *)allInstalledApplications;
- (NSArray *)allApplications;
- (NSArray *)applicationsOfType:(unsigned int)appType; // 0 for user, 1 for system
@end@interface LSApplicationProxy : NSObject
+ (LSApplicationProxy *)applicationProxyForIdentifier:(id)appIdentifier;
@property(readonly) NSString * applicationIdentifier;
@property(readonly) NSString * bundleVersion;
@property(readonly) NSString * bundleExecutable;
@property(readonly) NSArray * deviceFamily;
@property(readonly) NSURL * bundleContainerURL;
@property(readonly) NSString * bundleIdentifier;
@property(readonly) NSURL * bundleURL;
@property(readonly) NSURL * containerURL;
@property(readonly) NSURL * dataContainerURL;
@property(readonly) NSString * localizedShortName;
@property(readonly) NSString * localizedName;
@property(readonly) NSString * shortVersionString;
@endstatic NSString *SystemVersion = nil;
static int DeviceModel = 0;static BOOL isUninstall = NO;
static BOOL isGetInfo = NO;
static BOOL isListing = NO;
static BOOL isBackup = NO;
static BOOL isBackupFull = NO;static BOOL cleanInstall = NO;
static int quietInstall = 0; //0 is show all outputs, 1 is to show only errors, 2 is to show nothing
static BOOL forceInstall = NO;
static BOOL removeMetadata = NO;
static BOOL deleteFile = NO;
static BOOL notRestore = NO;static NSString * randomStringInLength(int len) {NSString *ret = @"";NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";for (int i=0; i<len; i++)ret = [NSString stringWithFormat:@"%@%C", ret, [letters characterAtIndex:arc4random() % [letters length]]];return ret;
}static BOOL removeAllContentsUnderPath(NSString *path) {NSFileManager *fileMgr = [NSFileManager defaultManager];BOOL isDirectory;if ([fileMgr fileExistsAtPath:path isDirectory:&isDirectory]) {if (isDirectory) {NSArray *dirContents = [fileMgr contentsOfDirectoryAtPath:path error:nil];BOOL allRemoved = YES;for (int unsigned j=0; j<[dirContents count]; j++) {if (![fileMgr removeItemAtPath:[path stringByAppendingPathComponent:[dirContents objectAtIndex:j]] error:nil])allRemoved = NO;}if (!allRemoved)return NO;if (![fileMgr removeItemAtPath:path error:nil])return NO;}}return YES;
}static void setPermissionsForPath(NSString *path) {NSFileManager *fileMgr = [NSFileManager defaultManager];//Set root folder's attributesNSDictionary *directoryAttributes = [fileMgr attributesOfItemAtPath:path error:nil];NSMutableDictionary *defaultDirectoryAttributes = [NSMutableDictionary dictionaryWithCapacity:[directoryAttributes count]];[defaultDirectoryAttributes setDictionary:directoryAttributes];[defaultDirectoryAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileOwnerAccountID];[defaultDirectoryAttributes setObject:@"mobile" forKey:NSFileOwnerAccountName];[defaultDirectoryAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileGroupOwnerAccountID];[defaultDirectoryAttributes setObject:@"mobile" forKey:NSFileGroupOwnerAccountName];[defaultDirectoryAttributes setObject:[NSNumber numberWithShort:0755] forKey:NSFilePosixPermissions];[fileMgr setAttributes:defaultDirectoryAttributes ofItemAtPath:path error:nil];for (NSString *subPath in [fileMgr contentsOfDirectoryAtPath:path error:nil]) {NSDictionary *attributes = [fileMgr attributesOfItemAtPath:[path stringByAppendingPathComponent:subPath] error:nil];if ([[attributes objectForKey:NSFileType] isEqualToString:NSFileTypeRegular]) {NSMutableDictionary *defaultAttributes = [NSMutableDictionary dictionaryWithDictionary:directoryAttributes];[defaultAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileOwnerAccountID];[defaultAttributes setObject:@"mobile" forKey:NSFileOwnerAccountName];[defaultAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileGroupOwnerAccountID];[defaultAttributes setObject:@"mobile" forKey:NSFileGroupOwnerAccountName];[defaultAttributes setObject:[NSNumber numberWithShort:0644] forKey:NSFilePosixPermissions];[fileMgr setAttributes:defaultAttributes ofItemAtPath:[path stringByAppendingPathComponent:subPath] error:nil];} else if ([[attributes objectForKey:NSFileType] isEqualToString:NSFileTypeDirectory])setPermissionsForPath([path stringByAppendingPathComponent:subPath]);else {//Ignore symblic links}}
}static void setExecutables(NSString *dirPath) {NSFileManager *fileMgr = [NSFileManager defaultManager];BOOL isDir;if (![fileMgr fileExistsAtPath:dirPath isDirectory:&isDir])return;if (!isDir)return;NSString *infoPlistPath = [dirPath stringByAppendingPathComponent:@"Info.plist"];if ([fileMgr fileExistsAtPath:infoPlistPath]) {NSDictionary *infoDict = [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];NSString *exeName = [infoDict objectForKey:@"CFBundleExecutable"];NSString *exePath = [dirPath stringByAppendingPathComponent:exeName];if ([fileMgr fileExistsAtPath:exePath]) {NSDictionary *attributes = [fileMgr attributesOfItemAtPath:exePath error:nil];if ([[attributes objectForKey:NSFileType] isEqualToString:NSFileTypeRegular]) {NSMutableDictionary *executableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];[executableAttributes setObject:[NSNumber numberWithShort:0755] forKey:NSFilePosixPermissions];[fileMgr setAttributes:executableAttributes ofItemAtPath:exePath error:nil];}}}for (NSString *subPath in [fileMgr contentsOfDirectoryAtPath:dirPath error:nil]) {NSString *subDirPath = [dirPath stringByAppendingPathComponent:subPath];NSDictionary *attributes = [fileMgr attributesOfItemAtPath:subDirPath error:nil];if ([[attributes objectForKey:NSFileType] isEqualToString:NSFileTypeDirectory])setExecutables(subDirPath);}
}static int versionCompare(NSString *ver1, NSString *ver2) {//-1: ver1<ver2; 0: ver1=ver2; 1: ver1>ver2BOOL isEmpty1 = (ver1 == nil || [ver1 length] == 0);BOOL isEmpty2 = (ver2 == nil || [ver2 length] == 0);if (isEmpty1 && isEmpty2)return 0;else if (isEmpty1 && !isEmpty2)return -1;else if (!isEmpty1 && isEmpty2)return 1;else {NSArray *components1 = [ver1 componentsSeparatedByString:@"."];NSArray *components2 = [ver2 componentsSeparatedByString:@"."];int count = [components1 count] > [components2 count] ? [components2 count] : [components1 count];for (int i=0; i<count; i++) {int num1 = [[components1 objectAtIndex:i] intValue];int num2 = [[components2 objectAtIndex:i] intValue];if (num1 < num2)return -1;else if (num1 > num2)return 1;else {if ([[components1 objectAtIndex:i] isEqualToString:[components2 objectAtIndex:i]])continue;elsereturn [[components1 objectAtIndex:i] compare:[components2 objectAtIndex:i]] == NSOrderedDescending ? 1 : -1;}}if ([components1 count] != [components2 count])return [components1 count] > [components2 count] ? 1 : -1;elsereturn 0;}
}static NSArray *getInstalledApplications() {if (kCFCoreFoundationVersionNumber < 1140.10) {NSDictionary *mobileInstallationPlist = [NSDictionary dictionaryWithContentsOfFile:@"/private/var/mobile/Library/Caches/com.apple.mobile.installation.plist"];NSDictionary *installedAppDict = (NSDictionary*)[mobileInstallationPlist objectForKey:@"User"];NSArray * identifiers = [[installedAppDict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];return identifiers;} else {Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");if (LSApplicationWorkspace_class) {LSApplicationWorkspace *workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];if (workspace) {NSArray *allApps = [workspace applicationsOfType:0];NSMutableArray *identifiers = [NSMutableArray arrayWithCapacity:[allApps count]];for (LSApplicationProxy *appBundle in allApps)[identifiers addObject:appBundle.bundleIdentifier];return [identifiers sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];}}}return nil;
}static NSString *formatDictValue(NSObject *object) {return object ? (NSString *)object : @"";
}static NSString *getBestString(NSString *main, NSString *minor) {return (minor && [minor length] > 0) ? minor : (main ? main : @"");
}static NSDictionary *getInstalledAppInfo(NSString *appIdentifier) {if (kCFCoreFoundationVersionNumber < 1140.10) {NSDictionary *mobileInstallationPlist = [NSDictionary dictionaryWithContentsOfFile:@"/private/var/mobile/Library/Caches/com.apple.mobile.installation.plist"];NSDictionary *installedAppDict = (NSDictionary*)[mobileInstallationPlist objectForKey:@"User"];NSDictionary *appInfo = [installedAppDict objectForKey:appIdentifier];if (appInfo) {NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:8];[info setObject:formatDictValue([appInfo objectForKey:@"CFBundleIdentifier"]) forKey:@"APP_ID"];[info setObject:formatDictValue([appInfo objectForKey:@"Container"]) forKey:@"BUNDLE_PATH"];[info setObject:formatDictValue([appInfo objectForKey:@"Path"]) forKey:@"APP_PATH"];[info setObject:formatDictValue([appInfo objectForKey:@"Container"]) forKey:@"DATA_PATH"];[info setObject:formatDictValue([appInfo objectForKey:@"CFBundleVersion"]) forKey:@"VERSION"];[info setObject:formatDictValue([appInfo objectForKey:@"CFBundleShortVersionString"]) forKey:@"SHORT_VERSION"];[info setObject:formatDictValue([appInfo objectForKey:@"CFBundleName"]) forKey:@"NAME"];[info setObject:formatDictValue([appInfo objectForKey:@"CFBundleDisplayName"]) forKey:@"DISPLAY_NAME"];return info;}} else {Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");if (LSApplicationWorkspace_class) {LSApplicationWorkspace *workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];if (workspace && [workspace applicationIsInstalled:appIdentifier]) {Class LSApplicationProxy_class = objc_getClass("LSApplicationProxy");if (LSApplicationProxy_class) {LSApplicationProxy *app = [LSApplicationProxy_class applicationProxyForIdentifier:appIdentifier];if (app) {NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:9];[info setObject:formatDictValue(app.bundleIdentifier) forKey:@"APP_ID"];[info setObject:formatDictValue([app.bundleContainerURL path]) forKey:@"BUNDLE_PATH"];[info setObject:formatDictValue([app.bundleURL path]) forKey:@"APP_PATH"];[info setObject:formatDictValue([app.dataContainerURL path]) forKey:@"DATA_PATH"];[info setObject:formatDictValue(app.bundleVersion) forKey:@"VERSION"];[info setObject:formatDictValue(app.shortVersionString) forKey:@"SHORT_VERSION"];[info setObject:formatDictValue(app.localizedName) forKey:@"NAME"];[info setObject:formatDictValue(app.localizedShortName) forKey:@"DISPLAY_NAME"];return info;}}}}}return nil;
}static int installApp(NSString *ipaPath, NSString *ipaId) {int ret = -1;if (kCFCoreFoundationVersionNumber < 1140.10) {void *lib = dlopen(KEY_SDKPATH, RTLD_LAZY);if (lib) {MobileInstallationInstall install = (MobileInstallationInstall)dlsym(lib, "MobileInstallationInstall");if (install)ret = install(ipaPath, [NSDictionary dictionaryWithObject:KEY_INSTALL_TYPE forKey:@"ApplicationType"], 0, ipaPath);dlclose(lib);}} else {Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");if (LSApplicationWorkspace_class) {LSApplicationWorkspace *workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];if (workspace && [workspace installApplication:[NSURL fileURLWithPath:ipaPath] withOptions:[NSDictionary dictionaryWithObject:ipaId forKey:@"CFBundleIdentifier"]])ret = 0;}}return ret;
}static BOOL uninstallApplication(NSString *appIdentifier) {if (kCFCoreFoundationVersionNumber < 1140.10) {void *lib = dlopen(KEY_SDKPATH, RTLD_LAZY);if (lib) {MobileInstallationUninstall uninstall = (MobileInstallationUninstall)dlsym(lib, "MobileInstallationUninstall");if (uninstall)return 0 == uninstall(appIdentifier, nil, nil);dlclose(lib);}} else {Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");if (LSApplicationWorkspace_class) {LSApplicationWorkspace *workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];if (workspace && [workspace uninstallApplication:appIdentifier withOptions:nil])return YES;}}return NO;
}int main (int argc, char **argv, char **envp) {NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];freopen("/dev/null", "w", stderr); //Suppress output from NSLog//Get system infoSystemVersion = [UIDevice currentDevice].systemVersion;NSString *deviceString = [UIDevice currentDevice].model;if ([deviceString isEqualToString:@"iPhone"] || [deviceString isEqualToString:@"iPod touch"])DeviceModel = 1;else if ([deviceString isEqualToString:@"iPad"])DeviceModel = 2;elseDeviceModel = 3; //Apple TV maybe?//Process parametersNSArray *arguments = [[NSProcessInfo processInfo] arguments];if ([arguments count] < 1) {[pool release];return IPA_FAILED;}NSString *executableName = [[arguments objectAtIndex:0] lastPathComponent];NSString *helpString = [NSString stringWithFormat:@"Usage: %@ [OPTION]... [FILE]...\n       %@ -{bB} [APP_ID] [-o OUTPUT_PATH]\n       %@ -i [APP_ID]...\n       %@ -l\n       %@ -u [APP_ID]...\n\n\nOptions:\n    -a  Show tool about information.\n    -b  Back up application with given identifier to IPA.\n    -B  Back up application with given identifier and its documents and settings to IPA.\n    -c  Perform a clean install.\n        If the application has already been installed, the existing documents and other resources will be cleared.\n        This implements -n automatically.\n    -d  Delete IPA file(s) after installation.\n    -f  Force installation, do not check capabilities and system version.\n        Installed application may not work properly.\n    -h  Display this usage information.\n    -i  Display information of installed application(s).\n    -l  List identifiers of all installed App Store applications.\n    -n  Do not restore saved documents and other resources.\n    -o  Output IPA to specified path, or the IPA will be saved under /var/mobile/Documents/.\n    -q  Quiet mode, suppress all normal outputs.\n    -Q  Quieter mode, suppress all outputs including errors.\n    -r  Remove iTunesMetadata.plist after installation.\n    -u  Uninstall application with given identifier(s).", executableName, executableName, executableName, executableName, executableName];NSDate *today = [NSDate date];NSDateFormatter *currentFormatter = [[NSDateFormatter alloc] init];[currentFormatter setDateFormat:@"yyyy"];NSString *aboutString = [NSString stringWithFormat:@"About %@\nInstall IPAs via command line or back up/browse/uninstall installed applications.\nVersion: %@\nAuthor: Merlin Mao\n\nZipArchive from Matt Connolly\nFSSystemHasCapability from Ryan Petrich\n\nCopyright \u00A9 2012%@ Merlin Mao. All rights reserved.", executableName, EXECUTABLE_VERSION, [[currentFormatter stringFromDate:today] isEqualToString:@"2012"] ? @"" : [@"-" stringByAppendingString:[currentFormatter stringFromDate:today]]];[currentFormatter release];if ([arguments count] == 1) {printf("%s\n", [helpString cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return 0;}NSFileManager *fileMgr = [NSFileManager defaultManager];if ([arguments count] >= 3) {NSMutableArray *identifiers = [NSMutableArray array];NSString *op1 = [arguments objectAtIndex:1];if ([op1 isEqualToString:@"-uq"] || [op1 isEqualToString:@"-qu"]) {isUninstall = YES;quietInstall = 1;for (unsigned int i=2; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];}if ([op1 isEqualToString:@"-uQ"] || [op1 isEqualToString:@"-Qu"]) {isUninstall = YES;quietInstall = 2;for (unsigned int i=2; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];}NSString *op2 = [arguments objectAtIndex:2];if ([op1 isEqualToString:@"-u"]) {isUninstall = YES;if ([op2 isEqualToString:@"-q"]) {quietInstall = 1;for (unsigned int i=3; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];}else if ([op2 isEqualToString:@"-Q"]) {quietInstall = 2;for (unsigned int i=3; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];} else {for (unsigned int i=2; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];}}if ([op1 isEqualToString:@"-i"]) {isGetInfo = YES;for (unsigned int i=2; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];}if ([op2 isEqualToString:@"-u"]) {if ([op1 isEqualToString:@"-q"]) {isUninstall = YES;quietInstall = 1;for (unsigned int i=3; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];}if ([op1 isEqualToString:@"-Q"]) {quietInstall = 2;for (unsigned int i=3; i<[arguments count]; i++)[identifiers addObject:[arguments objectAtIndex:i]];}}if (isGetInfo) {if ([identifiers count] < 1) {printf("You must specify at least one application identifier.\n");[pool release];return IPA_FAILED;}NSArray *installedApps = getInstalledApplications();for (unsigned int i=0; i<[identifiers count]; i++) {NSString *identifier = [identifiers objectAtIndex:i];if ([installedApps containsObject:identifier]) {NSDictionary *installedAppInfo = getInstalledAppInfo(identifier);NSString *appDirPath = [installedAppInfo objectForKey:@"BUNDLE_PATH"];NSString *appPath = [installedAppInfo objectForKey:@"APP_PATH"];NSString *dataPath = [installedAppInfo objectForKey:@"DATA_PATH"];NSString *appName = [installedAppInfo objectForKey:@"NAME"];NSString *appDisplayName = [installedAppInfo objectForKey:@"DISPLAY_NAME"];NSString *appVersion = [installedAppInfo objectForKey:@"VERSION"];NSString *appShortVersion = [installedAppInfo objectForKey:@"SHORT_VERSION"];printf("Identifier: %s\n", [identifier cStringUsingEncoding:NSUTF8StringEncoding]);if ([appVersion length] > 0)printf("Version: %s\n", [appVersion cStringUsingEncoding:NSUTF8StringEncoding]);if ([appShortVersion length] > 0)printf("Short Version: %s\n", [appShortVersion cStringUsingEncoding:NSUTF8StringEncoding]);if ([appName length] > 0)printf("Name: %s\n", [appName cStringUsingEncoding:NSUTF8StringEncoding]);if ([appDisplayName length] > 0)printf("Display Name: %s\n", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding]);if ([appDirPath length] > 0)printf("Bundle: %s\n", [appDirPath cStringUsingEncoding:NSUTF8StringEncoding]);if ([appPath length] > 0)printf("Application: %s\n", [appPath cStringUsingEncoding:NSUTF8StringEncoding]);if ([dataPath length] > 0)printf("Data: %s\n", [dataPath cStringUsingEncoding:NSUTF8StringEncoding]);} else {if (quietInstall < 2)printf("Application \"%s\" is not installed.\n", [identifier cStringUsingEncoding:NSUTF8StringEncoding]);}if (i < [identifiers count] - 1)printf("\n");}return 0;}if (isUninstall) {if ([identifiers count] < 1) {printf("You must specify at least one application identifier.\n");[pool release];return IPA_FAILED;} else {NSArray *installedApps = getInstalledApplications();for (unsigned int i=0; i<[identifiers count]; i++) {if ([installedApps containsObject:[identifiers objectAtIndex:i]]) {printf("Removing application \"%s\".\n", [[identifiers objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]);if (uninstallApplication([identifiers objectAtIndex:i])) {if (quietInstall == 0)printf("Successfully removed application \"%s\".\n", [[identifiers objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]);} else {if (quietInstall < 2)printf("Failed to remove application \"%s\".\n", [[identifiers objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]);}} else {if (quietInstall < 2)printf("Application \"%s\" is not installed.\n", [[identifiers objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]);}}[pool release];return 0;}}NSString *identifier = nil, *savePath = nil;if ([op1 isEqualToString:@"-bq"] || [op1 isEqualToString:@"-qb"]) {isBackup = YES;quietInstall = 1;if ([arguments count] == 5) {identifier = [arguments objectAtIndex:2];NSString *opOutput = [arguments objectAtIndex:3];if (![opOutput isEqualToString:@"-o"]) {printf("Invalid parameters.\n");[pool release];return 0;}savePath = [arguments objectAtIndex:4];} else if ([arguments count] != 3) {printf("Invalid parameters.\n");[pool release];return 0;} elseidentifier = [arguments objectAtIndex:2];}if ([op1 isEqualToString:@"-bQ"] || [op1 isEqualToString:@"-Qb"]) {isBackup = YES;quietInstall = 2;if ([arguments count] == 5) {identifier = [arguments objectAtIndex:2];NSString *opOutput = [arguments objectAtIndex:3];if (![opOutput isEqualToString:@"-o"]) {printf("Invalid parameters.\n");[pool release];return 0;}savePath = [arguments objectAtIndex:4];} else if ([arguments count] != 3) {printf("Invalid parameters.\n");[pool release];return 0;} elseidentifier = [arguments objectAtIndex:2];}if ([op1 isEqualToString:@"-Bq"] || [op1 isEqualToString:@"-qB"]) {isBackupFull = YES;quietInstall = 1;if ([arguments count] == 5) {identifier = [arguments objectAtIndex:2];NSString *opOutput = [arguments objectAtIndex:3];if (![opOutput isEqualToString:@"-o"]) {printf("Invalid parameters.\n");[pool release];return 0;}savePath = [arguments objectAtIndex:4];} else if ([arguments count] != 3) {printf("Invalid parameters.\n");[pool release];return 0;} elseidentifier = [arguments objectAtIndex:2];}if ([op1 isEqualToString:@"-BQ"] || [op1 isEqualToString:@"-QB"]) {isBackupFull = YES;quietInstall = 2;if ([arguments count] == 5) {identifier = [arguments objectAtIndex:2];NSString *opOutput = [arguments objectAtIndex:3];if (![opOutput isEqualToString:@"-o"]) {printf("Invalid parameters.\n");[pool release];return 0;}savePath = [arguments objectAtIndex:4];} else if ([arguments count] != 3) {printf("Invalid parameters.\n");[pool release];return 0;} elseidentifier = [arguments objectAtIndex:2];}if ([op1 isEqualToString:@"-b"] || [op1 isEqualToString:@"-B"]) {if ([op1 isEqualToString:@"-b"])isBackup = YES;elseisBackupFull = YES;if ([op2 isEqualToString:@"-q"] || [op2 isEqualToString:@"-Q"]) {quietInstall = [op2 isEqualToString:@"-q"] ? 1 : 2;if ([arguments count] == 6) {identifier = [arguments objectAtIndex:3];NSString *opOutput = [arguments objectAtIndex:4];if (![opOutput isEqualToString:@"-o"]) {printf("Invalid parameters.\n");[pool release];return 0;}savePath = [arguments objectAtIndex:5];} else if ([arguments count] != 4) {printf("Invalid parameters.\n");[pool release];return 0;} elseidentifier = [arguments objectAtIndex:3];} else {if ([arguments count] == 5) {identifier = [arguments objectAtIndex:2];NSString *opOutput = [arguments objectAtIndex:3];if (![opOutput isEqualToString:@"-o"]) {printf("Invalid parameters.\n");[pool release];return 0;}savePath = [arguments objectAtIndex:4];} else if ([arguments count] != 3) {printf("Invalid parameters.\n");[pool release];return 0;} elseidentifier = [arguments objectAtIndex:2];}}if ([op2 isEqualToString:@"-b"] || [op2 isEqualToString:@"-B"]) {if ([op1 isEqualToString:@"-q"] || [op1 isEqualToString:@"-Q"]) {if ([op2 isEqualToString:@"-b"])isBackup = YES;elseisBackupFull = YES;quietInstall = [op1 isEqualToString:@"-q"] ? 1 : 2;if ([arguments count] == 6) {identifier = [arguments objectAtIndex:3];NSString *opOutput = [arguments objectAtIndex:4];if (![opOutput isEqualToString:@"-o"]) {printf("Invalid parameters.\n");[pool release];return 0;}savePath = [arguments objectAtIndex:5];} else if ([arguments count] != 4) {printf("Invalid parameters.\n");[pool release];return 0;} elseidentifier = [arguments objectAtIndex:3];}}if (isBackup || isBackupFull) {if ([identifier length] < 1) {printf("You must specify an application identifier.\n");[pool release];return 0;}if (savePath) {if (![savePath hasPrefix:@"/"])savePath = [[fileMgr currentDirectoryPath] stringByAppendingPathComponent:savePath];savePath = [savePath stringByStandardizingPath];;}if ([fileMgr fileExistsAtPath:savePath]) {printf("%s already exists.\n", [savePath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}NSDictionary *installedAppInfo = getInstalledAppInfo(identifier);if (!installedAppInfo) {if (quietInstall < 2)printf("Application \"%s\" is not installed.\n", [identifier cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;} elseprintf("Backing up application with identifier \"%s\"...\n", [identifier cStringUsingEncoding:NSUTF8StringEncoding]);NSString *appDirPath = [installedAppInfo objectForKey:@"BUNDLE_PATH"];NSString *appPath = [installedAppInfo objectForKey:@"APP_PATH"];NSString *dataPath = [installedAppInfo objectForKey:@"DATA_PATH"];NSString *appName = [installedAppInfo objectForKey:@"NAME"];NSString *appDisplayName = [installedAppInfo objectForKey:@"DISPLAY_NAME"];NSString *appVersion = [installedAppInfo objectForKey:@"VERSION"];NSString *appShortVersion = [installedAppInfo objectForKey:@"SHORT_VERSION"];if (!appDisplayName || [appDisplayName length] < 1)appDisplayName = appName;if (!appShortVersion || [appShortVersion length] < 1)appShortVersion = appVersion;BOOL isDirectory;if (![fileMgr fileExistsAtPath:appDirPath isDirectory:&isDirectory]) {if (quietInstall < 2)printf("Cannot find %s.\n", [appDirPath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}if (!isDirectory) {if (quietInstall < 2)printf("%s is not a directory.\n", [appDirPath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}if (![fileMgr fileExistsAtPath:appPath isDirectory:&isDirectory]) {if (quietInstall < 2)printf("Cannot find %s.\n", [appPath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}if (!isDirectory) {if (quietInstall < 2)printf("%s is not a directory.\n", [appPath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}if (isBackupFull) {if (![fileMgr fileExistsAtPath:dataPath isDirectory:&isDirectory]) {if (quietInstall < 2)printf("Cannot find %s.\n", [dataPath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}if (!isDirectory) {if (quietInstall < 2)printf("%s is not a directory.\n", [dataPath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}}//Clean beforeNSArray *filesInTemp = [fileMgr contentsOfDirectoryAtPath:NSTemporaryDirectory() error:nil];for (NSString *file in filesInTemp) {file = [NSTemporaryDirectory() stringByAppendingPathComponent:[file lastPathComponent]];if ([[file lastPathComponent] hasPrefix:@"com.autopear.ipainstaller."] && ![fileMgr removeItemAtPath:file error:nil]) {if (quietInstall < 2)printf("Failed to delete %s.\n", [file cStringUsingEncoding:NSUTF8StringEncoding]);}}//Create temp pathNSString *workPath = nil;while (YES) {workPath = [NSString stringWithFormat:@"com.autopear.ipainstaller.%@", randomStringInLength(6)];workPath = [NSTemporaryDirectory() stringByAppendingPathComponent:workPath];if (![fileMgr fileExistsAtPath:workPath])break;}if(![fileMgr createDirectoryAtPath:workPath withIntermediateDirectories:YES attributes:nil error:NULL] ) {if (quietInstall < 2)printf("Failed to create workspace.\n");[pool release];return IPA_FAILED;}ZipArchive *ipaArchive = [[ZipArchive alloc] init];// APPEND_STATUS_ADDINZIP = 2if (![ipaArchive openZipFile2:[workPath stringByAppendingPathComponent:@"temp.zip"] withZipModel:APPEND_STATUS_ADDINZIP]) {[ipaArchive release];if (quietInstall < 2)printf("Failed to create IPA file.\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}if (![ipaArchive addDirectoryToZip:appPath toPathInZip:[NSString stringWithFormat:@"Payload/%@/", [appPath lastPathComponent]]]) {if (quietInstall < 2)printf("Failed to create ipa file.\n");[ipaArchive release];if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}if ([fileMgr fileExistsAtPath:[appDirPath stringByAppendingPathComponent:@"iTunesArtwork"]])[ipaArchive addFileToZip:[appDirPath stringByAppendingPathComponent:@"iTunesArtwork"] newname:@"iTunesArtwork"];if ([fileMgr fileExistsAtPath:[appDirPath stringByAppendingPathComponent:@"iTunesMetadata.plist"]])[ipaArchive addFileToZip:[appDirPath stringByAppendingPathComponent:@"iTunesMetadata.plist"] newname:@"iTunesMetadata.plist"];if (isBackupFull) {if (quietInstall == 0)printf("Backing up application data...\n");NSArray *dataContents = [fileMgr contentsOfDirectoryAtPath:dataPath error:nil];for (NSString *file in dataContents) {if ([file hasSuffix:@".app"] ||[file isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] ||[file isEqualToString:@".com.apple.mobileinstallation.placeholder"] ||[file isEqualToString:@".GlobalPreferences.plist"] ||[file isEqualToString:@"com.apple.PeoplePicker.plist"] ||[file isEqualToString:@"iTunesArtwork"] ||[file isEqualToString:@"iTunesMetadata.plist"])continue;if ([file isEqualToString:@"Library"]){BOOL globalMoved = NO;if ([fileMgr moveItemAtPath:[dataPath stringByAppendingPathComponent:@"Library/Preferences/.GlobalPreferences.plist"] toPath:[dataPath stringByAppendingPathComponent:@".GlobalPreferences.plist"] error:nil])globalMoved = YES;BOOL pickerMoved = NO;if ([fileMgr moveItemAtPath:[dataPath stringByAppendingPathComponent:@"Library/Preferences/com.apple.PeoplePicker.plist"] toPath:[dataPath stringByAppendingPathComponent:@"com.apple.PeoplePicker.plist"] error:nil])pickerMoved = YES;[ipaArchive addDirectoryToZip:[dataPath stringByAppendingPathComponent:@"Library"] toPathInZip:@"Container/Library/"];if (globalMoved)[fileMgr moveItemAtPath:[dataPath stringByAppendingPathComponent:@".GlobalPreferences.plist"] toPath:[dataPath stringByAppendingPathComponent:@"Library/Preferences/.GlobalPreferences.plist"] error:nil];if (pickerMoved)[fileMgr moveItemAtPath:[dataPath stringByAppendingPathComponent:@"com.apple.PeoplePicker.plist"] toPath:[dataPath stringByAppendingPathComponent:@"Library/Preferences/com.apple.PeoplePicker.plist"] error:nil];} else {NSString *sourcePath = [dataPath stringByAppendingPathComponent:file];BOOL isDir;if ([fileMgr fileExistsAtPath:sourcePath isDirectory:&isDir] && isDir)[ipaArchive addDirectoryToZip:sourcePath toPathInZip:[NSString stringWithFormat:@"Container/%@/", file]];else[ipaArchive addFileToZip:sourcePath newname:[NSString stringWithFormat:@"Container/%@/", file]];}}}[ipaArchive release];if (savePath) {NSString *saveDir = [savePath stringByDeletingLastPathComponent];BOOL isDirectory;if ([fileMgr fileExistsAtPath:saveDir isDirectory:&isDirectory]) {if (!isDirectory) {if (quietInstall < 2)printf("%s is not a directory.\n", [saveDir cStringUsingEncoding:NSUTF8StringEncoding]);if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}} else {if(![fileMgr createDirectoryAtPath:saveDir withIntermediateDirectories:YES attributes:nil error:NULL] ) {if (quietInstall < 2)printf("Failed to create directory %s.\n", [saveDir cStringUsingEncoding:NSUTF8StringEncoding]);if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}//Set root folder's attributesNSDictionary *directoryAttributes = [fileMgr attributesOfItemAtPath:saveDir error:nil];NSMutableDictionary *defaultDirectoryAttributes = [NSMutableDictionary dictionaryWithCapacity:[directoryAttributes count]];[defaultDirectoryAttributes setDictionary:directoryAttributes];[defaultDirectoryAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileOwnerAccountID];[defaultDirectoryAttributes setObject:@"mobile" forKey:NSFileOwnerAccountName];[defaultDirectoryAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileGroupOwnerAccountID];[defaultDirectoryAttributes setObject:@"mobile" forKey:NSFileGroupOwnerAccountName];[defaultDirectoryAttributes setObject:[NSNumber numberWithShort:0755] forKey:NSFilePosixPermissions];[fileMgr setAttributes:defaultDirectoryAttributes ofItemAtPath:saveDir error:nil];}//Moveif (![fileMgr moveItemAtPath:[workPath stringByAppendingPathComponent:@"temp.zip"] toPath:savePath error:nil]) {if (quietInstall < 2)printf("Failed to create IPA file.\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}if (quietInstall == 0)printf("The application has been backed up as %s.\n", [savePath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return 0;} else {NSString *nameBase;if (isBackup)nameBase = [NSString stringWithFormat:@"%@ (%@) v%@", getBestString(appName, appDisplayName), identifier, getBestString(appVersion, appShortVersion)];elsenameBase = [NSString stringWithFormat:@"%@ (%@) v%@ (Full)", getBestString(appName, appDisplayName), identifier, getBestString(appVersion, appShortVersion)];NSString *saveDir = @"/private/var/mobile/Documents";if (![fileMgr fileExistsAtPath:saveDir]) {if(![fileMgr createDirectoryAtPath:saveDir withIntermediateDirectories:YES attributes:nil error:NULL] ) {if (quietInstall < 2)printf("Failed to create /var/mobile/Documents.\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}//Set root folder's attributesNSDictionary *directoryAttributes = [fileMgr attributesOfItemAtPath:saveDir error:nil];NSMutableDictionary *defaultDirectoryAttributes = [NSMutableDictionary dictionaryWithCapacity:[directoryAttributes count]];[defaultDirectoryAttributes setDictionary:directoryAttributes];[defaultDirectoryAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileOwnerAccountID];[defaultDirectoryAttributes setObject:@"mobile" forKey:NSFileOwnerAccountName];[defaultDirectoryAttributes setObject:[NSNumber numberWithInt:501] forKey:NSFileGroupOwnerAccountID];[defaultDirectoryAttributes setObject:@"mobile" forKey:NSFileGroupOwnerAccountName];[defaultDirectoryAttributes setObject:[NSNumber numberWithShort:0755] forKey:NSFilePosixPermissions];[fileMgr setAttributes:defaultDirectoryAttributes ofItemAtPath:saveDir error:nil];}//MoveNSString *ipaPath = [[NSString stringWithFormat:@"%@/%@.ipa", saveDir, nameBase] stringByStandardizingPath];if ([fileMgr fileExistsAtPath:ipaPath]) {for (int i=1; ; i++) {ipaPath = [NSString stringWithFormat:@"%@/%@ %d.ipa", saveDir, nameBase, i];if (![fileMgr fileExistsAtPath:ipaPath])break;}}if (![fileMgr moveItemAtPath:[workPath stringByAppendingPathComponent:@"temp.zip"] toPath:ipaPath error:nil]) {if (quietInstall < 2)printf("Failed to create IPA file.\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}if (quietInstall == 0)printf("The application has been backed up as %s.\n", [ipaPath cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return 0;}}}NSMutableArray *ipaFiles = [NSMutableArray arrayWithCapacity:0];NSMutableArray *filesNotFound = [NSMutableArray arrayWithCapacity:0];BOOL noParameters = NO;BOOL showHelp = NO;BOOL showAbout = NO;for (unsigned int i=1; i<[arguments count]; i++) {NSString *arg = [arguments objectAtIndex:i];if ([arg hasPrefix:@"-" ]) {if ([arg length] < 2 || noParameters) {printf("Invalid parameters.\n");[pool release];return IPA_FAILED;}for (unsigned int j=1; j<[arg length]; j++) {NSString *p = [arg substringWithRange:NSMakeRange(j, 1)];if ([p isEqualToString:@"u"])isUninstall = YES;else if ([p isEqualToString:@"l"])isListing = YES;else if ([p isEqualToString:@"b"]) {if (isBackupFull) {printf("Parameter b and B cannot be specified at the same time.\n");[pool release];return IPA_FAILED;}isBackup = YES;} else if ([p isEqualToString:@"B"]) {if (isBackup) {printf("Parameter -b and -B cannot be specified at the same time.\n");[pool release];return IPA_FAILED;}isBackupFull = YES;} else if ([p isEqualToString:@"a"])showAbout = YES;else if ([p isEqualToString:@"c"])cleanInstall = YES;else if ([p isEqualToString:@"d"])deleteFile = YES;else if ([p isEqualToString:@"i"] || [p isEqualToString:@"I"])isGetInfo = YES;else if ([p isEqualToString:@"f"])forceInstall = YES;else if ([p isEqualToString:@"h"])showHelp = YES;else if ([p isEqualToString:@"n"])notRestore = YES;else if ([p isEqualToString:@"q"]) {if (quietInstall != 0) {printf("Parameter -q and -Q cannot be specified at the same time.\n");[pool release];return IPA_FAILED;}quietInstall = 1;} else if ([p isEqualToString:@"Q"]) {if (quietInstall != 0) {printf("Parameter -q and -Q cannot be specified at the same time.\n");[pool release];return IPA_FAILED;}quietInstall = 2;} else if ([p isEqualToString:@"r"])removeMetadata = YES;else if ([p isEqualToString:@"o"]) {if (!isBackup && !isBackupFull) {printf("You must specify -b or -B before -o.\n");[pool release];return IPA_FAILED;}} else {printf("Invalid parameter '%s'.\n", [p cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return IPA_FAILED;}}} else {if (!isBackup && !isBackupFull) {noParameters = YES;NSURL *url = [NSURL fileURLWithPath:arg isDirectory:NO];BOOL isDirectory;if (url && [fileMgr fileExistsAtPath:[[url absoluteURL] path] isDirectory:&isDirectory]) {if (isDirectory)[filesNotFound addObject:arg];else[ipaFiles addObject:[[url absoluteURL] path]]; //File exists} else[filesNotFound addObject:arg];}}}if (isListing) {getInstalledApplications();if ([arguments count] != 2) {printf("Invalid parameters.\n");[pool release];return IPA_FAILED;} else {NSArray * identifiers = getInstalledApplications();for (unsigned int i=0; i<[identifiers count]; i++)printf("%s\n", [(NSString *)[identifiers objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return 0;}}if ((showAbout && showHelp) ||((showAbout || showHelp) &&(cleanInstall ||deleteFile ||forceInstall ||notRestore ||quietInstall != 0 ||removeMetadata ||([ipaFiles count] + [filesNotFound count] > 0)))) {printf("Invalid parameters.\n");[pool release];return IPA_FAILED;}if (showHelp) {printf("%s\n", [helpString cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return 0;}if (showAbout) {printf("%s\n", [aboutString cStringUsingEncoding:NSUTF8StringEncoding]);[pool release];return 0;}for (unsigned int i=0; i<[filesNotFound count]; i++) {if (quietInstall < 2)printf("File not found at path: %s.\n", [[filesNotFound objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]);}if ([ipaFiles count] < 1) {if (quietInstall < 2)printf("Please specify any IPA file(s) to install.\n");[pool release];return IPA_FAILED;}if (cleanInstall)notRestore = YES;if (quietInstall == 0 && cleanInstall)printf("Clean installation enabled.\n");if (quietInstall == 0 && forceInstall)printf("Force installation enabled.\n");if (quietInstall == 0 && notRestore)printf("Will not restore any saved documents and other resources.\n");if (quietInstall == 0 && removeMetadata)printf("iTunesMetadata.plist will be removed after installation.\n");if (quietInstall == 0 && deleteFile) {if ([ipaFiles count] == 1)printf("%s will be deleted after installation.\n", [[[ipaFiles objectAtIndex:0] lastPathComponent] cStringUsingEncoding:NSUTF8StringEncoding]);elseprintf("IPA files will be deleted after installation.\n");}if (quietInstall == 0 && (cleanInstall || forceInstall || notRestore || removeMetadata || deleteFile))printf("\n");NSArray *filesInTemp = [fileMgr contentsOfDirectoryAtPath:NSTemporaryDirectory() error:nil];for (NSString *file in filesInTemp) {file = [NSTemporaryDirectory() stringByAppendingPathComponent:[file lastPathComponent]];if ([[file lastPathComponent] hasPrefix:@"com.autopear.ipainstaller."] && ![fileMgr removeItemAtPath:file error:nil]) {if (quietInstall < 2)printf("Failed to delete %s.\n", [file cStringUsingEncoding:NSUTF8StringEncoding]);}}NSString *workPath = nil;while (YES) {workPath = [NSString stringWithFormat:@"com.autopear.ipainstaller.%@", randomStringInLength(6)];workPath = [NSTemporaryDirectory() stringByAppendingPathComponent:workPath];if (![fileMgr fileExistsAtPath:workPath])break;}if(![fileMgr createDirectoryAtPath:workPath withIntermediateDirectories:YES attributes:nil error:NULL]) {if (quietInstall < 2)printf("Failed to create workspace.\n");[pool release];return IPA_FAILED;}NSString *installPath = [workPath stringByAppendingPathComponent:@"tmp.install.ipa"];int successfulInstalls = 0;for (unsigned i=0; i<[ipaFiles count]; i++) {//Before installation, make a clean workspaceif (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to create workspace.\n");[pool release];return IPA_FAILED;}NSString *ipa = [ipaFiles objectAtIndex:i];if (quietInstall == 0)printf("Analyzing %s...\n", [[ipa lastPathComponent] cStringUsingEncoding:NSUTF8StringEncoding]);BOOL isValidIPA = YES;BOOL hasContainer = NO;NSString *pathInfoPlist = nil;NSString *infoPath = nil;while (YES) {pathInfoPlist = [workPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.Info.plist", randomStringInLength(6)]];if (![fileMgr fileExistsAtPath:pathInfoPlist])break;}ZipArchive *ipaArchive = [[ZipArchive alloc] init];if ([ipaArchive unzipOpenFile:[ipaFiles objectAtIndex:i]]) {NSMutableArray *array = [ipaArchive getZipFileContents];NSMutableArray *infoStrings = [NSMutableArray arrayWithCapacity:0];NSString *appPathName = nil;int cnt = 0;for (unsigned int j=0; j<[array count]; j++) {NSString *name = [array objectAtIndex:j];NSArray *components = [name pathComponents];if ([components count] > 1 && [[components objectAtIndex:0] isEqualToString:@"Container"])hasContainer = YES;else {//Extract Info.plistif ([components count] == 3 &&[[components objectAtIndex:0] isEqualToString:@"Payload"] &&[[components objectAtIndex:1] hasSuffix:@".app"] &&[[components objectAtIndex:2] isEqualToString:@"Info.plist"]) {appPathName = [@"Payload" stringByAppendingPathComponent:[components objectAtIndex:1]];infoPath = name;cnt++;}//Extract InfoPlist.strings if availableif ([components count] == 4 &&[[components objectAtIndex:0] isEqualToString:@"Payload"] &&[[components objectAtIndex:1] hasSuffix:@".app"] &&[[components objectAtIndex:2] hasSuffix:@".lproj"] &&[[components objectAtIndex:3] isEqualToString:@"InfoPlist.strings"]) {[infoStrings addObject:[components objectAtIndex:2]];}}}if (cnt != 1)isValidIPA = NO;if (isValidIPA) {//Unzip Info.plist[ipaArchive unzipFileWithName:infoPath toPath:pathInfoPlist overwrite:YES];//Unzip all InfoPlist.stringsfor (unsigned int j=0; j<[infoStrings count]; j++) {NSString *lprojPath = [[workPath stringByAppendingPathComponent:@"localizations"] stringByAppendingPathComponent:[infoStrings objectAtIndex:j]];if ([fileMgr createDirectoryAtPath:lprojPath withIntermediateDirectories:YES attributes:nil error:NULL]) {//Unzip to this directory[ipaArchive unzipFileWithName:[[appPathName stringByAppendingPathComponent:[infoStrings objectAtIndex:j]] stringByAppendingPathComponent:@"InfoPlist.strings"] toPath:[lprojPath stringByAppendingPathComponent:@"InfoPlist.strings"] overwrite:YES];}}}[ipaArchive unzipCloseFile];} elseisValidIPA = NO;[ipaArchive release];if (!isValidIPA) {if (quietInstall < 2)printf("%s is not a valid IPA.%s", [[ipaFiles objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}NSString *appIdentifier = nil;NSString *appDisplayName = nil;NSString *appVersion = nil;NSString *appShortVersion = nil;NSString *minSysVersion = nil;NSMutableArray *supportedDeives = nil;id requiredCapabilities = nil;NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:pathInfoPlist];if (infoDict) {appIdentifier = [infoDict objectForKey:@"CFBundleIdentifier"];appVersion = [infoDict objectForKey:@"CFBundleVersion"];appShortVersion = [infoDict objectForKey:@"CFBundleShortVersionString"];minSysVersion = [infoDict objectForKey:@"MinimumOSVersion"];supportedDeives = [infoDict objectForKey:@"UIDeviceFamily"];requiredCapabilities = [infoDict objectForKey:@"UIRequiredDeviceCapabilities"];appDisplayName = [infoDict objectForKey:@"CFBundleDisplayName"] ? [infoDict objectForKey:@"CFBundleDisplayName"] : [infoDict objectForKey:@"CFBundleName"];//Obtain localized display nameBOOL isDirectory;if ([fileMgr fileExistsAtPath:[workPath stringByAppendingPathComponent:@"localizations"] isDirectory:&isDirectory]) {if (isDirectory) {NSBundle *localizedBundle = [NSBundle bundleWithPath:[workPath stringByAppendingPathComponent:@"localizations"]];if ([localizedBundle localizedStringForKey:@"CFBundleDisplayName" value:nil table:@"InfoPlist"])appDisplayName = [localizedBundle localizedStringForKey:@"CFBundleDisplayName" value:appDisplayName table:@"InfoPlist"];elseappDisplayName = [localizedBundle localizedStringForKey:@"CFBundleName" value:appDisplayName table:@"InfoPlist"];//Delete the directory[fileMgr removeItemAtPath:[workPath stringByAppendingPathComponent:@"localizations"] error:nil];}}} else {if (quietInstall < 2)printf("%s is not a valid IPA.%s", [[ipaFiles objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}if (!appIdentifier || !appDisplayName || !appVersion) {if (quietInstall < 2)printf("%s is not a valid IPA.%s", [[ipaFiles objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}//Make a copy of extracted Info.plistNSString *pathOriginalInfoPlist = [NSString stringWithFormat:@"%@.original", pathInfoPlist];if ([fileMgr fileExistsAtPath:pathOriginalInfoPlist]) {if (![fileMgr removeItemAtPath:pathOriginalInfoPlist error:nil]) {if (![fileMgr copyItemAtPath:pathInfoPlist toPath:pathOriginalInfoPlist error:nil]) {//Force installation has to be disabled.if (forceInstall && quietInstall < 2)printf("Force installation has to be disabled.\n");forceInstall = NO;}}} else {if (![fileMgr copyItemAtPath:pathInfoPlist toPath:pathOriginalInfoPlist error:nil]) {//Force installation has to be disabled.if (forceInstall && quietInstall < 2)printf("Force installation has to be disabled.\n");forceInstall = NO;}}//Check installed statsNSDictionary *installedAppDict = getInstalledAppInfo(appIdentifier);BOOL appAlreadyInstalled = NO;if (installedAppDict) {appAlreadyInstalled = YES;NSString *installedVerion = [installedAppDict objectForKey:@"VERSION"];NSString *installedShortVersion = [installedAppDict objectForKey:@"SHORT_VERSION"];if (installedShortVersion != nil && appShortVersion != nil) {if (versionCompare(installedShortVersion, appShortVersion) == 1) {//Skip to avoid overriding a new versionif (forceInstall) {if (quietInstall == 0)printf("%s (v%s) is already installed. Will force to downgrade.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [installedShortVersion cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");} else {if (quietInstall < 2)printf("%s (v%s) is already installed. You may use -f parameter to force downgrade.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [installedShortVersion cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}}} else {if (versionCompare(installedVerion, appVersion) == 1) {//Skip to avoid overriding a new versionif (forceInstall) {if (quietInstall == 0)printf("%s (v%s) is already installed. Will force to downgrade.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [installedVerion cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");} else {if (quietInstall < 2)printf("%s (v%s) is already installed. You may use -f parameter to force downgrade.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [installedVerion cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}}}}BOOL shouldUpdateInfoPlist = NO;//Check device familyBOOL supportiPhone = NO;BOOL supportiPad = NO;BOOL supportAppleTV = NO;if (!supportedDeives || [supportedDeives count] == 0) {supportiPhone = YES;supportiPad = YES;supportAppleTV = YES;} else {for (unsigned int j=0; j<[supportedDeives count]; j++) {int d =[[supportedDeives objectAtIndex:j] intValue];if (d == 1) {supportiPhone = YES;supportiPad = YES;}if (d == 2)supportiPad = YES;if (d == 3)supportAppleTV = YES;}}NSString *supportedDeivesString = nil;if (!supportiPhone && supportiPad && !supportAppleTV)supportedDeivesString = @"iPad";else if (!supportiPhone && !supportiPad && supportAppleTV)supportedDeivesString = @"Apple TV";else if (supportiPhone && supportiPad && !supportAppleTV)supportedDeivesString = @"iPhone, iPod touch or iPad";else if (supportiPhone && !supportiPad && supportAppleTV)supportedDeivesString = @"iPhone, iPod touch or Apple TV";else if (!supportiPhone && supportiPad && supportAppleTV)supportedDeivesString = @"iPad or Apple TV";else if (supportiPhone && !supportiPad && !supportAppleTV)supportedDeivesString = @"iPhone or iPod touch"; //Should not reach here, normally support iPhone should support iPad tooelsesupportedDeivesString = @"iPhone, iPod touch, iPad or Apple TV"; //Should not reach hereif ((DeviceModel == 1 && !supportiPhone) || //Not support iPhone / iPod touch(DeviceModel == 2 && !supportiPad) || //Not support iPad(DeviceModel == 3 && !supportAppleTV)) { //Not support Apple TV//Device not supportedif (forceInstall) {if (quietInstall == 0)printf("%s (v%s) requires %s while your device is %s.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding], [supportedDeivesString cStringUsingEncoding:NSUTF8StringEncoding], [deviceString cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) || forceInstall ? "\n" : "\n\n");[supportedDeives addObject:[NSNumber numberWithInt:DeviceModel]];[infoDict setObject:[supportedDeives sortedArrayUsingSelector:@selector(compare:)] forKey:@"UIDeviceFamily"];shouldUpdateInfoPlist = YES;} else {if (quietInstall < 2)printf("%s (v%s) requires %s while your device is %s.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding], [supportedDeivesString cStringUsingEncoding:NSUTF8StringEncoding], [deviceString cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) || forceInstall ? "\n" : "\n\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}}//Check minimun system requirementif (minSysVersion && versionCompare(minSysVersion, SystemVersion) == 1) {//System version is less than the min required versionif (forceInstall) {if (quietInstall == 0)printf("%s (v%s) requires iOS %s while your system is %s.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding], [minSysVersion cStringUsingEncoding:NSUTF8StringEncoding], [SystemVersion cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) || forceInstall ? "\n" : "\n\n");[infoDict setObject:SystemVersion forKey:@"MinimumOSVersion"];shouldUpdateInfoPlist = YES;} else {if (quietInstall < 2)printf("%s (v%s) requires iOS %s while your system is %s.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding], [minSysVersion cStringUsingEncoding:NSUTF8StringEncoding], [SystemVersion cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) || forceInstall ? "\n" : "\n\n");if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}}//Chekc capabilitiesif (requiredCapabilities) {BOOL isCapable = YES;//requiredCapabilities is NSArray, contains only stringsif ([requiredCapabilities isKindOfClass:[NSArray class]]) {NSMutableArray *newCapabilities = [NSMutableArray arrayWithCapacity:0];for (unsigned int j=0; j<[(NSArray *)requiredCapabilities count]; j++) {NSString *capability = [(NSArray *)requiredCapabilities objectAtIndex:j];if ([[UIDevice currentDevice] supportsCapability:capability])[newCapabilities addObject:capability];else {isCapable = NO;if (forceInstall) {if (quietInstall == 0)printf("Your device does not support %s capability.\n", [capability cStringUsingEncoding:NSUTF8StringEncoding]);shouldUpdateInfoPlist = YES;} else {if (quietInstall < 2)printf("Your device does not support %s capability.\n", [capability cStringUsingEncoding:NSUTF8StringEncoding]);}}}if (!isCapable) {if (forceInstall)[infoDict setObject:[newCapabilities sortedArrayUsingSelector:@selector(compare:)] forKey:@"UIRequiredDeviceCapabilities"];else {if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}if (i != [ipaFiles count] - 1) //Not the last outputprintf("\n");continue;}}} else if ([requiredCapabilities isKindOfClass:[NSDictionary class]]) {//requiredCapabilities is NSDictionary, contains only key-object pairsNSMutableDictionary *newCapabilities = [NSMutableDictionary dictionaryWithCapacity:0];for (NSString *capabilityKey in [(NSDictionary *)requiredCapabilities allKeys]) {BOOL capabilityValue = [[(NSDictionary *)requiredCapabilities objectForKey:capabilityKey] boolValue];//Only boolean valueif (capabilityValue == [[UIDevice currentDevice] supportsCapability:capabilityKey])[newCapabilities setObject:[NSNumber numberWithBool:!capabilityValue] forKey:capabilityKey];else {isCapable = NO;if (forceInstall) {if (quietInstall == 0) {if (capabilityValue) //Device does not supportprintf("Your device does not support %s capability.\n", [capabilityKey cStringUsingEncoding:NSUTF8StringEncoding]);else //Device support but IPA requires to be falseprintf("Your device conflicts with %s capability.\n", [capabilityKey cStringUsingEncoding:NSUTF8StringEncoding]);}shouldUpdateInfoPlist = YES;} else {if (quietInstall < 2) {if (capabilityValue) //Device does not supportprintf("Your device does not support %s capability.\n", [capabilityKey cStringUsingEncoding:NSUTF8StringEncoding]);else //Device support but IPA requires to be falseprintf("Your device conflicts with %s capability.\n", [capabilityKey cStringUsingEncoding:NSUTF8StringEncoding]);}}}}if (!isCapable) {if (forceInstall)[infoDict setObject:newCapabilities forKey:@"UIRequiredDeviceCapabilities"];else {if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}if (i != [ipaFiles count] - 1) //Not the last outputprintf("\n");continue;}}}}if (shouldUpdateInfoPlist && ![infoDict writeToFile:pathInfoPlist atomically:YES]) {if (quietInstall < 2)printf("Failed to use force installation mode, %s (v%s) will not be installed.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");continue;}//Copy file to installif ([fileMgr fileExistsAtPath:installPath]) {if (![fileMgr removeItemAtPath:installPath error:nil]) {if (quietInstall < 2)printf("Failed to delete %s.\n", [installPath cStringUsingEncoding:NSUTF8StringEncoding]);if (![fileMgr removeItemAtPath:workPath error:nil]) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return IPA_FAILED;}}if (![fileMgr copyItemAtPath:ipa toPath:installPath error:nil]) {if (quietInstall < 2)printf("Failed to create temporaty files.\n");if (![fileMgr removeItemAtPath:workPath error:nil] && quietInstall < 2)printf("Failed to clean caches.\n");[pool release];return IPA_FAILED;}//Modify ipa to force installif (shouldUpdateInfoPlist) {BOOL shouldContinue = NO;ZipArchive *tmpArchive = [[ZipArchive alloc] init];// APPEND_STATUS_ADDINZIP = 2if ([tmpArchive openZipFile2:installPath withZipModel:APPEND_STATUS_ADDINZIP] && ![tmpArchive addFileToZip:pathInfoPlist newname:infoPath]) {if (quietInstall < 2)printf("Failed to use force installation mode, %s (v%s) will not be installed.%s", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");//Delete copied file[fileMgr removeItemAtPath:installPath error:nil];shouldContinue = YES;}[tmpArchive release];//Remove extracted Info.plist[fileMgr removeItemAtPath:pathInfoPlist error:nil];if (shouldContinue) {if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}continue;}}if (quietInstall == 0)printf("%snstalling %s (v%s)...\n", shouldUpdateInfoPlist ? "Force i" : "I", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding]);//Set permission before installationsetPermissionsForPath(workPath);int ret = installApp(installPath, appIdentifier);if (ret == 0) {//Get installation pathNSDictionary *installedAppDict = getInstalledAppInfo(appIdentifier);if (installedAppDict) {NSString *installedVerion = [installedAppDict objectForKey:@"VERSION"];NSString *installedShortVersion = [installedAppDict objectForKey:@"SHORT_VERSION"];NSString *installedAppLocation = [installedAppDict objectForKey:@"BUNDLE_PATH"];NSString *installedDataLocation = [installedAppDict objectForKey:@"DATA_PATH"];NSString *appDirPath = [installedAppDict objectForKey:@"APP_PATH"];BOOL appInstalled = YES;if (appInstalled && versionCompare(installedVerion, appVersion) != 0)appInstalled = NO;if (appInstalled && versionCompare(installedShortVersion, appShortVersion) != 0)appInstalled = NO;if (appInstalled) {//Recover the original Info.plist in force installationif (shouldUpdateInfoPlist) {NSString *pathInstalledInfoPlist = [NSString stringWithFormat:@"%@/%@/Info.plist", installedAppLocation, [[infoPath pathComponents] objectAtIndex:1]];BOOL isDirectory;if ([fileMgr fileExistsAtPath:pathInstalledInfoPlist isDirectory:&isDirectory]) {if (!isDirectory) {if ([fileMgr removeItemAtPath:pathInstalledInfoPlist error:nil]) {if ([fileMgr moveItemAtPath:pathOriginalInfoPlist toPath:pathInstalledInfoPlist error:nil]) {if ([fileMgr fileExistsAtPath:pathOriginalInfoPlist])[fileMgr removeItemAtPath:pathOriginalInfoPlist error:nil];}}}}}successfulInstalls++;if (quietInstall == 0)printf("%snstalled %s (v%s) successfully%s.\n", shouldUpdateInfoPlist ? "Force i" : "I", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding], shouldUpdateInfoPlist ? ", but it may not work properly" : "");BOOL tempEnableClean = NO;if (!cleanInstall && hasContainer && !notRestore) {tempEnableClean = YES;cleanInstall = YES;}//Clear documents, etc.if (appAlreadyInstalled && cleanInstall) {if (quietInstall == 0)printf("Cleaning old contents of %s...\n", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding]);BOOL allContentsCleaned = YES;NSArray *dataContents = [fileMgr contentsOfDirectoryAtPath:installedDataLocation error:nil];for (NSString *file in dataContents) {if ([file hasSuffix:@".app"] ||[file isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] ||[file isEqualToString:@".com.apple.mobileinstallation.placeholder"] ||[file isEqualToString:@"iTunesArtwork"] ||[file isEqualToString:@"iTunesMetadata.plist"])continue;if ([file isEqualToString:@"Library"]){NSString *dirLibrary = [installedDataLocation stringByAppendingPathComponent:@"Library"];NSString *dirPreferences = [dirLibrary stringByAppendingPathComponent:@"Preferences"];NSString *dirCaches = [dirLibrary stringByAppendingPathComponent:@"Caches"];NSArray *dirContents = [fileMgr contentsOfDirectoryAtPath:dirLibrary error:nil];for (int unsigned j=0; j<[dirContents count]; j++) {NSString *fileName = [dirContents objectAtIndex:j];if ([fileName isEqualToString:@"Preferences"]) {NSArray *preferencesContents = [fileMgr contentsOfDirectoryAtPath:dirPreferences error:nil];for (unsigned int k=0; k<[preferencesContents count]; k++) {NSString *preferenceFile = [preferencesContents objectAtIndex:k];if (![preferenceFile isEqualToString:@".GlobalPreferences.plist"] && ![preferenceFile isEqualToString:@"com.apple.PeoplePicker.plist"]) {if (![fileMgr removeItemAtPath:[dirPreferences stringByAppendingPathComponent:preferenceFile] error:nil])allContentsCleaned = NO;}}} else if ([fileName isEqualToString:@"Caches"]) {NSArray *cachesContents = [fileMgr contentsOfDirectoryAtPath:dirCaches error:nil];for (unsigned int k=0; k<[cachesContents count]; k++) {if (![fileMgr removeItemAtPath:[dirCaches stringByAppendingPathComponent:[cachesContents objectAtIndex:k]] error:nil])allContentsCleaned = NO;}} else {if (![fileMgr removeItemAtPath:[dirLibrary stringByAppendingPathComponent:fileName] error:nil])allContentsCleaned = NO;}}} else {NSString *sourcePath = [installedDataLocation stringByAppendingPathComponent:file];BOOL isDir;if ([fileMgr fileExistsAtPath:sourcePath isDirectory:&isDir] && isDir) {NSArray *dirContents = [fileMgr contentsOfDirectoryAtPath:sourcePath error:nil];for (int unsigned j=0; j<[dirContents count]; j++) {if (![fileMgr removeItemAtPath:[sourcePath stringByAppendingPathComponent:[dirContents objectAtIndex:j]] error:nil])allContentsCleaned = NO;}} else {if (![fileMgr removeItemAtPath:sourcePath error:nil])allContentsCleaned = NO;}}}if (!allContentsCleaned) {if (quietInstall < 2)printf("Failed to clean old contents of %s.\n", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding]);}}if (tempEnableClean)cleanInstall = NO;//Recover documentsif (!cleanInstall && hasContainer && !notRestore) {//The tmp ipa file is already deleted.ipaArchive = [[ZipArchive alloc] init];if ([ipaArchive unzipOpenFile:[ipaFiles objectAtIndex:i]]) {if ([ipaArchive unzipFileWithName:@"Container" toPath:[workPath stringByAppendingPathComponent:@"Container"] overwrite:YES]) {NSString *containerPath = [workPath stringByAppendingPathComponent:@"Container"];NSArray *containerContents = [fileMgr contentsOfDirectoryAtPath:containerPath error:nil];if ([containerContents count] > 0) {BOOL allSuccessfull = YES;for (unsigned int j=0; j<[containerContents count]; j++) {NSString *dirName = [containerContents objectAtIndex:j];if ([dirName isEqualToString:@"Library"]) {NSString *containerLibraryPath = [containerPath stringByAppendingPathComponent:dirName];NSArray *containerLibraryContents = [fileMgr contentsOfDirectoryAtPath:containerLibraryPath error:nil];for (unsigned int k=0; k<[containerLibraryContents count]; k++) {NSString *dirLibraryName = [containerLibraryContents objectAtIndex:k];if ([dirLibraryName isEqualToString:@"Caches"]) {NSString *dirCachePath = [containerLibraryPath stringByAppendingPathComponent:dirLibraryName];NSArray *containerCachesContents = [fileMgr contentsOfDirectoryAtPath:dirCachePath error:nil];for (unsigned int m=0; m<[containerCachesContents count]; m++) {if (![fileMgr moveItemAtPath:[dirCachePath stringByAppendingPathComponent:[containerCachesContents objectAtIndex:m]] toPath:[[[installedDataLocation stringByAppendingPathComponent:dirName] stringByAppendingPathComponent:dirLibraryName] stringByAppendingPathComponent:[containerCachesContents objectAtIndex:m]] error:nil])allSuccessfull = NO;}} else if ([dirLibraryName isEqualToString:@"Preferences"]) {NSString *dirPreferencesPath = [containerLibraryPath stringByAppendingPathComponent:dirLibraryName];NSArray *containerPreferencesContents = [fileMgr contentsOfDirectoryAtPath:dirPreferencesPath error:nil];for (unsigned int m=0; m<[containerPreferencesContents count]; m++) {NSString *preferencesFileName = [containerPreferencesContents objectAtIndex:m];if (![preferencesFileName isEqualToString:@".GlobalPreferences.plist"] && ![preferencesFileName isEqualToString:@"com.apple.PeoplePicker.plist"]) {if (![fileMgr moveItemAtPath:[dirPreferencesPath stringByAppendingPathComponent:preferencesFileName] toPath:[[[installedDataLocation stringByAppendingPathComponent:dirName] stringByAppendingPathComponent:dirLibraryName] stringByAppendingPathComponent:preferencesFileName] error:nil])allSuccessfull = NO;}}} else {if (![fileMgr moveItemAtPath:[containerLibraryPath stringByAppendingPathComponent:dirLibraryName] toPath:[[installedDataLocation stringByAppendingPathComponent:dirName] stringByAppendingPathComponent:dirLibraryName] error:nil])allSuccessfull = NO;}}} else {NSString *containerSourcePath = [containerPath stringByAppendingPathComponent:dirName];NSString *destPath = [installedDataLocation stringByAppendingPathComponent:dirName];if ([fileMgr fileExistsAtPath:destPath]) {if ([fileMgr removeItemAtPath:destPath error:nil]) {if (![fileMgr moveItemAtPath:containerSourcePath toPath:destPath error:nil])allSuccessfull = NO;} elseallSuccessfull = NO;} else {if (![fileMgr moveItemAtPath:containerSourcePath toPath:destPath error:nil])allSuccessfull = NO;}}}if (!allSuccessfull) {if (quietInstall < 2)printf("Cannot restore all saved documents and other resources.\n");}}}[ipaArchive unzipCloseFile];}[ipaArchive release];}//Remove metadataBOOL isDirectory;if (removeMetadata && [fileMgr fileExistsAtPath:[installedAppLocation stringByAppendingPathComponent:@"iTunesMetadata.plist"] isDirectory:&isDirectory]) {if (!isDirectory) {if (quietInstall == 0)printf("Removing iTunesMetadata.plist for %s...\n", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding]);if (![fileMgr removeItemAtPath:[installedAppLocation stringByAppendingPathComponent:@"iTunesMetadata.plist"] error:nil]) {if (quietInstall < 2)printf("Failed to remove %s.\n", [[installedAppLocation stringByAppendingPathComponent:@"iTunesMetadata.plist"] cStringUsingEncoding:NSUTF8StringEncoding]);}}}//Set overall permissionif (kCFCoreFoundationVersionNumber < 793.00)setPermissionsForPath(installedAppLocation);elsesetPermissionsForPath(installedDataLocation); //Restore data directory's user/group for writingsetExecutables(appDirPath);} else {if (quietInstall < 2)printf("Failed to install %s (v%s).\n", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding]);}} else {if (quietInstall < 2)printf("Failed to install %s (v%s).\n", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding]);}} else {if (quietInstall < 2)printf("Failed to install %s (v%s).\n", [appDisplayName cStringUsingEncoding:NSUTF8StringEncoding], [(appShortVersion ? appShortVersion : appVersion) cStringUsingEncoding:NSUTF8StringEncoding]);}//Delete tmp ipa fileif (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to delete %s.%s", [installPath cStringUsingEncoding:NSUTF8StringEncoding], (i == [ipaFiles count] - 1) ? "\n" : "\n\n");[pool release];return IPA_FAILED;}//Delete original ipaif (deleteFile && [fileMgr fileExistsAtPath:ipa]) {if (![fileMgr removeItemAtPath:ipa error:nil]) {if (quietInstall < 2)printf("Failed to delete %s.\n", [ipa cStringUsingEncoding:NSUTF8StringEncoding]);}}if (quietInstall == 0 && i < [ipaFiles count]-1)printf("\n");}if (!removeAllContentsUnderPath(workPath)) {if (quietInstall < 2)printf("Failed to clean caches.\n");}[pool release];return successfulInstalls;
}

https://github.com/autopear/ipainstaller

中的theos工程经过make之后,需要手动ldid签名,之后打包deb才能正常工作

签名格式:

ldid -Ssign.plist XXXXX 

iOS 调用私有函数安装app 卸载 app相关推荐

  1. gifrecord可以卸载吗_频繁的安装和卸载app会不会伤害苹果手机?

    逼乎上看到一个xx的回答,转一下 作者:齐枫 问:频繁的安装和卸载app会不会伤害苹果手机?答:你好,会的知道为什么卸载APP的时候,所有APP图标都会一起抖动吗?除了被删的那个,其他的都被吓得瑟瑟发 ...

  2. iOS开发 关于调用私有函数 监测安装app 卸载 app

    MobileInstallation.framework 私有API 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 /* ...

  3. onclick如何调用含参函数_在 golang 中如何调用私有函数(绑定隐藏的标识符)

    名字在 golang 中的重要性和在其他任何一种语言是一样的.他们甚至含有语义的作用:在一个包的外部某个名字的可见性是由这个名字首字母是否是大写来决定的. 有时为了更好的组织代码或者在其他包使用某些隐 ...

  4. hybird app(混合式app开发)cordova ionic 创建相应平台的app

    hybird app(混合式app开发) 之ionic 框架平台 guide cordova 创建相应平台的app 1. npm install -g cordova //全局安装cordova-cl ...

  5. Android 9 P静默安装/卸载App适配终极指南

          Android 9 (P)静默安装/卸载App适配终极指南 Android 9 (P)开发适配指南系列博客目录: Adnroid 9 (P) recovery升级Map of '@/cac ...

  6. iOS js判断移动端是否安装某款app的方法

    一.判断是那种设备 var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 二. ios设备:原理:判断是否认识这个协议,认识则 ...

  7. 如何使用电脑共享给苹果iOS设备下载和安装APP

    现在的iTunes已经不能管理应用程序了, 而iMazing不但能够给具有文件共享功能的APP传输文档,还可以给设备安装或者卸载APP,极大地方便了使用者对应用程序的管理. 一.应用程序的下载 借助i ...

  8. 使用AccessibilityService实现APP的自动安装与卸载

    使用AccessibilityService实现APP的自动安装与卸载   作者: 蒋东国 时间: 2016年12月6日 星期二 应用来源: hqt APP(测试机型:三星 Note4) 博客地址: ...

  9. Android之解决卸载app后再次安装提示room数据库错误

    1.问题 目前只有一个google手机之前安装了app,里面有room写的数据库,后面把app卸载了,再次安装新的app(修改了数据库里面的字段),启动奔溃. 2.分析 提示数据库错误,很明显就像以前 ...

最新文章

  1. Android 引导界面制作
  2. ElasticSearch5.6安装head插件
  3. 配置一台计算机所需的东西,攒一台计算机需要的配置
  4. linux内核模块签名,如何签名内核模块Ubuntu 18.04
  5. 学python编程-趣学python编程中文版 PDF 下载
  6. 标准3层神经网络搭建Demo
  7. 网赚项目活动线报监控提醒
  8. 电力电子技术笔记(1)
  9. C语言—递归函数有5个人围坐在一起,问第5个人多大年纪,他说比第4个人大2岁;问第4个人,他说比第3个人大2岁;问第3个人,他说比第2个人大2岁;问第2个人,他说比第1个人大2岁。第1个人说自己10岁
  10. 台式计算机的配置怎么看,台式电脑配置怎么看
  11. python 爬虫 requests模块 中的Cookies 验证 通过验证cookies模拟登陆豆瓣登陆
  12. 深度学习基础(五):循环神经网络概念、结构及原理实现
  13. 《鸟哥的私房菜基础篇》第四版学习笔记——第0章 计算机概论
  14. 180122 逆向-Frida在Windows下的使用
  15. 认知网络知识点及例题总结
  16. 方式SingleTask 启动Intent设置 不能如愿打开需要的Activity
  17. 大数据 BigData
  18. NFS、GFS、NAS文件存储服务对比分析
  19. java生成一条唯一的邀请码_如何实现用户id生成一个唯一邀请码
  20. 关于抓包的一些常用软件

热门文章

  1. 《SOA与REST:用REST构建企业级SOA解决方案》目录—导读
  2. 2022年最新视觉框架VM PRO 2.7版本,增加了机器人 流程框架 多任务流程 C#源码框架,机器视觉源码框架,编程语言C#,算法使用的是halcon,参考了cognex visionpro的输入
  3. URL短链地址生成器Pckd
  4. java arraycopy
  5. AI画图 Disco-diffusion 本地搭建测试
  6. Quartus II 9.1的安装与破解
  7. Qt解压带有密码的加密文件
  8. 用于AR/MR的光波导足迹分析
  9. 大数据Flink(四十七):扩展阅读 File Sink
  10. 一个验证字符串是否纯英语的方法