iOS 7 及以下
AppStore 应用程序安装在/var/mobile/Applications 内部目录中,名称随机。应用程序的目录(文档、库等)和 *.app 目录都在其中。要确定它是哪个应用程序,您需要解析 *.app 目录中的 Info.plist 文件,其中存储了应用程序名称和包标识符。
iOS 8
Apple 彻底改变了 AppStore 应用程序存储在文件系统中的方式。我们现在需要的一切都在/var/mobile/Containers 目录中——此时我在下面提到的每个目录都包含在该目录中。所有捆绑包(任何包含应用程序代码的东西)都存储在Bundle 目录中。在那里你会找到应用程序、插件,可能还有其他一些东西。
例如,OpenVPN 应用程序包含两个带有应用程序代码的捆绑包 - OpenVPN.app 带有应用程序可执行文件,OpenVPNPlugin.vpnplugin 将 OpenVPN 协议实现为 iOS VPN 插件。 OpenVPN.app 位于 Applications 目录中,OpenVPNPlugin.vpnplugin 位于 VPNPlugin 中。出于某种原因,OpenVPNPlugin.vpnplugin 也存储在 Applications 中,但它看起来是出于兼容性原因的临时措施。
所有应用程序数据现在都存储在Data 目录中。应用程序、插件将其数据存储在该目录中。
应用程序目录(文档、库等)现在以随机名称存储在 Data/Application 内的目录中。要确定它是哪个应用程序目录,您需要解析Data/Application/xx-xx-xx/.com.apple.mobile_container_manager.metadata.plist。在里面你会发现 MCMMetadataIdentifier 包含应用程序包标识符的键。
我的设备上还有Data/PluginKitPlugin 和Data/VPNPlugin 目录。同样,分别解析 Data/PluginKitPlugin/xx-xx-xx/.com.apple.mobile_container_manager.metadata.plist 和 Data/VPNPlugin/xx-xx-xx/.com.apple.mobile_container_manager.metadata.plist。在其中你会找到包含插件包标识符的MCMMetadataIdentifier 键。对于 PluginKitPlugin,要确定它属于哪个应用程序,您需要转到 *.app。 PluginKitPlugin 包似乎存储在*.app/PlugIns 中。解析它的 Info.plist 以确定插件的包标识符。例如,您可以查看 Evernote 的存储方式。
最后是Shared 目录。它似乎包含可以在不同应用程序之间共享的应用程序文档。同样,在Shared 中,您将找到具有随机名称的目录。要确定哪个应用程序共享该文档,请解析 .com.apple.mobile_container_manager.metadata.plist。 MCMMetadataIdentifier 将包含 group. 字符串与应用的捆绑标识符连接。
iOS 8 更新
自 iOS 8.4 以来,Apple 再次改变了一切。现在没有.com.apple.mobile_container_manager.metadata.plist 文件。相反,您需要解析/var/mobile/Library/MobileInstallation/LastLaunchServicesMap.plist。它包含自 iOS 8 以来所有已安装应用程序(甚至是系统应用程序)的信息,因此您实际上根本不需要 .com.apple.mobile_container_manager.metadata.plist。
plist 的结构非常简单。首先是有两个主键的字典
-
系统 - 系统应用程序字典(包括 Cydia 应用程序)
-
用户 - 用户应用程序字典(AppStore、企业、开发者应用程序等)
那些字典使用包标识符作为键,使用应用程序信息作为值的字典。例如:
-
路径 - 应用程序包目录的路径
-
容器 - 应用程序目录(文档、库等)的路径
iOS 9 更新
看起来.com.apple.mobile_container_manager.metadata.plist 和/var/mobile/Library/MobileInstallation/LastLaunchServicesMap.plist 都太不可靠了。前者再次出现在 iOS 9 中 - 不知道 8.4 中发生了什么,可能是一个错误。后者并不总是最新的。事实上,大多数时候它包含旧信息。特别是对于应用程序沙箱路径。看起来它确实会定期更改,因为我发现 plist 给了我错误的路径。
有一个更可靠的解决方案,不需要摆弄 plist 或任何东西 - 来自 MobileCoreServices 框架的 LSApplicationWorkspace。它有 - (id)allInstalledApplications 方法,它返回一个 LSApplicationProxy 对象数组,这些对象将为您提供在 LastLaunchServicesMap.plist 中可能找到的所有信息。而且,如果我没记错的话,即使没有越狱它也可以工作。