Использование 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).