iOS 分享扩展(四):让分享扩展与主应用无缝衔接

这里每天分享一个 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新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!

相关推荐
云深不知处_16 分钟前
RE0_OC_1
前端·ios
leluckys41 分钟前
swift-协程
开发语言·ios·swift
烈焰晴天4 小时前
新发布的一款使用ReactNative新架构加载Svga动画的开源插件[android/ios]
android·react native·ios
前端与小赵4 小时前
ios如何把H5网页变成主屏幕webapp应用
ios·web app
章鱼paul帝7 小时前
iOS 启动优化之自注册--attribute(section)
ios·性能优化
Larva7 小时前
记录使用 SwiftLint检测代码内的硬编码字符串
ios·swift·代码规范
iOS阿玮8 小时前
鬼才网友给苹果CEO写邮件,申诉找回账号的奇幻之旅。
uni-app·app·apple
大熊猫侯佩8 小时前
SwiftUI 中无法对添加模糊(blur)效果视图截图的初步解决
swiftui·swift·apple
大熊猫侯佩9 小时前
Swift 异步序列 AsyncStream 新“玩法”以及内存泄漏、死循环那些事儿(下)
swift·编程语言·apple