You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

应用已在「打开方式...」菜单,无法加载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. 测试验证

  1. 重新安装主应用和Extension;
  2. 发送一封带PDF附件的邮件到测试设备;
  3. 打开邮件,点击PDF附件,选择「打开方式」里你的应用;
  4. 检查主应用是否能正确加载并展示PDF。如果失败,查看Xcode控制台的日志,排查Extension或主应用的错误信息。

内容的提问来源于stack exchange,提问作者neda Derakhshesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:57:53