Starting with Cloudkit
Total Page:16
File Type:pdf, Size:1020Kb
Starting with CloudKit Jeroen Zonneveld Who am I? ! Jeroen Zonneveld " The Netherlands # iOS & tvOS Developer $ Triple, wearetriple.com Table of Contents ‣ What is CloudKit? ‣ Creating a database ‣ Connect and query to the database ‣ Store data in the database ‣ References ‣ GDPR ‣ Going to production What is CloudKit? Who already heard of CloudKit? Who have used CloudKit before in a project? What is CloudKit? "CloudKit is the framework that powers iCloud on all Apple platforms. It's feature-rich API to store and query your own custom data in iCloud." Examples What is CloudKit? Saving notes using the notes app Saving a backup of your WhatsApp history. Check apps on your iOS device using CloudKit: Settings > Apple ID > iCloud What is CloudKit? watchOS tvOS iOS macOS What is CloudKit? Apple device CloudKit iCloud database What is CloudKit? In development, when you run your app through Xcode on a simulator or a device, you need to enter iCloud credentials to read records in the Public database Shared database publicPrivate database. database In production, the default permissions allow non- authenticated users to read records in the public database but do not Focus op Public & Private allow them to write records. What is CloudKit? What is CloudKit? Pros Cons ‣ Easy to use in development ‣ Only available for Apple devices ‣ Syncing data between Apple devices automatically ‣ No need to worry about a secure backend ‣ Sharing between Apple devices ‣ Data in a private database is not visible for the developer ‣ No need to login for the user or give permission to allow you to use CloudKit Creating a database Capabilities aanzetten iCloud + vinkje cloudkit niet vergeten. Now you can click on “CloudKit dashboard”. Creating a database Indien de app daar niet staat, keer de app builden. Creating a database icloud.developer.apple.com Creating a database Creating a database iCloud dashboard Beheren van databases Manage database Logs bekijken om fouten in te zien ‣ van queries Grafieken inzien van request ‣ Check logs snelheden. Inzien gebruik gemaakt wordt van ‣ View telemetry een public database API’s beheren, indien je gebruik wil ‣ Check public database usage maken van de CloudKit JS api. ‣ Manage API access Klik op aapje record types om een tabel aan te maken. Voeg vervolgens de velden toe, voorzien Creating a database van een naam en een type en sla het record op. Zo gemakkelijk is het om een tabel te maken! Vergeet daarna niet om ‘recordName’ (default property) als index actief te zetten in het indexes tabje. Private of public maakt niet uit, dat bepaal je later in code. Creating a database Field types you can add ‣ String, Int, Double ‣ Date / Time ‣ Location ‣ Asset ‣ Reference Creating a database Connect and query to the database Connect and query to the database Important Objects ‣ CKContainer id firstname lastname ‣ CKDatabase ‣ CKRecord 1 Jeroen Zonneveld CKRecordZone ‣ Database ‣ CKRecordIdentifier Connect and query to the database struct ACTalk { var title: String? var speaker: String? var date: Date? var location: String? } Connect and query to the database Get a reference to the database let privateDatabase = CKContainer.default().privateCloudDatabase let publicDatabase = CKContainer.default().publicCloudDatabase Public database Private database Connect and query to the database Query data from a public database let publicDatabase = CKContainer.default().publicCloudDatabase let predicate = NSPredicate(format: "TRUEPREDICATE") let query = CKQuery(recordType: "talks", predicate: predicate) publicDatabase.perform(query, inZoneWith: nil) { (results, error) in } Testen in simulator? Zorg dat iCloud account is ingesteld! Anders krijg je [CKRecord] een error Connect and query to the database Je ontvangt data op een aparte Query data from a public database thread. Bij UI aanpassingen altijd naar de mainthread gaan! publicDatabase.perform(query, inZoneWith: nil) { [weak self] (results, error) in guard error == nil else { // show error to the user return } results?.forEach({ (talk) in let title = talk.object(forKey: "title") as? String let speaker = talk.object(forKey: "speaker") as? String let date = talk.object(forKey: "date") as? Date let location = talk.object(forKey: "location") as? String let talk = ACTalk(title: title, speaker: speaker, date: date, location: location) self?.talks.append(talk) }) } Connect and query to the database Connect and query to the database Query data from a public database let publicDatabase = CKContainer.default().publicCloudDatabase let predicate = NSPredicate(format: "TRUEPREDICATE") let query = CKQuery(recordType: "talks", predicate: predicate) query.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)] publicDatabase.perform(query, inZoneWith: nil) { (results, error) in } Connect and query to the database Query data from a public database Connect and query to the database Connect and query to the database struct ACTalk { var title: String? var speaker: String? var date: Date? var location: String? var speakerImage: UIImage? } Connect and query to the database Query data from a public database publicDatabase.perform(query, inZoneWith: nil) { [weak self] (results, error) in results?.forEach({ (talk) in var speakerImage: UIImage? if let speakerAsset = talk.object(forKey: "speakerImage") as? CKAsset, let data = try? Data(contentsOf: speakerAsset.fileURL) { speakerImage = UIImage(data: data) } }) } Connect and query to the database Query data from a public database publicDatabase.perform(query, inZoneWith: nil) { [weak self] (results, error) in results?.forEach({ (talk) in let speakerAsset = talk.object(forKey: "speakerImage") as? CKAsset let speakerImage = speakerAsset?.image }) } extension CKAsset { var image: UIImage? { guard let data = try? Data(contentsOf: fileURL) else { return nil } guard let image = UIImage(data: data) else { return nil } return image } } Connect and query to the database Store data in the database Store data in the database Store data in the database Store a talk in the database func addTalkToDatabase(title: NSString, speaker: NSString, location: NSString, date: NSDate, image: UIImage) { let talkRecord = CKRecord(recordType: "talks") talkRecord["title"] = title talkRecord["speaker"] = speaker talkRecord["location"] = location talkRecord["date"] = date let asset = try? CKAsset(image: image) talkRecord["speakerImage"] = asset let publicDatabase = CKContainer.default().publicCloudDatabase publicDatabase.save(talkRecord) { record, error in // check error // do complete action } } References References References References CKReference Talk title speaker Favorite talk Talk title speaker References struct ACTalk { var record: CKRecord? } References Store a talk reference in the favorites database guard let record = talk.record else { return } let privateDatabase = CKContainer.default().privateCloudDatabase let favoritesRecord = CKRecord(recordType: "favorites") let reference = CKReference(record: record, action: CKReferenceAction.deleteSelf) favoritesRecord["talk"] = reference privateDatabase.save(favoritesRecord) { [weak self] (record, error) in guard error == nil, let record = record else { return } self?.favorites?.append(record) } GDPR General Data Protection Regulation GDPR ‣ Since May 25, 2018, only if you target people in the EU ‣ Create a privacy statement which data you are collecting ‣ Add an option to requests to Delete Data GDPR Delete all data from the user CKContainer.default().privateCloudDatabase.fetchAllRecordZones { zones, error in guard let zones = zones, error == nil else { print("Error fetching zones.") return } let zoneIDs = zones.map { $0.zoneID } let deletionOperation = CKModifyRecordZonesOperation(recordZonesToSave: nil, recordZoneIDsToDelete: zoneIDs) deletionOperation.modifyRecordZonesCompletionBlock = { _, _, error in guard error == nil else { print("Error deleting records.") return } print("Records successfully deleted in this zone.") } CKContainer.default().privateCloudDatabase.add(deletionOperation) } Going to production Going to production Going to production Going to production Production talks to production CloudKit, Only for tvOS you are able to select that the build should be connect to development Summary Summary ‣ Create a database online using the developer portal ‣ It’s easy to query or insert data using the CloudKit framework ‣ Use references to create links between tables ‣ Add a ‘remove my data’ function to your privacy statement to confirm to GDPR rules More about CloudKit… Sharing API https://developer.apple.com/documentation/uikit/uicloudsharingcontroller CloudKit JS https://developer.apple.com/documentation/cloudkitjs Apple sessions Introducing CloudKit - Session 208, WWDC 2014 Advanced CloudKit - Session 231, WWDC 2014 CloudKit JS and Web Services - Session 710, WWDC 2015 CloudKit Tips and Tricks - Session 715, WWDC 2015 What's New with CloudKit - Session 704, WWDC 2015 What's New with CloudKit - Session 226, WWDC 2016 CloudKit Best Practices - Session 231, WWDC 2016 Build Better Apps with CloudKit Dashboard - Session 226, WWDC 2017 developer.apple.com/icloud/cloudkit Examples on GitHub ‣ Altconf schedule example ‣ GDPR delete all data playground https://github.com/jeroenzonneveld/cloudkit-examples Thank you! Jeroen Zonneveld.