iOS 分享與打開到 YourProject 整體流程

本文整理「從系統(tǒng)外把內(nèi)容分享到 / 打開到某個 iOS App」相關(guān)的底層機制與典型實現(xiàn),適合作為設(shè)計入口、排查問題和擴展新分享場景的參考。


1. 常見入口類型概覽

  • 文件類(Word / PDF / TXT / 本地圖片等)通過“在其他應(yīng)用中打開”

    • 系統(tǒng)復(fù)制文件到目標(biāo) App 的沙盒
    • 通過 application(_:open:options:) 傳入一個 file:// URL
  • URL / Deep Link(myapp://... / https://... / 登錄回調(diào)等)

    • 通過 URL Scheme / Universal Link 進入
    • application(_:open:options:)application(_:continue:restorationHandler:) 處理
  • Share Extension(分享擴展)

    • 系統(tǒng)用 NSItemProvider 把文本 / 圖片 / URL 等數(shù)據(jù)交給擴展進程
    • 擴展通過 App Group + 自定義 URL(例如 myapp://ShareExtension)喚醒主 App 并傳遞數(shù)據(jù)
  • Universal Link + 特殊業(yè)務(wù)場景(如 NFC、H5 落地頁)

    • 通過 NSUserActivitywebpageURL 進入
    • application(_:continue:restorationHandler:) 處理

2. 文件類分享(Word / PDF / TXT / 圖片等)

2.1 系統(tǒng)層:從外部 App 到目標(biāo) App 的文件交接

當(dāng)用戶在外部 App(Files / Word / WPS / 郵件附件等)中選擇「在其他應(yīng)用中打開到某 App」時:

  1. 源 App 發(fā)起打開請求

    • 通過 UIDocumentInteractionControllerUIDocumentPickerViewController 或 Files 等文檔瀏覽入口
    • 告訴系統(tǒng):「這里有一個文件,可以由支持該類型的 App 打開」
  2. iOS 匹配目標(biāo) App

    • 查目標(biāo) App 的 Info.plistCFBundleDocumentTypes / UTI / UTType 配置
    • 判斷該 App 是否支持此文件類型(.docx / .pdf / .txt / 圖片等)
  3. 復(fù)制/授權(quán)文件到目標(biāo) App 沙盒

    • 系統(tǒng)將文件復(fù)制或授權(quán)到目標(biāo) App 可訪問的路徑(常見在 tmp/Inbox/),例如:
      • /var/mobile/Containers/Data/Application/<App_UUID>/tmp/Inbox/xxx.docx
    • 用這個路徑構(gòu)造一個本地 file:// URL
  4. 調(diào)用 App 入口

    • 進入 AppDelegate
      func application(_ app: UIApplication,
                       open url: URL,
                       options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
      
    • 參數(shù) url 就是上述 file://... 路徑

這個 URL 是「復(fù)制到當(dāng)前 App 沙盒中的本地文件路徑」,不是公網(wǎng)鏈接,也不是所有 App 可見的共享 URL。

2.2 App 內(nèi)對文件 URL 的典型處理流程

application(_:open:options:) 內(nèi),典型文件處理流程可以設(shè)計為:

  1. 優(yōu)先交給第三方 SDK(登錄回調(diào) / 統(tǒng)計 / 分享 SDK 等)

    if someSDK.handle(url) { return true }
    
  2. 記錄“從文檔打開”的狀態(tài)(可選)

    openedFromDocument = true
    
  3. 主頁尚未初始化(冷啟動)時先緩存 URL

    guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else {
        UserDefaults.standard.set(url.absoluteString, forKey: "ShareContentURL")
        return true
    }
    
  4. 內(nèi)部 URL Scheme 路由(如 myapp://,與文件分享無關(guān)時可提前返回)

    if url.absoluteString.hasPrefix("myapp:") {
        // 執(zhí)行內(nèi)部路由
        return true
    }
    
  5. 其它特殊鏈接(如某些 H5 活動)可單獨判斷(可選)

  6. 兜底:視為文件分享 → 進入文檔打印 / 預(yù)覽模塊

    // 直接或稍作延遲,等待 UI / 導(dǎo)航棧穩(wěn)定
    documentRouter.openDocument(from: rootVC, fileURL: url)
    return true
    

2.3 是否要再復(fù)制到自定義目錄?

  • 一次性使用(只打印 / 預(yù)覽一次,不做歷史記錄)
    • 可以直接使用系統(tǒng)給的 file://.../tmp/Inbox/... 路徑。
  • 需要長期保存 / 歷史記錄 / 再次編輯
    • 建議在第一次拿到 url 時:
      let destURL = ... // 比如 Documents/ImportedDocs/xxx.docx
      try? FileManager.default.copyItem(at: url, to: destURL)
      
    • 后續(xù)所有邏輯以 destURL 為準(zhǔn),而不是繼續(xù)依賴 tmp/Inbox(該目錄會被系統(tǒng)清理)。

3. 文本類分享:文本文件 vs 純文本內(nèi)容

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

當(dāng) .txt 作為文件被“打開到 App”時:

  1. 走的是文件分享機制:系統(tǒng)復(fù)制文件 → file://...xxx.txtapplication(_:open:options:)。
  2. 文檔模塊可以定義統(tǒng)一入口:
    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) 內(nèi)部典型實現(xiàn):
    • 使用適當(dāng)編碼(GBK / UTF-8 等)讀取文本;
    • WKWebView.loadHTMLString 把內(nèi)容排版為 HTML;
    • 再渲染為圖片,適配打印頁面尺寸。

3.2 純文本內(nèi)容(不是文件,不是 URL):通過 Share Extension

當(dāng)用戶在其他 App 中選中一段文本,通過系統(tǒng)分享面板分享到目標(biāo) App:

3.2.1 系統(tǒng)層:Share Extension + NSItemProvider

  1. 源 App 使用 UIActivityViewController 觸發(fā)分享面板;
  2. 將文本封裝為 NSItemProvider,UTType 為 public.text / public.plain-text
  3. 系統(tǒng)根據(jù)各 Share Extension 的 NSExtensionActivationRule 判斷哪些擴展支持該類型;
  4. 用戶選中某 App 的 Share Extension 后:
    • 系統(tǒng)啟動該擴展進程;
    • 通過 NSExtensionContext.inputItemsNSExtensionItem 列表傳給擴展;
    • 擴展再通過 NSItemProvider.loadItem(forTypeIdentifier: ...) 異步拿到實際的 String 文本。

3.2.2 擴展 → 主 App:App Group + 自定義 URL

典型做法:

  1. 擴展將解析出的數(shù)據(jù)打包成一個字典,比如:
    let payload: [String: Any] = [
        "type": 4,            // 自定義業(yè)務(wù)類型:例如“文本+文檔打印”
        "txt":  textContent,  // 文本內(nèi)容
        "url":  fileURLString // 可選:源文件名/URL,或其它元數(shù)據(jù)
    ]
    
  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:) 或共享文件中讀出字典,根據(jù) type 分流:
    • 純文本 → 文本編輯頁;
    • 文本+文檔 → 文檔打印頁;
    • 圖片數(shù)組 → 圖片相關(guān)業(yè)務(wù)等。
  3. 對于「文本 + 文檔打印」場景,一個常見模式是:
    • txt 傳給 txtToImage(contents:)(直接按字符串排版成圖片);
    • txt 及文件名/元信息落盤到自定義目錄,以供后續(xù)再次打開。

4. URL / Deep Link 入口

4.1 URL Scheme / 深鏈

示例:

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

流程:

  1. 系統(tǒng)根據(jù) Info.plistCFBundleURLTypes 匹配 App;
  2. 調(diào)用:
    func application(_ app: UIApplication,
                     open url: URL,
                     options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
    
  3. App 內(nèi)可按以下順序處理:
    • 優(yōu)先交給第三方 SDK(登錄、統(tǒng)計、分享等);
    • 按 URL 前綴/路徑分發(fā)到路由層,例如:
      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. 系統(tǒng)創(chuàng)建 NSUserActivity
    • activityType = NSUserActivityTypeBrowsingWeb
    • webpageURL = 對應(yīng)的 https:// 鏈接
  4. 調(diào)用:
    func application(_ application: UIApplication,
                     continue userActivity: NSUserActivity,
                     restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool
    
  5. App 內(nèi)可以:
    • 檢查 userActivity.activityType 是否為 NSUserActivityTypeBrowsingWeb;
    • 根據(jù) webpageURL 判斷是否為某個業(yè)務(wù)場景(如 NFC、H5 落地頁、營銷活動頁);
    • 結(jié)合當(dāng)前狀態(tài)(隱私協(xié)議是否同意、當(dāng)前流程是否允許跳轉(zhuǎn))決定是否攔截或跳轉(zhuǎn)到目標(biāo)頁面。

5. Share Extension 能力與支持類型

Share Extension 能處理的數(shù)據(jù)類型取決于擴展 target 的 Info.plist 中:

  • NSExtensionAttributesNSExtensionActivationRule(以及支持的 UTType)

常見可配置類型包括:

  • 文本:public.text / public.plain-text
  • 圖片:public.image
  • URL:public.url
  • 各類文檔:如 PDF、Office 文檔等對應(yīng)的 UTType

在擴展代碼里,可以統(tǒng)一將這些類型抽象成內(nèi)部結(jié)構(gòu)(比如 type + payload),再使用 App Group 傳遞給主 App,由主 App 按業(yè)務(wù)類型分發(fā)。


6. FAQ 總結(jié)

  • Q:分享 Word / PDF / TXT / 圖片到 App 時,底層是什么機制?
    A:文件分享 / Open In。系統(tǒng)復(fù)制到 App 沙盒 → file:// URL → application(_:open:options:) → 文檔/圖片業(yè)務(wù)。

  • Q:分享的是一段“文本內(nèi)容”(不是 URL,不是 txt 文件),系統(tǒng)怎么傳給 App?
    A:通過 Share Extension。系統(tǒng)用 NSItemProvider(public.text) 把文本交給擴展 → 擴展寫入 App Group 容器 → 通過固定 URL 喚醒主 App → 主 App 從共享容器讀取文本并處理。

  • Q:拿到 URL 后要不要再復(fù)制到自定義目錄?
    A

    • 只用一次:可以直接用系統(tǒng)給的 file:// 路徑;
    • 需要長期保存/再編輯/歷史記錄:應(yīng)該復(fù)制到自己控制的沙盒目錄,再以新路徑為準(zhǔn)。
  • Q:Share Extension 只能分享圖片嗎?
    A:不是。它可以支持文本、URL、圖片、各種文檔等,具體取決于擴展 target 中聲明的支持類型(UTType)以及擴展代碼如何從 NSItemProvider 中抽取數(shù)據(jù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容