Использование UIApplicationDelegateAdaptor для получения обратных вызовов от userDidAcceptCloudKitShareWith не работает

Я пытаюсь получить уведомление, когда мне позвонят. Традиционно это называлось в, но поскольку я создаю iOS 14+, используя Appкак мой корневой объект. Я пока не смог найти никакой документации о том, как добавить в мой класс приложения, поэтому я использую UIApplicationDelegateAdaptor использовать App Delegate класс, но это не похоже userDidAcceptCloudKitShareWith когда-нибудь звонят?

      import SwiftUI
import CloudKit

// Our observable object class
class ShareDataStore: ObservableObject {
    
    static let shared = ShareDataStore() 
    @Published var didRecieveShare = false
    @Published var shareInfo = ""
}

@main
struct athlyticSocialTestAppApp: App {
    
    
    @StateObject var shareDataStore = ShareDataStore.shared 
    
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(shareDataStore)
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {
    
    let container = CKContainer(identifier: "iCloud.com.TestApp")
    
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("did finish launching called")
        return true
    }
    
    
    func application(_ application: UIApplication, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) {
        print("delegate callback called!! ")
        acceptShare(metadata: cloudKitShareMetadata) { result in
            switch result {
            case .success(let recordID):
                print("successful share!")
                ShareDataStore.shared.didRecieveShare = true
                ShareDataStore.shared.shareInfo = recordID.recordName
            case .failure(let error):
                print("failure in share = \(error)")
            }
        }    }
    
    func acceptShare(metadata: CKShare.Metadata,
                     completion: @escaping (Result<CKRecord.ID, Error>) -> Void) {
        
        // Create a reference to the share's container so the operation
        // executes in the correct context.
        let container = CKContainer(identifier: metadata.containerIdentifier)
        
        // Create the operation using the metadata the caller provides.
        let operation = CKAcceptSharesOperation(shareMetadatas: [metadata])
        
        var rootRecordID: CKRecord.ID!
        // If CloudKit accepts the share, cache the root record's ID.
        // The completion closure handles any errors.
        operation.perShareCompletionBlock = { metadata, share, error in
            if let _ = share, error == nil {
                rootRecordID = metadata.rootRecordID
            }
        }
        
        // If the operation fails, return the error to the caller.
        // Otherwise, return the record ID of the share's root record.
        operation.acceptSharesCompletionBlock = { error in
            if let error = error {
                completion(.failure(error))
            } else {
                completion(.success(rootRecordID))
            }
        }
        
        // Set an appropriate QoS and add the operation to the
        // container's queue to execute it.
        operation.qualityOfService = .utility
        container.add(operation)
    }
    
    
}

2 ответа

В Scene-based приложение обратный вызов отправляется делегату сцены, но в SwiftUI 2.0 App-based приложение, делегат сцены используется самим SwiftUI для предоставления scenePhase события, но не предоставляет собственный способ обработки обратного вызова темы.

Возможный подход к решению этой проблемы - найти окно и ввести собственную оболочку делегата сцены, которая будет обрабатывать userDidAcceptCloudKitShareWith и перенаправить других исходному делегату SwiftUI (чтобы стандартные события SwiftUI работали).

Вот несколько демонстрационных снимков, основанных на доступе к окну /questions/54454429/hosting-kontroller-pri-ispolzovanii-ios-14-main/54454435#54454435 (однако вы можете использовать любой другой предпочтительный способ получить окно)

      @main
struct athlyticSocialTestAppApp: App {
    @StateObject var shareDataStore = ShareDataStore.shared 
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    let sceneDelegate = MySceneDelegate()
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(shareDataStore)
              .withHostingWindow { window in
                 sceneDelegate.originalDelegate = window.windowScene.delegate
                 window.windowScene.delegate = sceneDelegate
              }
        }
    }
}

class MySceneDelegate : NSObject, UIWindowSceneDelegate {
   var originalDelegate: UIWindowSceneDelegate?

   func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShareMetadata) {

       // your code here
   }

   // forward all other UIWindowSceneDelegate/UISceneDelegate callbacks to original, like
   func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
       originalDelegate?.scene(scene, willConnectTo: session, options: connectionOptions)
   }
}

Check out this question that has a lot of useful things to check across several possible answers:

CloudKit CKShare userDidAcceptCloudKitShareWith Never Fires on Mac App

Be sure to add the CKSharingSupported key to your info.plist, and then try putting the userDidAcceptCloudKitShareWith in different places using the answers in the above link (where you put it will depend on what kind of app you're building).

Другие вопросы по тегам