Reputation: 276
I am developing a share app and am having trouble with share invitations. I'm using Swift UI with iOS 16. I have come across two example projects which work fine except the share invitation fails the same way on both. In both, data is stored in cloud and the sharelink is generated correctly. However, the data in the link is not recognized or saved unless the recipient's app is already launched. If the recipient's app is not lauched before clicking the link, the app is only launched. The recipient has to go back to the link and then click a second time to get the share. It seems to boil down to the scene delegate func windowScene. It is not called unless the app is already launched. My questions are does anyone know of a workaround? can anyone concur this is a bug that Apple may be working on? is it only related to iOS 16? I assume these examples worked in earlier versions? The reference example links are below with delegate snippets.
Example 1: https://github.com/apple/sample-cloudkit-sharing.
Example 2: https://www.kodeco.com/29934862-sharing-core-data-with-cloudkit-in-swiftui
// Example 1
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
}
import UIKit
import SwiftUI
import CloudKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView().environmentObject(ViewModel())
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) {
guard cloudKitShareMetadata.containerIdentifier == Config.containerIdentifier else {
print("Shared container identifier \(cloudKitShareMetadata.containerIdentifier) did not match known identifier.")
return
}
// Create an operation to accept the share, running in the app's CKContainer.
let container = CKContainer(identifier: Config.containerIdentifier)
let operation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata])
debugPrint("Accepting CloudKit Share with metadata: \(cloudKitShareMetadata)")
operation.perShareResultBlock = { metadata, result in
let rootRecordID = metadata.rootRecordID
switch result {
case .failure(let error):
debugPrint("Error accepting share with root record ID: \(rootRecordID), \(error)")
case .success:
debugPrint("Accepted CloudKit share for root record ID: \(rootRecordID)")
}
}
operation.acceptSharesResultBlock = { result in
if case .failure(let error) = result {
debugPrint("Error accepting CloudKit Share: \(error)")
}
}
operation.qualityOfService = .utility
container.add(operation)
}
}
// Example 2
import CloudKit
import SwiftUI
final class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
let sceneConfig = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
sceneConfig.delegateClass = SceneDelegate.self
return sceneConfig
}
}
final class SceneDelegate: NSObject, UIWindowSceneDelegate {
func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) {
let shareStore = CoreDataStack.shared.sharedPersistentStore
let persistentContainer = CoreDataStack.shared.persistentContainer
persistentContainer.acceptShareInvitations(from: [cloudKitShareMetadata], into: shareStore) { _, error in
if let error = error {
print("acceptShareInvitation error :\(error)")
}
}
}
}
Upvotes: 2
Views: 203