ios - UICloudSharingController 无法显示/无法与 CloudKit 应用程序一起使用

标签 ios swiftui cloudkit uiviewcontrollerrepresentable cloudkit-sharing

我一直在努力寻找一款能够与 CloudKit 一起使用并进行记录共享的应用程序。我有 创建了多个应用程序,可以为一名用户在设备之间同步核心数据记录。我没有 能够让 UICloudSharingController 用于共享记录。我可以显示 共享 View Controller ,但点击邮件或消息会显示键盘,但不会 地址字段,无法消除该 View 。我对此感到非常沮丧,以至于我 决定尝试Apple“共享”示例应用程序从基础开始。但是,那 示例应用程序也不适合我。

以下是示例应用程序的链接: https://github.com/apple/cloudkit-sample-sharing/tree/swift-concurrency

下面的代码几乎直接来自示例应用程序。

这是 ContentView 文件:

import SwiftUI
import CloudKit

struct ContentView: View {

    @EnvironmentObject private var vm: ViewModel

    @State private var isAddingContact = false
    @State private var isSharing = false
    @State private var isProcessingShare = false

    @State private var showShareView = false
    @State private var showIntermediateView = false

    @State private var activeShare: CKShare?
    @State private var activeContainer: CKContainer?

    var body: some View {
        NavigationView {
            contentView
                .navigationTitle("Contacts")
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button { Task.init { try await vm.refresh() } } label: { Image(systemName: "arrow.clockwise") }
                    }
                    ToolbarItem(placement: .navigationBarLeading) {
                        progressView
                    }
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: { isAddingContact = true }) { Image(systemName: "plus") }
                    }
                }
        }
        .onAppear {
            Task.init {
                try await vm.initialize()
                try await vm.refresh()
            }
        }
        .sheet(isPresented: $isAddingContact, content: {
            AddContactView(onAdd: addContact, onCancel: { isAddingContact = false })
        })
    }

    /// This progress view will display when either the ViewModel is loading, or a share is processing.
    var progressView: some View {
        let showProgress: Bool = {
            if case .loading = vm.state {
                return true
            } else if isProcessingShare {
                return true
            }
            return false
        }()
        return Group {
            if showProgress {
                ProgressView()
            }
        }
    }

    /// Dynamic view built from ViewModel state.
    private var contentView: some View {
        Group {
            switch vm.state {
            case let .loaded(privateContacts, sharedContacts):
                List {
                    Section(header: Text("Private")) {
                        ForEach(privateContacts) { contactRowView(for: $0) }
                    }
                    Section(header: Text("Shared")) {
                        ForEach(sharedContacts) { contactRowView(for: $0, shareable: false) }
                    }
                }.listStyle(GroupedListStyle())
            
            case .error(let error):
                VStack {
                    Text("An error occurred: \(error.localizedDescription)").padding()
                    Spacer()
                }
            
            case .loading:
                VStack { EmptyView() }
            }
        }
    }

    /// Builds a `CloudSharingView` with state after processing a share.
    private func shareView() -> CloudSharingView? {

        guard let share = activeShare, let container = activeContainer else {
            return nil
        }
    
        return CloudSharingView(container: container, share: share)
    }

    /// Builds a Contact row view for display contact information in a List.
    private func contactRowView(for contact: Contact, shareable: Bool = true) -> some View {
        HStack {
            VStack(alignment: .leading) {
                Text(contact.name)
                Text(contact.phoneNumber)
                    .textContentType(.telephoneNumber)
                    .font(.footnote)
            }
        
            if shareable {
            
                Spacer()

                Button(action: { Task.init { try? await shareContact(contact) }
                }, label: { Image(systemName: "square.and.arrow.up") }).buttonStyle(BorderlessButtonStyle())
                    .sheet(isPresented: $isSharing, content: { shareView() })
            
            }//if sharable
        }//h
    }//contact row view

    // MARK: - Actions

    private func addContact(name: String, phoneNumber: String) async throws {
        try await vm.addContact(name: name, phoneNumber: phoneNumber)
        try await vm.refresh()
        isAddingContact = false
    }

    private func shareContact(_ contact: Contact) async throws {
        isProcessingShare = true
    
        do {
            let (share, container) = try await vm.createShare(contact: contact)
            isProcessingShare = false
            activeShare = share
            activeContainer = container
            isSharing = true
        } catch {
            debugPrint("Error sharing contact record: \(error)")
        }
    }
}

以及共享 View 的 UIViewControllerRepresentable 文件:

import Foundation
import SwiftUI
import UIKit
import CloudKit

/// This struct wraps a `UIImagePickerController` for use in SwiftUI.
struct CloudSharingView: UIViewControllerRepresentable {

    @Environment(\.presentationMode) var presentationMode
    let container: CKContainer
    let share: CKShare

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}

    func makeUIViewController(context: Context) -> some UIViewController {

        let sharingController = UICloudSharingController(share: share, container: container)
        sharingController.availablePermissions = [.allowReadWrite, .allowPrivate]
        sharingController.delegate = context.coordinator
    
        return sharingController
    }

    func makeCoordinator() -> CloudSharingView.Coordinator {
        Coordinator()
    }

    final class Coordinator: NSObject, UICloudSharingControllerDelegate {
    
        func cloudSharingController(_ csc: UICloudSharingController, failedToSaveShareWithError error: Error) {
            debugPrint("Error saving share: \(error)")
        }

        func itemTitle(for csc: UICloudSharingController) -> String? {
            "Sharing Example"
        }
    }
}

这是点击共享记录时呈现的屏幕。这一切看起来都符合预期:

enter image description here

这是点击“消息”后的屏幕(与“邮件”的结果相同)。我没有看到任何影响第二个屏幕呈现的方法 - 似乎可表示的 View Controller 不适用于此版本的 Xcode:

enter image description here

任何指导将不胜感激。 Xcode 13.1、iOS 15,我使用的是 macOS Monterrey。

最佳答案

我遇到了同样的问题,并通过更改 CloudSharingView.swift 中的 makeUIViewController() 来修复它:

    func makeUIViewController(context: Context) -> some UIViewController {
        share[CKShare.SystemFieldKey.title] = "Boom"
        let sharingController = UICloudSharingController(share: share, container: container)
        sharingController.availablePermissions = [.allowReadWrite, .allowPrivate]
        sharingController.delegate = context.coordinator
-->>>        sharingController.modalPresentationStyle = .none
        return sharingController
    }

似乎有些有值(value),有些则不然。不知道为什么。

关于ios - UICloudSharingController 无法显示/无法与 CloudKit 应用程序一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69868944/

相关文章:

ios - 从 UITableView 行选择导航到 UIWebView

swift - 如何在 Swift 中访问 KMMShared MutableStateFlow 对象

ios - CloudKit 推送通知 didReceiveRemoteNotification 从未调用过

ios - CloudKit 和 iCloud 帐户

ios - 不使用私有(private) API 获取电话 (GSM) 信号强度

ios - 向应用程序添加广告 - 了解过去的客户

core-data - fetchUserRecordID Cloudkit 错误 : Couldn't get container configuration

ios - 更新 CloudKit 记录,得到 "UITextField.text must be used from main thread only"

ios - 如何计算 iOS 中多边形的物理面积?

ios - 无法使用 SwiftUI 实现暗模式