Share Extension — 是一种 iOS 扩展,可将您的应用程序添加到系统菜单 “分享”(Share Sheet)中。用户可以从 Safari、照片、文件或任何其他应用程序直接向您的应用程序发送内容,无需复制和在窗口之间切换。根据 Apple(2024)的数据,带有 Share Extension 的应用程序比没有分享功能的应用程序多接收 35% 的用户内容。该扩展通过统一的 NSExtensionItem 接口处理文本、图像、视频、URL 和文件。
要点
Share Extension — 是一种 iOS app extension 类型,在选择任何应用程序中的内容时出现在系统菜单 “分享”中。用户在 Safari 中选择文本,点击 “分享”,然后在可用操作列表中看到您的应用程序。选择后,内容被发送到扩展进行处理:保存、发布、发送或转换。
与 Action Extension 不同,Share Extension 专门用于接收来自外部应用程序的内容。Action Extension 则相反,将数据从您的应用程序发送到外部。Share Extension 是用户内容的入口点,是用户获取的关键元素:用户通过 Share Extension 试用应用程序,而无需完全安装。App Store 禁止唯一功能是通过 Share Extension 显示广告的应用程序(App Store Review Guideline 4.2)。
Share Extension 降低了进入门槛:用户从熟悉的上下文(浏览器、图库、文件管理器)向您的应用程序发送内容。根据 Branch(2024)的数据,带有 Share Extension 的应用程序在第 7 天显示出 28% 更高的留存率。额外效果是病毒式传播:每次用户在 Share Sheet 中看到您的应用程序时,都会在不付出广告成本的情况下进行被动品牌推广。
Share Extension 的机制基于通过系统 NSExtensionItem 容器传输内容。主应用程序(Safari、照片)将所选内容打包到 NSExtensionItem 中,并指定类型(public.image、public.url、public.plain-text)。系统将此容器传递给扩展,扩展通过 extensionContext.inputItems 提取数据。
Share Extension 在单独的进程中启动,执行时间有限(约 30 秒处理时间)。扩展不应同步执行长时间操作。对于大文件上传,请使用带有后台配置的 NSURLSession。SLComposeServiceViewController 是 Share Extension 的基类,提供内容预览和发送按钮。
iOS 使用 Uniform Type Identifiers(UTI)来确定传输内容的类型。Share Extension 的主要 UTI:public.image(照片、截图)、public.url(链接)、public.plain-text(文本)、public.video(视频文件)和 public.file-url(文件)。扩展通过 NSExtensionActivationRule 键在 Info.plist 中注册支持的 UTI。
Share Extension 由三个组件组成:Xcode 中的目标 target、SLComposeServiceViewController 和 Info.plist 配置。架构决定了处理哪些内容类型、如何显示界面以及数据存储在哪里。
| 组件 | 用途 | 特点 |
|---|---|---|
| Target | 在 Xcode 中的扩展目标 | 带有标识符的独立 bundle |
| ViewController | 界面和处理逻辑 | SLComposeServiceViewController 或自定义 |
| Info.plist | 激活和 UTI 配置 | 带有谓词的 NSExtensionActivationRule |
| App Groups | 与应用程序的共享存储 | 用于数据传输的 UserDefaults suite |
Share Extension 配置的关键元素是激活规则。它决定了扩展在什么条件下出现在 Share Sheet 中。该规则在 Info.plist 中定义为带有限制的字典:最大图像数量、最小文本长度、必须存在 URL。标准规则为任意一种内容类型激活扩展。
// Info.plist — Share Extension 的 NSExtensionActivationRule
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>5</integer>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
让我们来看一个为书签应用程序在 Swift 中创建 Share Extension 的实际示例。扩展从 Safari 接收 URL,显示带有预览的界面,并将链接保存到 App Group 中。SLComposeServiceViewController 提供现成的 UI,带有文本字段和 Post 按钮。
import Social
import MobileCoreServices
class ShareViewController: SLComposeServiceViewController {
override func isContentValid() -> Bool {
return !(contentText?.isEmpty() ?? true)
}
override func didSelectPost() {
guard let item = extensionContext?.inputItems.first as? NSExtensionItem
else { return }
for attachment in item.attachments ?? [] {
attachment.loadItem(forTypeIdentifier: kUTTypeURL as String) {
[weak self] (item, error) in
if let url = item as? URL {
BookmarkService().save(url, title: self?.contentText)
}
self?.extensionContext?.completeRequest(
returningItems: [], completionHandler: nil)
}
}
}
}
发送内容后,扩展通过调用 completeRequest 结束其工作 — 这是必要步骤,否则系统不会释放扩展进程。重要:Share Extension 在受限环境中运行,对网络和文件系统的访问受限 — 请使用后台会话上传内容。
Share Extension 必须正确处理不同类型的输入数据:文本、图像、视频、URL 和文件。每种类型使用自己的 UTI 和数据提取方法。通用处理 — 通过遍历 attachment.attachments 并检查 hasItemConformingToTypeIdentifier。
图像作为 public.image 传输,可以通过 UIImage 或 Data 获取。对于大图像,在保存之前使用 jpegData(compressionQuality:)。Share Extension 不应在未经用户明确许可的情况下修改原始图像。建议将原始文件保存在 App Group 中,并创建预览以在界面中显示。
Safari 和其他浏览器将 URL 发送为 public.url,将选中的文本发送为 public.plain-text。一个 NSExtensionItem 可以同时包含两种类型 — 页面的 URL 和页面上选中的文本。Share Extension 应检查所有附件并提取相关数据。组合场景:将 URL 保存为书签,将文本保存为书签的注释。
Share Extension 和主应用程序在不同的进程中运行,没有对文件系统的共享访问权限。数据交换使用 App Groups 机制:带有 group.* 标识符的共享容器。将数据保存到 App Group 后,扩展通过 CFNotificationCenter 或 Darwin Notify 通知应用程序。
App Groups 在目标的 Capabilities 中启用:选择 “App Groups” 并添加标识符(例如 group.com.example.myapp)。两个目标(主应用程序和扩展)必须有权访问同一组。UserDefaults suite 允许以最小的开销在共享存储中读取和写入数据。
// 从 Share Extension 将数据保存到 App Group
let sharedDefaults = UserDefaults(suiteName: "group.com.example.myapp")
let bookmark: [String: Any] = [
"url": url.absoluteString,
"title": contentText ?? "",
"date": Date().timeIntervalSince1970
]
sharedDefaults?.set(bookmark, forKey: "bookmark_\(Date().timeIntervalSince1970)")
sharedDefaults?.synchronize()
常见问题
Share Extension 从其他应用程序接收内容到您的应用程序。Action Extension 则相反,在主应用程序内对内容执行操作 — 翻译文本、修改图像。Share Extension — 接收,Action Extension — 转换。
取决于您应用程序的内容类型。对于书签 — public.url。对于照片编辑器 — public.image。对于笔记 — public.plain-text。对于多种类型,请使用带有 AND/OR 谓词组合的 NSExtensionActivationRule。
常见原因是 NSExtensionActivationRule 不正确或 UTI 不匹配。在 Info.plist 中检查:激活规则必须与测试的内容类型匹配。还要确保扩展已在设置 → 您的应用程序 → Siri 和搜索中启用。Xcode clean build 通常可以解决问题。
系统分配大约 30 秒 用于执行。之后 iOS 会强制终止扩展进程。对于长时间操作,请使用后台 NSURLSession,并在下次启动应用程序时处理结果。
可以,可以使用普通的 UIViewController 替代 SLComposeServiceViewController。在这种情况下,您可以完全控制界面。但是,发送和取消按钮需要您自己实现。自定义 UI 建议用于非标准的内容处理场景。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。