-
Re: Is CloudKit sharing really in iOS 10?
Mr. Brightside Sep 10, 2016 4:52 PM (in response to lenk)Yes, sharing is available in iOS 10. And yes, the documentation is scarce at the moment. Use WWDC presentation and information available in CloudKit header files.
-
Re: Is CloudKit sharing really in iOS 10?
MendelK Sep 18, 2016 12:03 PM (in response to Mr. Brightside)...and sharing seems to be working great in our test enviroment.
Just look out for a bug on the Mac in -[NSItemProvider registerCloudKitShareWithPreparationHandler...]. It is not working when a _MASReceipt is present.
-
Re: Is CloudKit sharing really in iOS 10?
pdm Sep 19, 2016 6:03 AM (in response to MendelK)Could you file a bug report with a small sample project for that bug on the Mac? If you could post the bug number here I'd like to follow up on that.
-
Re: Is CloudKit sharing really in iOS 10?
Mr. Brightside Sep 21, 2016 1:33 AM (in response to pdm)I can confirm that CloudKit sharing does not work for 3rd party apps downloaded from the Mac App Store. It is not possible to add participants to a share. There is no such problem with a Developer ID signed app. Bug report 28377984.
-
Re: Is CloudKit sharing really in iOS 10?
MendelK Sep 21, 2016 11:37 AM (in response to pdm)Here's my bug reporter number: 28115542
Funny thing is that you can even break the Sierra Notes.app: Simply but a _MASReceipt in there and KABOOM, sharing UI is gone for good :-)
-
Re: Is CloudKit sharing really in iOS 10?
pdm Sep 21, 2016 1:56 PM (in response to MendelK)This issue with the Mac App Store signed apps should be addressed in the macOS Sierra beta that was posted today. It would be great to hear from folks that can install it.
-
Re: Is CloudKit sharing really in iOS 10?
MendelK Sep 21, 2016 2:06 PM (in response to pdm)Thanks for getting back to us. I will try it out first thing in the morning from the office on one of our testing Macs and report back.
In case it is fixed, any hint if macOS Sierra 10.12.1 will be available shortly for the general public or if it will take several months?
-
Re: Is CloudKit sharing really in iOS 10?
Mr. Brightside Sep 21, 2016 2:30 PM (in response to pdm)The issue is still there in 10.12.1 Beta 1, I just checked.
-
Re: Is CloudKit sharing really in iOS 10?
pdm Sep 22, 2016 12:28 AM (in response to Mr. Brightside)Indeed, I apologize. The fix to this issue missed the cutoff for seed 1. It should be in the next seed that goes out. Sorry for the confusion.
-
Re: Is CloudKit sharing really in iOS 10?
MendelK Sep 22, 2016 1:23 AM (in response to pdm)Ok, we'll wait for the next seed
-
Re: Is CloudKit sharing really in iOS 10?
MendelK Sep 27, 2016 10:51 AM (in response to pdm)_MASReceipt Issue has been fixed in 10.12.1b2! Thank you very much.
Sadly, a much bigger issue popped up using CKShares: https://forums.developer.apple.com/thread/64194
You guys would be my heroes if you can fix this, too
-
-
-
-
-
-
-
-
Re: Is CloudKit sharing really in iOS 10?
-jon- Sep 19, 2016 6:22 PM (in response to lenk)Well sharing (or something having to do with it) is definitely in iOS 10 because it currently is breaking our ability to fetch any records from our (non-shared) public database's default container... see my post here https://forums.developer.apple.com/thread/62699
We are getting the error:
Error: <CKError 0x15e7c2b0: "Internal Error" (1/5001); "Couldn't get a PCS object to unwrap encrypted data for field encryptedPublicSharingKey: (null)">
Note that it is called the encryptedPublicSharingKey. Since we are not using sharing or anything related to it, then I guess our "sharing" key is (null). But why this would block our ability to even fetch a simple record from the default container of our public database... well that's beyond me.
-
Re: Is CloudKit sharing really in iOS 10?
Jonny Sep 20, 2016 11:57 PM (in response to lenk)Did you find a way to share?
I find myself stuck in the first step.
CloudKit says I cannot use default zone in the share database. OK, so I place my records into a custom zone instead. But now I get this error.
CKError(_nsError: <CKError 0x1700514f0: "Partial Failure" (2/1011); "Failed to modify some records"; uuid = C6B66342-B2C4-466C-904C-522EBD8D23E1; container ID = "iCloud.com.jonny.CloudShareTest"; partial errors: { Share-F578CD7D-A74D-4E48-8982-3003487E69FB:(MyUniqueRecordZoneName:__defaultOwner__) = <CKError 0x1740561d0: "Invalid Arguments" (12/2006); server message = "ShareDB can't be used to access local zone"> ... 1 "Batch Request Failed" CKError's omited ... }>)
I even don't know what is the "local zone". I have already save the zone to private database so it should be a "cloud zone" right?...
-
Re: Is CloudKit sharing really in iOS 10?
Jonny Sep 21, 2016 12:18 AM (in response to Jonny)OK, just figure out how to share a CKRecord.
It must be done on real device, simulator won't works.
@IBAction func shareButtonItemDidTap(_ sender: UIBarButtonItem) { let controller = UICloudSharingController { controller, preparationCompletionHandler in // this block called when user select a destiniation to share. either copy link, or share to Twitter, Facebook etc. print("prepare for sharing") let privateDatabase = CKContainer.default().privateCloudDatabase // create and save zone if needed let zoneID = CKRecordZoneID(zoneName: "MyUniqueRecordZoneName", ownerName: CKCurrentUserDefaultName) let zone = CKRecordZone(zoneID: zoneID) let modifyRecordZonesOperation = CKModifyRecordZonesOperation(recordZonesToSave: [zone], recordZoneIDsToDelete: nil) modifyRecordZonesOperation.timeoutIntervalForRequest = 10 modifyRecordZonesOperation.timeoutIntervalForResource = 10 modifyRecordZonesOperation.modifyRecordZonesCompletionBlock = { zone, _, error in if let error = error as? CKError { print("modifyRecordZonesOperation error:", error) preparationCompletionHandler(nil, nil, error) return } // create, save and share a record. as example, share a simple image record let recordID = CKRecordID(recordName: UUID().uuidString, zoneID: zoneID) let record = CKRecord(recordType: "Image", recordID: recordID) record["image"] = UIImagePNGRepresentation(#imageLiteral(resourceName: "sample image"))! as CKRecordValue // Documentation Note: When saving a newly created CKShare, you must save the share and its rootRecord in the same CKModifyRecordsOperation batch. let share = CKShare(rootRecord: record) share[CKShareTitleKey] = "My Amazing Image!!" as CKRecordValue let modifyRecordsOperation = CKModifyRecordsOperation(recordsToSave: [record, share], recordIDsToDelete: nil) modifyRecordsOperation.timeoutIntervalForRequest = 10 modifyRecordsOperation.timeoutIntervalForResource = 10 modifyRecordsOperation.modifyRecordsCompletionBlock = { records, recordIDs, error in if let error = error as? CKError { print("modifyRecordsOperation error:", error) } preparationCompletionHandler(share, CKContainer.default(), error) } privateDatabase.add(modifyRecordsOperation) } privateDatabase.add(modifyRecordZonesOperation) } controller.availablePermissions = [.allowPublic, .allowReadOnly] controller.popoverPresentationController?.barButtonItem = sender present(controller, animated: true) }
-
Re: Is CloudKit sharing really in iOS 10?
morgen Sep 21, 2016 4:10 PM (in response to Jonny)Thanks for the example of how to share a record. What steps need to be taken on the particpant (sharee) side?
I presume you have to implement...
func application(_ application: UIApplication, userDidAcceptCloudKitShareWith userAcceptedCloudKitShareWith: CKShareMetadata)
Which gives you a CKShareMetadata object with references to a CKShare, recordID, etc. Do you then need to use a CKAcceptSharesOperation, or has that been taken care of by the framework when the participant user accepted?
-
Re: Is CloudKit sharing really in iOS 10?
Jonny Nov 4, 2016 9:44 PM (in response to morgen)Here it is.
Hope you guys can post some sample code, fill API documentations and update CloudKit instructions.
func application(_ application: UIApplication, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShareMetadata) { print(#function) let time = CFAbsoluteTimeGetCurrent() let acceptSharesOperation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata]) acceptSharesOperation.perShareCompletionBlock = { metadata, share, error in if let error = error { print("perShareCompletionBlock error", error) return } print(#function, "\(CFAbsoluteTimeGetCurrent() - time)s") self.handleShareMetadata(cloudKitShareMetadata) } acceptSharesOperation.acceptSharesCompletionBlock = { error in if let error = error { print("acceptSharesCompletionBlock error", error) } } print("cloudKitShareMetadata.containerIdentifier", cloudKitShareMetadata.containerIdentifier) CKContainer(identifier: cloudKitShareMetadata.containerIdentifier).add(acceptSharesOperation) } func handleShareMetadata(_ metadata: CKShareMetadata) { let time = CFAbsoluteTimeGetCurrent() let operation = CKFetchRecordsOperation(recordIDs: [metadata.rootRecordID]) operation.perRecordProgressBlock = { _, progress in print("download progress:", progress) } operation.perRecordCompletionBlock = { record, _, error in print(#function, "\(CFAbsoluteTimeGetCurrent() - time)s") if let error = error { print("perRecordCompletionBlock error:", error) } if let record = record, let imageData = record["image"] as? Data, let image = UIImage(data: imageData) { DispatchQueue.main.async { print("Image ckRecord download success!") if let imageView = (self.window?.rootViewController as? UINavigationController)?.viewControllers.first?.view as? UIImageView { imageView.image = image } } } } operation.fetchRecordsCompletionBlock = { _, error in if let error = error as? CKError { print("CKFetchRecordsOperation fetchRecordsCompletionBlock error:", error) } } CKContainer.default().sharedCloudDatabase.add(operation) }
-
Re: Is CloudKit sharing really in iOS 10?
stormychel Oct 19, 2016 8:27 PM (in response to Jonny)Hi,
thanks for sharing your code.
I tried this in a testing branch of my app on a real device, but when clicking the resulting link, I get taken to the iCloud website which tells me that this item is unavailable because the user stopped sharing it or that I don't have permission to open it.
Is this normal? Or am I doing something wrong. I copied your code (by typing, to get a better understanding), without changing anything.
The only possible reason which comes up to me is that I'm trying to open the link with the iCloud account that created it... Should I have 2 accounts to test?
Any feedback is highly appreciated!
-
Re: Is CloudKit sharing really in iOS 10?
Jonny Oct 21, 2016 10:32 AM (in response to stormychel)Yes, you need to use 2 devices, 2 Apple IDs.
-
Re: Is CloudKit sharing really in iOS 10?
stormychel Oct 21, 2016 4:24 PM (in response to Jonny)Hi,
thanks for your feedback. I sourced a spare iPhone and made a second AppleID, however I still get the same error... Seems like I am missing something, will double-check the code for errors...
I also followed along with the example from WWDC2016, but even Apple's example code does not seem to work properly, especially the part where they set ip the controller with (share: share), this is refused by the compiler somehow.
Guess we really need some proper documentation about this...
-
Re: Is CloudKit sharing really in iOS 10?
roypmckenzie Jan 6, 2017 9:59 PM (in response to stormychel)MY guess is that you are setting sharing permissions on the `UICloudSharingController` but perhaps not on the actual `CKShare` too. I made that mistake and when I added permissions onto the `CKShare` object it worked.
let share = CKShare(rootRecord: record) share.publicPermission = .readWrite
-
-
-
-
Re: Is CloudKit sharing really in iOS 10?
kauai Nov 4, 2016 9:31 PM (in response to Jonny)Janny,
Thanks for the code snippets. You demonstrate how to share a record using one AppleID, then receiving the share on another device with second AppleID. Though, once the data is received, are we required to save the metadata.rootRecordID in persistent storage in the event the app is exitted/killed. I am unable to perform a CKQuery on the shared database after receiving the shared record ID the first time. So all works well for your code (again thanks), though not being able to query the shared database later is a bit limiting. Means I need to store the recordID's in persistent storage or other. I feel like I am missing something important here. Though, Apple would serve developers well by putting together a functional demo app for the share process going forward.
Thanks for any further guidance.
-
Re: Is CloudKit sharing really in iOS 10?
Jonny Nov 4, 2016 9:53 PM (in response to kauai)I don't have further test yet.
But I think you may use CKDatabaseSubscription to subscribe all changes that happen in the share database, then, when you receive CloudKit's remote notification, use CKFetchDatabaseChangesOperation and CKFetchRecordZonesOperation to perform change fetch.
Btw I always find CKOperation is more reliable than CKQuery, so you should try it.
-
Re: Is CloudKit sharing really in iOS 10?
kauai Nov 7, 2016 8:49 PM (in response to Jonny)Jonny,
I attempted to create a subscription in the sharedCloudDatabase and received CKError:
<CKError 0x1742514c0: "Invalid Arguments" (12/2006); server message = "Subscription type not supported in SharedDB">
Appears this is unaccepted practice.
-
Re: Is CloudKit sharing really in iOS 10?
kauai Nov 7, 2016 9:41 PM (in response to kauai)Jonny,
Also attempted to place a Subscription on Private DB cloudkit.share as follows:
let shareSubscription = CKQuerySubscription(recordType: "cloudkit.share",
predicate: predicate,
options: [.firesOnRecordCreation, .firesOnRecordUpdate, .firesOnRecordDeletion])
Though this doesn't rigger upon any changes and/or deletion of the share. Handled differently then other Private DB subscriptions it appears.
-
-
-
-
-
-
Re: Is CloudKit sharing really in iOS 10?
okayjeff Oct 2, 2016 4:03 AM (in response to Jonny)Super helpful! Thank you, Jonny.
One thing that trips me up is the insistence that we share root records and shares simultaneously. What if I already have a root record created and synched to iCloud but I come along later and want to share it? How does the implementation differ from what you have here?
-
Re: Is CloudKit sharing really in iOS 10?
MendelK Oct 2, 2016 4:09 AM (in response to okayjeff)If you already have a root record on CloudKit, do the following: First, query your root record. Afterwards, create a CKShare and save it together with the freshly queried root record using a CKModifyOperation.
I think the misunderstanding is that the root record and the share have to be saved in one modify operation. While this is true, it does not mean that the root record has to be created in that modify operation, just saved.
Please be aware that there are limits when working with CKShare, have a look here: https://forums.developer.apple.com/thread/64533
-
Re: Is CloudKit sharing really in iOS 10?
okayjeff Oct 2, 2016 8:36 AM (in response to MendelK)Immensely helpful. Thank you!
For anyone who stumbles upon this, here is how I went about doing it:
@IBAction func shareButtonTapped(_ sender: UIButton) { let shareController = UICloudSharingController { shareController, preparationCompletionHandler in let zoneID = CKRecordZoneID(zoneName: "MyCustomZoneName", ownerName: CKCurrentUserDefaultName) let zone = CKRecordZone(zoneID: zoneID) let modZonesOp = CKModifyRecordZonesOperation(recordZonesToSave: [zone], recordZoneIDsToDelete: nil) modZonesOp.timeoutIntervalForRequest = 10 modZonesOp.timeoutIntervalForResource = 10 modZonesOp.modifyRecordZonesCompletionBlock = { zone, _, error in if let error = error as? CKError { print("modZonesOp error:", error) preparationCompletionHandler(nil, nil, error) return } // Get the record ID; I include it in the model and capture upon initial save to iCloud let recordID = self.list?.recordID self.privateDB.fetch(withRecordID: recordID!, completionHandler: { (record, error) in if error != nil { print("Error fetching record:", error) } else { print("Found record, creating share...") let share = CKShare(rootRecord: record!) let listType = self.list?.type.rawValue share[CKShareTitleKey] = "\(listType!) List" as CKRecordValue let modRecordsOp = CKModifyRecordsOperation(recordsToSave: [record!, share], recordIDsToDelete: nil) modRecordsOp.timeoutIntervalForRequest = 10 modRecordsOp.timeoutIntervalForResource = 10 modRecordsOp.modifyRecordsCompletionBlock = { records, recordIDs, error in if error != nil { print("modifyRecordsOp error:", error) } else { print("Successfully modified records") } preparationCompletionHandler(share, CKContainer.default(), error) } self.privateDB.add(modRecordsOp) } }) } self.privateDB.add(modZonesOp) } shareController.availablePermissions = [.allowPrivate, .allowReadWrite] shareController.popoverPresentationController?.sourceView = shareButton present(shareController, animated: true) }
-
-
-
-
-
Re: Is CloudKit sharing really in iOS 10?
lenk Jan 19, 2017 11:32 AM (in response to lenk)Very strange: four months later and there still doesn't appear to be documentation or sample code from Apple. I'd really like to continue my work using these APIs but I'm very concerned that they've been orphaned. Or maybe they don't really work? Or don't scale? Can anyone from Apple shed some light on this? pdm? morgen?