iOS 分享与打开到 YourProject 整体流程

本文整理「从系统外把内容分享到 / 打开到某个 iOS App」相关的底层机制与典型实现,适合作为设计入口、排查问题和扩展新分享场景的参考。


1. 常见入口类型概览

  • 文件类(Word / PDF / TXT / 本地图片等)通过“在其他应用中打开”

    • 系统复制文件到目标 App 的沙盒
    • 通过 application(_:open:options:) 传入一个 file:// URL
  • URL / Deep Link(myapp://... / https://... / 登录回调等)

    • 通过 URL Scheme / Universal Link 进入
    • application(_:open:options:)application(_:continue:restorationHandler:) 处理
  • Share Extension(分享扩展)

    • 系统用 NSItemProvider 把文本 / 图片 / URL 等数据交给扩展进程
    • 扩展通过 App Group + 自定义 URL(例如 myapp://ShareExtension)唤醒主 App 并传递数据
  • Universal Link + 特殊业务场景(如 NFC、H5 落地页)

    • 通过 NSUserActivitywebpageURL 进入
    • application(_:continue:restorationHandler:) 处理

2. 文件类分享(Word / PDF / TXT / 图片等)

2.1 系统层:从外部 App 到目标 App 的文件交接

当用户在外部 App(Files / Word / WPS / 邮件附件等)中选择「在其他应用中打开到某 App」时:

  1. 源 App 发起打开请求

    • 通过 UIDocumentInteractionControllerUIDocumentPickerViewController 或 Files 等文档浏览入口
    • 告诉系统:「这里有一个文件,可以由支持该类型的 App 打开」
  2. iOS 匹配目标 App

    • 查目标 App 的 Info.plistCFBundleDocumentTypes / UTI / UTType 配置
    • 判断该 App 是否支持此文件类型(.docx / .pdf / .txt / 图片等)
  3. 复制/授权文件到目标 App 沙盒

    • 系统将文件复制或授权到目标 App 可访问的路径(常见在 tmp/Inbox/),例如:
      • /var/mobile/Containers/Data/Application/<App_UUID>/tmp/Inbox/xxx.docx
    • 用这个路径构造一个本地 file:// URL
  4. 调用 App 入口

    • 进入 AppDelegate
      func application(_ app: UIApplication,
                       open url: URL,
                       options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
      
    • 参数 url 就是上述 file://... 路径

这个 URL 是「复制到当前 App 沙盒中的本地文件路径」,不是公网链接,也不是所有 App 可见的共享 URL。

2.2 App 内对文件 URL 的典型处理流程

application(_:open:options:) 内,典型文件处理流程可以设计为:

  1. 优先交给第三方 SDK(登录回调 / 统计 / 分享 SDK 等)

    if someSDK.handle(url) { return true }
    
  2. 记录“从文档打开”的状态(可选)

    openedFromDocument = true
    
  3. 主页尚未初始化(冷启动)时先缓存 URL

    guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else {
        UserDefaults.standard.set(url.absoluteString, forKey: "ShareContentURL")
        return true
    }
    
  4. 内部 URL Scheme 路由(如 myapp://,与文件分享无关时可提前返回)

    if url.absoluteString.hasPrefix("myapp:") {
        // 执行内部路由
        return true
    }
    
  5. 其它特殊链接(如某些 H5 活动)可单独判断(可选)

  6. 兜底:视为文件分享 → 进入文档打印 / 预览模块

    // 直接或稍作延迟,等待 UI / 导航栈稳定
    documentRouter.openDocument(from: rootVC, fileURL: url)
    return true
    

2.3 是否要再复制到自定义目录?

  • 一次性使用(只打印 / 预览一次,不做历史记录)
    • 可以直接使用系统给的 file://.../tmp/Inbox/... 路径。
  • 需要长期保存 / 历史记录 / 再次编辑
    • 建议在第一次拿到 url 时:
      let destURL = ... // 比如 Documents/ImportedDocs/xxx.docx
      try? FileManager.default.copyItem(at: url, to: destURL)
      
    • 后续所有逻辑以 destURL 为准,而不是继续依赖 tmp/Inbox(该目录会被系统清理)。

3. 文本类分享:文本文件 vs 纯文本内容

3.1 文本文件(.txt)作为文件分享

.txt 作为文件被“打开到 App”时:

  1. 走的是文件分享机制:系统复制文件 → file://...xxx.txtapplication(_:open:options:)
  2. 文档模块可以定义统一入口:
    func loadDocument(_ url: URL) {
        let lower = url.absoluteString.lowercased()
        switch true {
        case lower.hasSuffix("doc"), lower.hasSuffix("docx"):
            wordToImage(url)
        case lower.hasSuffix("txt"):
            txtFileToImage(url)    // 从 txt 文件路径读取文本
        case lower.hasSuffix("pdf"):
            pdfToImage(url)
        default:
            break
        }
    }
    
  3. txtFileToImage(_ url: URL) 内部典型实现:
    • 使用适当编码(GBK / UTF-8 等)读取文本;
    • WKWebView.loadHTMLString 把内容排版为 HTML;
    • 再渲染为图片,适配打印页面尺寸。

3.2 纯文本内容(不是文件,不是 URL):通过 Share Extension

当用户在其他 App 中选中一段文本,通过系统分享面板分享到目标 App:

3.2.1 系统层:Share Extension + NSItemProvider

  1. 源 App 使用 UIActivityViewController 触发分享面板;
  2. 将文本封装为 NSItemProvider,UTType 为 public.text / public.plain-text
  3. 系统根据各 Share Extension 的 NSExtensionActivationRule 判断哪些扩展支持该类型;
  4. 用户选中某 App 的 Share Extension 后:
    • 系统启动该扩展进程;
    • 通过 NSExtensionContext.inputItemsNSExtensionItem 列表传给扩展;
    • 扩展再通过 NSItemProvider.loadItem(forTypeIdentifier: ...) 异步拿到实际的 String 文本。

3.2.2 扩展 → 主 App:App Group + 自定义 URL

典型做法:

  1. 扩展将解析出的数据打包成一个字典,比如:
    let payload: [String: Any] = [
        "type": 4,            // 自定义业务类型:例如“文本+文档打印”
        "txt":  textContent,  // 文本内容
        "url":  fileURLString // 可选:源文件名/URL,或其它元数据
    ]
    
  2. 通过 App Group 的 UserDefaults(suiteName:) 或共享文件写入该字典;
  3. 通过固定 URL Scheme 唤醒主 App,例如:
    let url = URL(string: "myapp://ShareExtension")!
    extensionContext.open(url, completionHandler: nil)
    

3.2.3 主 App:从共享容器读取文本并处理

  1. 主 App 在 application(_:open:options:) 中识别:
    if url.absoluteString == "myapp://ShareExtension" {
        // 从 App Group 容器读取扩展存入的字典
    }
    
  2. UserDefaults(suiteName:) 或共享文件中读出字典,根据 type 分流:
    • 纯文本 → 文本编辑页;
    • 文本+文档 → 文档打印页;
    • 图片数组 → 图片相关业务等。
  3. 对于「文本 + 文档打印」场景,一个常见模式是:
    • txt 传给 txtToImage(contents:)(直接按字符串排版成图片);
    • txt 及文件名/元信息落盘到自定义目录,以供后续再次打开。

4. URL / Deep Link 入口

4.1 URL Scheme / 深链

示例:

UIApplication.shared.open(URL(string: "myapp://page/editNote?id=123")!)

流程:

  1. 系统根据 Info.plistCFBundleURLTypes 匹配 App;
  2. 调用:
    func application(_ app: UIApplication,
                     open url: URL,
                     options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
    
  3. App 内可按以下顺序处理:
    • 优先交给第三方 SDK(登录、统计、分享等);
    • 按 URL 前缀/路径分发到路由层,例如:
      if url.scheme == "myapp" {
          router.route(url)
          return true
      }
      
    • 其它不识别的 URL 可以选择忽略或记录日志。

4.2 Universal Link(含 H5 落地页 / NFC 场景)

  1. App 为某域名配置 Associated Domains(如 applinks:example.com);
  2. 用户在 Safari / 邮件 / 其它 App 中点击该域名链接;
  3. 系统创建 NSUserActivity
    • activityType = NSUserActivityTypeBrowsingWeb
    • webpageURL = 对应的 https:// 链接
  4. 调用:
    func application(_ application: UIApplication,
                     continue userActivity: NSUserActivity,
                     restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool
    
  5. App 内可以:
    • 检查 userActivity.activityType 是否为 NSUserActivityTypeBrowsingWeb
    • 根据 webpageURL 判断是否为某个业务场景(如 NFC、H5 落地页、营销活动页);
    • 结合当前状态(隐私协议是否同意、当前流程是否允许跳转)决定是否拦截或跳转到目标页面。

5. Share Extension 能力与支持类型

Share Extension 能处理的数据类型取决于扩展 target 的 Info.plist 中:

  • NSExtensionAttributesNSExtensionActivationRule(以及支持的 UTType)

常见可配置类型包括:

  • 文本:public.text / public.plain-text
  • 图片:public.image
  • URL:public.url
  • 各类文档:如 PDF、Office 文档等对应的 UTType

在扩展代码里,可以统一将这些类型抽象成内部结构(比如 type + payload),再使用 App Group 传递给主 App,由主 App 按业务类型分发。


6. FAQ 总结

  • Q:分享 Word / PDF / TXT / 图片到 App 时,底层是什么机制?
    A:文件分享 / Open In。系统复制到 App 沙盒 → file:// URL → application(_:open:options:) → 文档/图片业务。

  • Q:分享的是一段“文本内容”(不是 URL,不是 txt 文件),系统怎么传给 App?
    A:通过 Share Extension。系统用 NSItemProvider(public.text) 把文本交给扩展 → 扩展写入 App Group 容器 → 通过固定 URL 唤醒主 App → 主 App 从共享容器读取文本并处理。

  • Q:拿到 URL 后要不要再复制到自定义目录?
    A

    • 只用一次:可以直接用系统给的 file:// 路径;
    • 需要长期保存/再编辑/历史记录:应该复制到自己控制的沙盒目录,再以新路径为准。
  • Q:Share Extension 只能分享图片吗?
    A:不是。它可以支持文本、URL、图片、各种文档等,具体取决于扩展 target 中声明的支持类型(UTType)以及扩展代码如何从 NSItemProvider 中抽取数据。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容