这里每天分享一个 iOS 的新知识,快来关注我吧
前言
在之前的文章中,我们已经学习了如何添加分享扩展、配置 info.plist 文件和自定义 ShareViewController 的 UI。
今天,我们将进一步探讨如何将用户在分享扩展中分享的内容传回主应用,以便进行进一步的操作或处理。这一步将使我们的应用更加灵活和功能丰富。
往期文章:
iOS 分享扩展(一):如何让你的 App 出现在 iOS 系统的分享面板中
iOS 分享扩展(二):info.plist 文件配置全解析
iOS 分享扩展(三):轻松定制 iOS 分享界面,提升用户体验
读取用户分享的内容
在分享扩展的 ShareViewController
中,我们可以通过 NSItemProvider
来读取用户分享的内容。在这个例子中,我们假设用户分享的内容是一个 URL。
其实要想使用用户分享的内容,主要有两种方法:
-
直接在扩展中处理,这种适合分享的内容比较少,且不太需要主应用参与的情况
-
传回主应用中处理,这种适合分享的内容比较多,需要依赖主应用的地方比较多
今天我们主要讲解第二种方法,传回主应用中处理。因为这种方式的好处是可以充分利用主应用的能力,并且可以拉起主应用,多一次启动的机会。也是目前比较主流的做法。
首先我们需要将用户分享的内容读出来,这一步在之前的文章中已经讲过了,这里就不再赘述了,不清楚的可以去看之前的文章,这里直接上代码:
javascript
if let item = self.extensionContext?.inputItems.first as? NSExtensionItem,
let itemProvider = item.attachments?.first as? NSItemProvider,
itemProvider.hasItemConformingToTypeIdentifier("public.url") {
itemProvider.loadItem(forTypeIdentifier: "public.url", options: nil) { (url, error) in
if let url = url as? URL {
// 读取到用户分享的内容
}
}
}
打开主应用
我们这里使用 URLSchemes 的方式来打开主应用,首先需要先在主应用中注册一个 URLSchemes,然后在分享扩展中使用这个 URLSchemes 来打开主应用。
让我们打开项目配置来注册一个 URLSchemes:

然后我们需要在 Appdelegate 中实现 application:openURL:options:
方法,来处理分享扩展传回的内容:
swift
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
print("用户分享的内容 url: \(url)")
return true
}
如果你的项目用的是 SceneDelegate,那么需要使用 scene:openURLContexts:
方法来处理:
swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
print("用户分享的内容: \(URLContexts)")
}
然后我们在分享扩展中,将用户分享的内容传回主应用:
swift
private func openMainApp(_ url: String) {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
let encodedURL = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let fullURL = "iOSNews://iosnews.com?url=\(encodedURL ?? "")"
if let url = URL(string: fullURL) {
application.open(url)
}
}
responder = responder?.next
}
}
解释一下这个方法:
-
这个方法会从当前的 responder 开始,一直向上找,直到找到一个 UIApplication 对象,然后使用 URLSchemes 的方式打开主应用
-
这里需要特别注意的是,URLSchemes 需要和主应用中注册的 URLSchemes 一致,否则会打不开主应用
当用户点击确认分享,我们只需要将 url 传入 openMainApp
方法,就可以在主应用中处理用户分享的内容了:

复杂的内容
如果用户分享的内容比较复杂,比如图片、视频等,那么我们可能无法通过一个简单的 URL 来描述,所以就需要使用 UserDefaults 来传递复杂的内容。这里我用图片举例,视频、音频、其他文件也是一样的。
默认情况下,分享扩展的沙盒目录是受限的,无法将数据通过 UserDefaults 与主应用共享,如果想在分享扩展中使用 UserDefaults,需要先创建一个 App Group:

然后点击加号创建一个新的 App Group,并填入一个标识符(后面需要用到),这里注意,主应用和分享扩展需要使用同一个 App Group:

然后我们就可以将用户分享的内容写入 UserDefaults 中了:
swift
private func readSharedImage() -> Data? {
if let item = self.extensionContext?.inputItems.first as? NSExtensionItem,
let itemProvider = item.attachments?.first as? NSItemProvider,
itemProvider.hasItemConformingToTypeIdentifier("public.image") {
itemProvider.loadItem(forTypeIdentifier: "public.image", options: nil) { (imageURL, error) in
if let imageURL = imageURL as? URL, let imageData = try? Data(contentsOf: imageURL) {
self.saveImageToUserDefaults(imageData)
// 存储之后打开主应用
self.openMainApp()
}
}
}
}
private func saveImageToUserDefaults(_ imageData: Data) {
UserDefaults(suiteName: "group.iosnews.shareExtension")?.set(imageData, forKey: "sharedImage")
}
最后在主应用中,我们可以从 UserDefaults 中读取分享的内容:
ini
let imageData = UserDefaults(suiteName: "group.iosnews.shareExtension")?.data(forKey: "sharedImage")
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
imageView.frame = view.bounds
imageView.image = UIImage(data: imageData)
总结
通过将用户在分享扩展中分享的内容传回主应用,我们可以实现用户分享内容与主应用的共享,从而使应用的功能更加丰富和灵活。希望本文能帮助你更好地理解如何处理用户分享的内容,并在应用中实现进一步的操作。
在未来的文章中,我们将继续探讨 iOS 分享扩展的更多高级特性和实践。感谢你的阅读和关注!如果你有任何问题或建议,欢迎与我交流。让我们一起不断学习,共同进步。
这里每天分享一个 iOS 的新知识,快来关注我吧
本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!