应用已在「打开方式...」菜单,无法加载PDF,如何以URL方式实现?
解决应用从「打开方式」启动后无法加载PDF的问题
我之前也碰到过类似的场景,帮你梳理下关键的后续步骤,搞定PDF加载的问题:
1. 确保Action Extension的配置正确
首先检查Extension的Info.plist,必须正确设置激活规则,让系统知道你的Extension支持PDF文件。替换默认的NSExtensionActivationRule为以下配置,精准匹配PDF类型:
<key>NSExtensionActivationRule</key> <string>SUBQUERY ( extensionItems, $extensionItem, SUBQUERY ( $extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf" ).@count >= 1 ).@count >= 1</string>
2. 在Extension中获取PDF的安全URL
Extension需要从系统传递的extensionItems里提取PDF文件的URL,并且要处理沙盒的安全访问限制。在Extension的ViewController里添加以下代码:
override func viewDidLoad() { super.viewDidLoad() // 从Extension上下文获取输入项 guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem, let attachment = extensionItem.attachments?.first as? NSItemProvider, attachment.hasItemConformingToTypeIdentifier("com.adobe.pdf") else { // 没有找到PDF附件,结束Extension流程 extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) return } // 加载PDF附件 attachment.loadItem(forTypeIdentifier: "com.adobe.pdf", options: nil) { [weak self] (item, error) in guard let self = self else { return } defer { // 无论成功失败,都要结束Extension流程 self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) } if let pdfURL = item as? URL, pdfURL.startAccessingSecurityScopedResource() { defer { // 处理完URL后必须释放安全访问权限 pdfURL.stopAccessingSecurityScopedResource() } // 把PDF路径传递给主应用(这里用App Groups共享数据,记得先开启App Groups权限) let sharedDefaults = UserDefaults(suiteName: "group.com.yourapp.yourgroupid")! sharedDefaults.set(pdfURL.path, forKey: "PendingPDFPath") // 通过自定义URL Scheme打开主应用 guard let appURL = URL(string: "yourappscheme://openpdf") else { return } self.extensionContext?.open(appURL, completionHandler: nil) } } }
3. 主应用接收并加载PDF
主应用需要监听自定义URL Scheme,获取Extension传递的PDF路径,然后用PSPDFKit加载。以SceneDelegate为例:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { guard let url = URLContexts.first?.url, url.scheme == "yourappscheme", url.host == "openpdf" else { return } // 从共享的UserDefaults获取PDF路径 let sharedDefaults = UserDefaults(suiteName: "group.com.yourapp.yourgroupid")! guard let pdfPath = sharedDefaults.string(forKey: "PendingPDFPath"), let pdfURL = URL(fileURLWithPath: pdfPath) else { return } // 用PSPDFKit加载并展示PDF let pdfDocument = PSPDFDocument(url: pdfURL) let pdfVC = PSPDFViewController(document: pdfDocument) // 替换根VC或者present,根据你的应用结构调整 if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UINavigationController(rootViewController: pdfVC) window.makeKeyAndVisible() self.window = window } // 清理缓存的路径 sharedDefaults.removeObject(forKey: "PendingPDFPath") }
4. 关键注意事项
- 开启App Groups:主应用和Extension必须共享同一个App Group,才能通过UserDefaults传递数据。在Xcode的Capabilities里开启App Groups,设置相同的Group ID。
- 自定义URL Scheme:在主应用的
Info.plist里添加CFBundleURLTypes,注册你的URL Scheme(比如yourappscheme)。 - 沙盒安全:处理安全域URL时,必须调用
startAccessingSecurityScopedResource()和stopAccessingSecurityScopedResource(),否则无法访问文件。
5. 测试验证
- 重新安装主应用和Extension;
- 发送一封带PDF附件的邮件到测试设备;
- 打开邮件,点击PDF附件,选择「打开方式」里你的应用;
- 检查主应用是否能正确加载并展示PDF。如果失败,查看Xcode控制台的日志,排查Extension或主应用的错误信息。
内容的提问来源于stack exchange,提问作者neda Derakhshesh
相关产品推荐
相关产品推荐

