将iOS应用程序(ipa文件)安装到另一个应用程序中?

4

我尝试编写一个应用程序,它可以从 Web 服务器(ipa 文件)下载应用程序并安装。有人知道如何安装这个 ipa 文件吗?我可以在应用程序中使用 OTA 还是使用命令行安装它?


3
你可以在越狱的设备上这样做。这个方案可行吗? - user529758
是的,可以,我该怎么做? - Quang Huynh
@QuangHuynh 你试过搜索吗? - trojanfoe
也许你可以寻找Testflight。他们为自己的应用提供证书,能够通过OTA安装其他IPA文件到设备上。 - who9vy
@trojanfoe 我搜索了很多但只找到OTA,或使用iFunbox、iTools安装ipa文件...或在越狱设备上通过终端安装ipa安装器控制台。 - Quang Huynh
显示剩余3条评论
2个回答

6

以下是针对越狱设备的即时解决方案,可以直接从应用程序中安装任何.ipa文件。您需要执行以下步骤:

I. 获得root访问权限。您可以通过在main()函数中调用setuid(0);来实现。您需要在可执行文件上设置粘性权限位并使用启动脚本。

II. 解压.ipa文件。没错,IPA只是伪装成ZIP文件。您可以使用开源的libzip库进行此操作。

III. 在其中有一个名为Payload的目录。实际的应用程序包(我们称其为MyApp.app)将驻留在该文件夹中。

IV. 在文件系统的/var/mobile/Applications目录中创建一个目录。这将是要安装的应用程序的容器沙盒。按照惯例,此目录的名称应为UUID。例如,您可以使用以下代码片段:

CFUUIDRef uuidObj = CFUUIDCreate(NULL);
CFStringRef uuid = CFUUIDCreateString(NULL, uuidObj);
CFRelease(uuidObj);

NSString *appPath = [@"/var/mobile/Applications" stringByAppendingPathComponent:(id)uuid];
[fmgr createDirectoryAtPath:appPath withIntermediateDirectories:YES attributes:nil error:NULL];
CFRelease(uuid);

V. 通过循环遍历在步骤 II 获取的 Payload 目录的内容,找到应用程序包并将其复制到新创建的沙盒中(其名称为 UUID 字符串)。同时复制 iTunesMetadata.plistiTunesArtwork 文件,以便 iTunes 显示一个漂亮的图标和通知您有更新。还要修复应用程序的可执行文件的权限,使其可以执行:

NSString *execName = [appInfoPlist objectForKey:@"CFBundleExecutable"];
NSString *execPath = [bundle stringByAppendingPathComponent:execName];
chmod(execPath.UTF8String, 0755);

VI. 您需要告诉SpringBoard定位您的应用程序,然后重新加载其已安装的应用程序缓存,以使新安装的图标出现在主屏幕上。为此,首先更新MobileInstallation属性列表文件中应用程序列表。这里的 bundle 变量指的是应用包的文件系统位置,类似于 /var/mobile/applications/LONG_UUID_STRING/MyApp.app

#define kMobileInstallationPlistPath @"/var/mobile/Library/Caches/com.apple.mobile.installation.plist"
NSMutableDictionary *appInfoPlist = [NSMutableDictionary dictionaryWithContentsOfFile:[bundle stringByAppendingPathComponent:@"Info.plist"]];
[appInfoPlist setObject:@"User" forKey:@"ApplicationType"];
[appInfoPlist setObject:bundle forKey:@"Path"];
[appInfoPlist setObject:@{
    @"CFFIXED_USER_HOME" : appPath,
    @"HOME" : appPath,
    @"TMPDIR" : [appPath stringByAppendingPathComponent:@"tmp"]
} forKey:@"EnvironmentVariables"];
[appInfoPlist setObject:appPath forKey:@"Container"];

NSData *data = [NSData dataWithContentsOfFile:kMobileInstallationPlistPath];
NSMutableDictionary *mobileInstallation = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:NULL error:NULL];
NSString *bundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"];
[[mobileInstallation objectForKey:@"User"] setObject:appInfoPlist forKey:bundleID];
[mobileInstallation writeToFile:kMobileInstallationPlistPath atomically:NO];

然后删除SpringBoard存储的缓存应用程序信息:

remove("/var/mobile/Library/Caches/com.apple.mobile.installation.plist");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-icons");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-icons.plist");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-smallicons");
remove("/var/mobile/Library/Caches/com.apple.springboard-imagecache-smallicons.plist");
remove("/var/mobile/Library/Caches/SpringBoardIconCache");
remove("/var/mobile/Library/Caches/SpringBoardIconCache-small");
remove("/var/mobile/Library/Caches/com.apple.IconsCache");

然后通知SpringBoard重新加载所有应用程序的列表:
Class __LSApplicationWorkspace = objc_getClass("LSApplicationWorkspace");
[(LSApplicationWorkspace *)[__LSApplicationWorkspace defaultWorkspace] invalidateIconCache:nil];
[(LSApplicationWorkspace *)[__LSApplicationWorkspace defaultWorkspace] registerApplication:[NSURL fileURLWithPath:bundle]];
notify_post("com.apple.mobile.application_installed");

@QuangHuynh 谢谢您的回复,您能否给我一些关于如何做到这一点的想法?那将是非常好的。 - Deepika Lalra
@QuangHuynh 很高兴你找到了另一种解决问题的方式。我就像Deepika Lara一样,希望你能与我们分享。谢谢。 - Sovannarith
@sovannarith 确定你的进程有root权限吗? - user529758
@QuangHuynh 它给我报错 (MobileInstallationInstall),pMobileInstallationInstall = <register sp is not available> 有什么想法吗? - Deepika Lalra
1
@DeepikaLalra,你应该尝试一下这个解决方案:https://dev59.com/7GvXa4cB1Zd3GeqPOe81。 - Quang Huynh
显示剩余47条评论

2

1
我能否使用OTA技术,而不使用Safari,而是使用Objective-C代码? - Quang Huynh
1
以下是如何调用URL的示例:https://github.com/bitstadium/HockeySDK-iOS/blob/develop/Classes/BITUpdateManager.m#L725 要添加到末尾的URL是上面提到的plist文件的链接。 - Kerni
@Kerni 如果我们使用这种方法,苹果会限制应用程序数量(100个)吗? - Quang Huynh
这是期望的行为,但首先应该出现一个提示来询问您是否要安装该应用程序。您确定您的 plist 格式正确吗? - ashtom
@ashtom 一切都运行良好,当用户点击安装按钮时应用程序已经安装,但是我该如何跟踪用户是否点击了“安装”或“取消”,因为我需要根据用户的点击执行一些操作? - Quang Huynh
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接