JohnSF
JohnSF

Reputation: 4330

SwiftUI CloudKit Sharing Permissions Not As Expected

I'm struggling mightily with permissions on a UICloudSharingController. I have a SwiftUI application using Core Data and CloudKit. The application works great - all data on all devices sync'd with the iCloud. I want to include the option for the user to share records with others. The sharing also works except for my efforts to control the permissions programmatically. Ideally, I would like all shares to be with access .allowPrivate only and then include a switch that sets permission to .allowReadOnly or .allowReadWrite.

When the share sheet is presented with no permission limitations in the code and the user taps Share Options, then chooses View Only, the share sheet correctly shows this choice and says "Invited people can view only".

enter image description here

enter image description here

enter image description here

However, once "Share with more people" is tapped the permission is reset to "Only invited people can edit".

enter image description here

If the user then taps that link and again taps "view only" the permission again changes to "Only invited people can view".

enter image description here

Tapping an invitee and sending the message results in the correct sharing where the user had Read Only access. This is obviously a very poor user experience.

Apple docs, in several places say access and permissions can be controlled with an array of desired permissions, but this is not working for me. Clearly, I'm misunderstanding something.

enter image description here

Here is my controller:

struct CloudSharingView: UIViewControllerRepresentable {

    //a switch sets this property
    @AppStorage("shareReadOnly") var shareReadOnly: Bool = true

    let share: CKShare
    let container: CKContainer
    //this is my Core Data Entity
    let recipe: Recipe

    func makeCoordinator() -> CloudSharingCoordinator {
        CloudSharingCoordinator(recipe: recipe)
    }

    func makeUIViewController(context: Context) -> UICloudSharingController {
        share[CKShare.SystemFieldKey.title] = recipe.rName
    
        let controller = UICloudSharingController(share: share, container: container)

        //this does not help
        //controller.availablePermissions = [.allowPrivate, .allowReadOnly]
        
        //this is what I want, but it does not work either
        /*
        if shareReadOnly {
            controller.availablePermissions = [.allowPrivate, .allowReadOnly]
        } else {
            controller.availablePermissions = [.allowPrivate, .allowReadWrite]
        }
        */

        controller.modalPresentationStyle = .formSheet
        controller.delegate = context.coordinator

        return controller
    }//make

    func updateUIViewController(_ uiViewController: UICloudSharingController, context: Context) {
        print("in update shareReadOnly is \(shareReadOnly.description)")
    }//update
}

final class CloudSharingCoordinator: NSObject, UICloudSharingControllerDelegate {
    let stack = CoreDataStack.shared
    let recipe: Recipe
    init(recipe: Recipe) {
        self.recipe = recipe
    }

    func itemTitle(for csc: UICloudSharingController) -> String? {
        recipe.rName
    }

    func cloudSharingController(_ csc: UICloudSharingController, failedToSaveShareWithError error: Error) {
        print("Failed to save share: \(error)")
    }

    func cloudSharingControllerDidSaveShare(_ csc: UICloudSharingController) {
        print("Saved the share")
    }

    func cloudSharingControllerDidStopSharing(_ csc: UICloudSharingController) {
        if !stack.isOwner(object: recipe) {
            stack.delete(recipe)
        }
    }
}//coordinator

Any guidance would be appreciated. Xcode 14.2 iOS 16.2

Upvotes: 2

Views: 446

Answers (1)

malhal
malhal

Reputation: 30746

The UIViewControllerRepresentable is not implemented correctly. However, there is actually already ShareLink in SwiftUI that provides this feature. See the docs for sample code.

Upvotes: 0

Related Questions