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

相关推荐
大熊猫侯佩12 小时前
WWDC 25 风云再起:SwiftUI 7 Charts 心法从 2D 到 3D 的华丽蜕变
swiftui·swift·wwdc
Engandend15 小时前
Flutter与iOS混合开发交互
flutter·ios·程序员
山水域17 小时前
GoogleAdsOnDeviceConversion 库的作用与用法
ios
Lucifer晓17 小时前
记录一次Flutter项目上传App Store Connect出现“Validation failed”错误的问题
flutter·ios
扶我起来还能学_19 小时前
uniapp Android&iOS 定位权限检查
android·javascript·ios·前端框架·uni-app
杂雾无尘21 小时前
SwiftUI 新手必读:如何用纯 SwiftUI 在应用中实现分段控制?
ios·swift·apple
开发者如是说1 天前
言叶是如何对文件进行端到端加密的
android·kotlin·swift
Daniel_Coder1 天前
iOS Widget 开发-5:Widget 与主 App 的通信原理:App Group、UserDefaults 与文件共享
ios·swift·widget
HX4361 天前
MP - Realm (not just realm)
android·ios·全栈
iOS阿玮1 天前
哪些产品符合免备案的骚操?看看你的产品符合吗?
uni-app·app·apple