I am able to send invitation from my device to friend's device. When friend clicks on invitation that was shared through text messages it says:
Open "Resources"?
User X wants to collaborate.
You'll join as User Y
(user Y @iCloud.com).
|Not Now| |Open|
If friend clicks on |Open|
then nothing happens. Share remains in "invited" state and the callbacks which I expected to be called are not.
The official Apple CloudKit Sharing App - https://github.com/apple/sample-cloudkit-sharing/blob/main/Sharing/App/AppDelegate.swift - is confusing me because it does not have following code like typical SwiftUI app:
@main
struct MainApp: App {
Instead it uses @main
for AppDelegate
.
Here is my code with prints that encode what is going on:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("I see this getting called on App startup")
return true
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
print("I also see this getting called on App startup")
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
print("I don't see this getting called")
}
func application(userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) -> Bool {
print("However, I expected this to be called when friend opened his CloudKit share invitation")
return false
}
}
@main
struct MainApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
static let sharedModelActor: ModelActorDatabase = {
let schema = Schema([
Resource.self,
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, cloudKitDatabase: .none)
do {
let modelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration])
return ModelActorDatabase(modelContainer: modelContainer)
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
@StateObject var syncedDatabase: SyncedDatabase = SyncedDatabase(modelContainer: Self.sharedModelActor.modelContainer)
var body: some Scene {
WindowGroup {
ResourceView()
.environmentObject(syncedDatabase)
}
.modelContainer( Self.sharedModelActor.modelContainer )
.database(SharedDatabase.shared.database)
}
}
I was expecting that this would call userDidAcceptCloudKitShareWith, but it is not. Why?
I implemented the userDidAcceptCloudKitShareWith… in the SceneDelegate, and set up the scene delegate as such:
class AppDelegate {
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
let config = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
config.delegateClass = SceneDelegate.self
return config
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) {
let acceptShareOperation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata])
acceptShareOperation.qualityOfService = .userInteractive
acceptShareOperation.perShareResultBlock = { meta, result in
guard let recordID = meta.hierarchicalRootRecordID else { return }
// do the things…
}
acceptShareOperation.acceptSharesResultBlock = { result in
// N/A
}
CKContainer(identifier: cloudKitShareMetadata.containerIdentifier).add(acceptShareOperation)
}
}