UICloudSharingController在CloudKit应用中无法正常显示和工作问题求解
CloudKit共享功能适配问题:UICloudSharingController点击邮件/信息后界面异常
我一直在尝试让应用适配CloudKit实现记录共享功能,此前我已经开发过多个支持单用户多设备间Core Data记录同步的应用,但始终无法让UICloudSharingController正常实现记录共享功能。我可以正常弹出共享视图控制器,但点击邮件或信息选项后,仅显示键盘,无地址输入栏,也没有办法关闭该视图。这个问题困扰了我很久,所以我决定从基础的Apple官方"Sharing"示例应用开始调试,但该示例应用在我这边也无法正常运行。
相关代码实现
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)") } } }
CloudSharingView(UICloudSharingController封装)代码
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" } } }
异常现象
- 点击共享记录按钮后弹出的初始共享界面显示完全符合预期:

- 点击信息/邮件选项后弹出的界面仅显示键盘,无地址输入栏,也无法关闭视图:

运行环境
- Xcode 13.1
- iOS 15
- macOS Monterey
解决方案
这个问题是iOS 15低版本系统下,UICloudSharingController嵌套在SwiftUI的sheet中时,系统自带的分享跳转界面(邮件/信息视图)的层级渲染异常导致的,可通过以下两种方式修复:
方案1:改用UIKit的present方式弹出共享控制器
不要将UICloudSharingController封装为UIViewControllerRepresentable放在SwiftUI的sheet中,而是通过获取当前最顶层的UIViewController直接present:
// 新增工具方法获取当前顶层控制器 func getTopViewController() -> UIViewController? { guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let rootViewController = windowScene.windows.first?.rootViewController else { return nil } var topViewController = rootViewController while let presentedViewController = topViewController.presentedViewController { topViewController = presentedViewController } return topViewController } // 调整分享逻辑 private func shareContact(_ contact: Contact) async throws { isProcessingShare = true do { let (share, container) = try await vm.createShare(contact: contact) isProcessingShare = false // 直接弹出UICloudSharingController let sharingController = UICloudSharingController(share: share, container: container) sharingController.availablePermissions = [.allowReadWrite, .allowPrivate] sharingController.delegate = CloudSharingCoordinator.shared getTopViewController()?.present(sharingController, animated: true) } catch { debugPrint("Error sharing contact record: \(error)") } } // 单独抽离全局的协调器实现 class CloudSharingCoordinator: NSObject, UICloudSharingControllerDelegate { static let shared = CloudSharingCoordinator() func cloudSharingController(_ csc: UICloudSharingController, failedToSaveShareWithError error: Error) { debugPrint("Error saving share: \(error)") } func itemTitle(for csc: UICloudSharingController) -> String? { "Sharing Example" } func cloudSharingControllerDidStopSharing(_ csc: UICloudSharingController) { csc.dismiss(animated: true) } }
方案2:升级开发环境
这个系统层级的bug在Xcode 14+、iOS 15.4+版本中已经被修复,直接升级开发环境和应用的编译基线也可解决该问题。
内容的提问来源于stack exchange,提问作者JohnSF
相关产品推荐
相关产品推荐

