Markv07
Markv07

Reputation: 276

Problem with SwiftUI Cloud Sharing - Apple bug or not? Work around?

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

Answers (0)

Related Questions