iOS 11+及Swift环境下获取已安装应用列表及验证应用可打开性咨询
哥们儿,我刚好踩过iOS获取已安装应用列表的坑,结合你的情况给你梳理下可行方案——毕竟iOS的沙盒和审核限制真的挺严格的:
苹果从iOS 9开始就严格限制第三方应用获取设备上的全部应用列表,私有API虽然能实现,但100%会被审核拒绝,而且iOS 11+之后对私有API的管控更严,这也是你之前尝试私有框架没成功的原因之一。
如果你的应用是要上架App Store的,只能通过「预设URL Scheme」的方式检测特定应用是否存在,没办法拿到全量列表。
这部分是完全合规的,不管iOS版本高低都能用:
第一步:配置Info.plist
在Info.plist中添加LSApplicationQueriesSchemes数组,把你要检测的应用的URL Scheme加进去(比如微信是weixin,支付宝是alipay)。这是iOS 9及以后的强制要求,否则canOpenURL会直接返回false。第二步:用
canOpenURL检测并打开应用
示例Swift代码:import UIKit // 检测应用是否可打开 func canOpenTargetApp(scheme: String) -> Bool { guard let appURL = URL(string: scheme) else { return false } return UIApplication.shared.canOpenURL(appURL) } // 打开应用(如果存在) func openTargetApp(scheme: String) { guard let appURL = URL(string: scheme), UIApplication.shared.canOpenURL(appURL) else { print("应用未安装或无法打开") return } // iOS 10+ 用open(_:options:completionHandler:) if #available(iOS 10.0, *) { UIApplication.shared.open(appURL, options: [:], completionHandler: nil) } else { UIApplication.shared.openURL(appURL) } } // 使用示例:检测并打开微信 if canOpenTargetApp(scheme: "weixin://") { openTargetApp(scheme: "weixin://") } else { print("未安装微信") }注意:每个应用的URL Scheme需要提前确认(通常可以在官方文档或开发者社区找到),部分应用可能有多个Scheme。
如果你的应用不需要上架App Store,比如企业内部使用,可以试试用LSApplicationWorkspace的私有方法,但要做好适配iOS版本的准备:
示例代码(Swift):
import UIKit func getAllInstalledApps() { // 动态加载私有框架 guard let workspaceClass = NSClassFromString("LSApplicationWorkspace") as? NSObject.Type else { print("无法获取LSApplicationWorkspace类") return } guard let workspace = workspaceClass.perform(Selector(("defaultWorkspace")))?.takeUnretainedValue() else { print("无法获取Workspace实例") return } // 调用私有方法获取所有已安装应用 guard let installedApps = workspace.perform(Selector(("allInstalledApplications")))?.takeUnretainedValue() as? [AnyObject] else { print("无法获取应用列表") return } // 遍历应用信息 for app in installedApps { let bundleID = app.perform(Selector(("bundleIdentifier")))?.takeUnretainedValue() as? String ?? "未知BundleID" let appName = app.perform(Selector(("localizedName")))?.takeUnretainedValue() as? String ?? "未知应用名" let isSystemApp = app.perform(Selector(("isSystemApplication")))?.takeUnretainedValue() as? Bool ?? false print("应用名:\(appName) | BundleID:\(bundleID) | 系统应用:\(isSystemApp ? "是" : "否")") } }
⚠️ 注意事项:
- iOS 11+真机上可能需要开启特定权限,或者苹果已经封堵了该API,你之前失败可能是因为这个原因
- 私有API随时可能被苹果修改,后续iOS版本更新可能会失效
- 打包时需要避免被静态代码分析工具检测到私有API(可以通过动态Selector的方式规避)
如果你的上架应用需要让用户选择其他应用,可以用UIDocumentPickerViewController或者系统分享面板,让用户手动选择要打开的应用,这种方式完全合规,不会有审核风险。
内容的提问来源于stack exchange,提问作者YouginaCH

