iosswiftcloudkitcloudkit-sharing

How to fetch the CKShare object of an already existing share (to get share URL)


I am trying to allow users of my app to be able to retrieve the iCloud sharing link to a record that they have ALREADY shared. I can get the URL when creating the share by using the let share = CKShare(rootRecord: CKRecord) followed by Apple's UISharingController. However, every time I use this method, the old link becomes invalid and kicks others out of the share they have already joined. How can I allow the users (the record owners) to fetch a shareable URL for the records CKShare object at any time?

//Initially shares the record
let share = CKShare(rootRecord: newRecord)
share[CKShare.SystemFieldKey.title] = "Group" as CKRecordValue?        
let modifyRecordsOperation = CKModifyRecordsOperation( recordsToSave: [newRecord, share], recordIDsToDelete: nil)

//Activates the UISharingController (code not shown)

Solution

  • Assuming the record has already been shared, you can get the URL to invite additional participants with the following:

    if let shareReference = record.share {
        database.fetch(withRecordID: shareReference.recordID) { (share, error) in
            let shareURL = (share as? CKShare)?.url
        }
    }
    

    If you wanted to show the UICloudSharingController again for an existing share (without it generating a new URL), you could do:

    let sharingController = UICloudSharingController { (_, prepareCompletionHandler) in
    
        func createNewShare() {
            let operationQueue = OperationQueue()
            operationQueue.maxConcurrentOperationCount = 1
    
            let share = CKShare(rootRecord: record)
            share[CKShare.SystemFieldKey.title] = "Title" as CKRecordValue
            share.publicPermission = .readWrite
    
            let modifyRecordsOp = CKModifyRecordsOperation(recordsToSave: [share, record], recordIDsToDelete: nil)
            modifyRecordsOp.modifyRecordsCompletionBlock = { records, recordIDs, error in
                prepareCompletionHandler(share, self, error)
            }
            modifyRecordsOp.database = database
            operationQueue.addOperation(modifyRecordsOp)
        }
    
        if let shareReference = record.share {
            database.fetch(withRecordID: shareReference.recordID) { (share, error) in
                guard let share = share as? CKShare else {
                    createNewShare()
                    return
                }
                prepareCompletionHandler(share, self, nil)
            }
        } else {
            createNewShare()
        }
    }