我正在尝试在userDidAcceptCloudKitShareWith被调用时得到通知。传统上,这是在App Delegate中调用的,但因为我使用App作为根对象来构建一个iOS 14+。到目前为止,我还找不到任何关于如何将userDidAcceptCloudKitShareWith添加到我的应用程序类中的文档,所以我使用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 SocialTestAppApp: 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)
}
}根据Asperi的答案更新:
import SwiftUI
import CloudKit
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
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 {
let container = CKContainer(identifier: "iCloud.com...")
var originalDelegate: UIWindowSceneDelegate?
var window: UIWindow?
func sceneWillEnterForeground(_ scene: UIScene) {
print("scene is active")
}
func sceneWillResignActive(_ scene: UIScene) {
print("scene will resign active")
}
// 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)
}
func windowScene(_ windowScene: UIWindowScene, 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)")
}
}
}
}
extension View {
func withHostingWindow(_ callback: @escaping (UIWindow?) -> Void) -> some View {
self.background(HostingWindowFinder(callback: callback))
}
}
struct HostingWindowFinder: UIViewRepresentable {
var callback: (UIWindow?) -> ()
func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}发布于 2021-05-23 14:05:16
在Scene-based应用程序中,userDidAcceptCloudKitShareWith回调被发送到场景代理,但在SwiftUI 2.0 App-based应用程序中,场景代理由SwiftUI本身用于提供scenePhase事件,但不提供处理主题回调的本机方法。
解决此问题的可能方法是找到一个窗口并注入自己的场景代理包装,该包装将处理userDidAcceptCloudKitShareWith并将其他代理转发给原始SwiftUI委托(以保持标准SwiftUI事件工作)。
下面是几个基于https://stackoverflow.com/a/63276688/12299030窗口访问的演示快照(不过,您也可以使用任何其他更好的方法来获取窗口)
@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: UISceneDelegate?
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)
}
}发布于 2021-05-19 08:42:36
看看这个问题,它有很多有用的东西,可以通过几个可能的答案来检查:
CloudKit CKShare userDidAcceptCloudKitShareWith Never Fires on Mac App
确保将CKSharingSupported密钥添加到您的info.plist中,然后尝试使用上面链接中的答案将userDidAcceptCloudKitShareWith放在不同的位置(放置位置将取决于您正在构建的应用程序的类型)。
https://stackoverflow.com/questions/67541441
复制相似问题