What’s New in CloudKit€¦ · CloudKit JS and Web Services WWDC 2015 What's New in CloudKit WWDC...

Post on 14-Jul-2020

17 views 0 download

Transcript of What’s New in CloudKit€¦ · CloudKit JS and Web Services WWDC 2015 What's New in CloudKit WWDC...

© 2016 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

There's a lot we want to share

App Frameworks #WWDC16

Session 226

What’s New in CloudKit

Paul Seligman CloudKit EngineerJacob Farkas CloudKit EngineerVanessa Hong CloudKit Engineer

What are we talking about?Table of Contents

What are we talking about?Table of Contents

CloudKit Overview

What are we talking about?Table of Contents

CloudKit OverviewTelemetry

What are we talking about?Table of Contents

CloudKit OverviewTelemetryAPI Improvements

What are we talking about?Table of Contents

CloudKit OverviewTelemetryAPI ImprovementsSharing

What is CloudKit?CloudKit Overview

Data everywhere!CloudKit Overview

Data everywhere!CloudKit Overview

iCloud Database

Data everywhere!CloudKit Overview

iCloud DatabaseExtensive use inside Apple

Data everywhere!CloudKit Overview

iCloud DatabaseExtensive use inside AppleUbiquitous

Prior talksCloudKit Overview

Introducing CloudKit WWDC 2014

Introducing CloudKit WWDC 2014

Advanced CloudKit WWDC 2014

CloudKit JS and Web Services WWDC 2015

What's New in CloudKit WWDC 2015

CloudKit Tips and Tricks WWDC 2015

Prior talksCloudKit Overview

Introducing CloudKit WWDC 2014

Advanced CloudKit WWDC 2014

CloudKit JS and Web Services WWDC 2015

What's New in CloudKit WWDC 2015

CloudKit Tips and Tricks WWDC 2015

https://developer.apple.com/cloudkit

Prior talksCloudKit Overview

Core objectsCloudKit Overview

ContainerDatabaseRecordRecord Zone

Core objectsCloudKit Overview

ContainerDatabaseRecordRecord Zone

Core objectsCloudKit Overview

ContainerDatabaseRecordRecord Zone

CloudKit Overview

ContainerDatabaseRecordRecord Zone

CloudKit Container

Core objects

CloudKit Overview

ContainerDatabaseRecordRecord Zone

CloudKit Container

Public Database Private Database

Core objects

CloudKit Overview

CloudKit Container

Public Database Private Database Shared Database

NEW

ContainerDatabaseRecordRecord Zone

Core objects

Core objectsCloudKit Overview

ContainerDatabaseRecordRecord Zone

Key ValueTitle String

Body String

CreationDate Date

Folder Reference

Note

Core objects

Record Zone

CloudKit Overview

ContainerDatabaseRecordRecord Zone

Database

Core objects

Record Zone

CloudKit Overview

ContainerDatabaseRecordRecord Zone

Database

Record

ContainerDatabaseRecordRecord Zone

RecordRecord

Database

CloudKit Overview

RecordRecordRecordRecordRecordRecordRecordRecord

Record Zone

RecordRecord

Core objects

Core objects

Database

CloudKit Overview

Default Zone Custom Zone

ContainerDatabaseRecordRecord Zone

RecordRecord

RecordRecord

Record Record

Record Record

RecordRecordRecordRecord

ContainerDatabaseRecordRecord Zone

Core objects

Private Database

CloudKit Overview

Public Database Shared Database

Default Zone Default Zone

Custom Zone

Custom Zone

Shared Zone

Shared Zone

Core objectsCloudKit Overview

ContainerDatabaseRecordRecord Zone

Core objectsCloudKit Overview

ContainerDatabaseRecordRecord ZoneShare

NEW

Core objects

Private Database

CloudKit Overview

ContainerDatabaseRecordRecord ZoneShare

NEW

Database

Custom Zone

RecordRecordRecord

RecordRecord

Record

RecordRecord

RecordRecord

Share

Share

Apple usage

CloudKit Container

CloudKit Overview

Public Database Shared DatabasePrivate Database

Apple usage

CloudKit Container

CloudKit Overview

Public Database Shared DatabasePrivate Database

Apple usage

CloudKit Container

CloudKit Overview

Public Database Shared DatabasePrivate Database

Apple usage

CloudKit Container

CloudKit Overview

Public Database Shared DatabasePrivate Database

CloudKit Is Now Available Everywhere

CloudKit Is Now Available Everywhere

CloudKit Is Now Available Everywhere

CloudKit Is Now Available Everywhere

CloudKit JS Web Services

CloudKit Is Now Available Everywhere NEW

CloudKit JS Web Services

macOS

macOS

No Mac App Store requirement

macOS

No Mac App Store requirement• Add iCloud Capabilities via your provisioning profile

Web

Server to server

Web

Server to server• Acts as admin user

Web

Server to server• Acts as admin user• Uses public/private key pair registered on CloudKit Dashboard

Web

Server to server• Acts as admin user• Uses public/private key pair registered on CloudKit Dashboard• Access to public database

watchOS 3

watchOS 3

Alternative to watch connectivity code

watchOS 3

Alternative to watch connectivity codeStandalone functionality

watchOS 3

Alternative to watch connectivity codeStandalone functionality• Can work without phone present (via wifi)

watchOS 3

Alternative to watch connectivity codeStandalone functionality• Can work without phone present (via wifi)

Full* CloudKit API

*offer does not include CKSubscription

watchOS 3

Alternative to watch connectivity codeStandalone functionality• Can work without phone present (via wifi)

Full* CloudKit APISimilar code on all Apple platforms

*offer does not include CKSubscription

watchOS 3

Alternative to watch connectivity codeStandalone functionality• Can work without phone present (via wifi)

Full* CloudKit APISimilar code on all Apple platformsLimited resources

*offer does not include CKSubscription

Visualize your app's behavior on the CloudKit DashboardTelemetry

Visualize your app's behavior on the CloudKit DashboardTelemetry

NEW

Visualize your app's behaviorTelemetry

CloudKit Dashboard

Visualize your app's behaviorTelemetry

CloudKit DashboardPublic DB

Visualize your app's behaviorTelemetry

CloudKit DashboardPublic DBAggregated Private DBs

Visualize your app's behaviorTelemetry

CloudKit DashboardPublic DBAggregated Private DBsHour/day/week/month

Visualize your app's behaviorTelemetry

CloudKit DashboardPublic DBAggregated Private DBsHour/day/week/monthPer Operation type/all Operations

Telemetry

Telemetry

Performance

Correctness

Correctness

Detect client changes with abnormally frequent errors

Correctness

Detect client changes with abnormally frequent errorsError handling is essential

API Improvements

API Improvements

NEW

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record Zones Fetching Multiple Change Sets

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record ZonesFetching Multiple Change Sets

Don’t repeat your workLong-Lived Operations

Don’t repeat your workLong-Lived Operations

Operations keep running if your application exits

Don’t repeat your workLong-Lived Operations

Operations keep running if your application exitsCallbacks saved by CloudKit

Don’t repeat your workLong-Lived Operations

Operations keep running if your application exitsCallbacks saved by CloudKitOperation can be replayed later

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record ZonesFetching Multiple Change Sets

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record Zones Fetching Multiple Change Sets

How long do you want to wait?CKOperation Timeouts

QualityOfService Behavior on broken network

userInteractive

userInitiated

utility

background

default

How long do you want to wait?CKOperation Timeouts

QualityOfService Behavior on broken network

userInteractive timeout after 60 seconds

userInitiated timeout after 60 seconds

utility

background

default

How long do you want to wait?CKOperation Timeouts

QualityOfService Behavior on broken network

userInteractive timeout after 60 seconds

userInitiated timeout after 60 seconds

utility timeout after 7 days

background timeout after 7 days

default timeout after 7 days

How long do you want to wait?CKOperation Timeouts

QualityOfService Behavior on broken network

userInteractive timeout after 60 seconds

userInitiated timeout after 60 seconds

utility timeout after 7 days

background timeout after 7 days

default timeout after 7 days

How long do you want to wait?CKOperation Timeouts

QualityOfService Behavior on broken network

userInteractive timeout after 60 seconds

userInitiated timeout after 60 seconds

utility timeout after 7 days

background timeout after 7 days

default timeout after 7 days

How long do you want to wait?CKOperation Timeouts

How long do you want to wait?CKOperation Timeouts

Network inactivity• Use the timeoutIntervalForRequest property on CKOperation• Default value is 60 seconds

How long do you want to wait?CKOperation Timeouts

Network inactivity• Use the timeoutIntervalForRequest property on CKOperation• Default value is 60 seconds

Start-to-finish timeout• Use the timeoutIntervalForResource property on CKOperation• Default value is 7 days• CKOperation may stay around longer

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record Zones Fetching Multiple Change Sets

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record ZonesFetching Multiple Change Sets

CKFetchRecordZonesOperation • Poll for all record zones in a database

Reduce payloads and roundtripsHandling Many Record Zones

CKFetchRecordZonesOperation • Poll for all record zones in a database

Reduce payloads and roundtripsHandling Many Record Zones

CKFetchRecordZonesOperation • Poll for all record zones in a database

Reduce payloads and roundtripsHandling Many Record Zones

CKFetchRecordZonesOperation • Poll for all record zones in a database

Reduce payloads and roundtripsHandling Many Record Zones

CKDatabaseSubscription• Receive a push for each change in a database

CKFetchDatabaseChangesOperation• Fetch ids of record zones with changes

CKFetchRecordChangesOperation • Track and fetch record changes on a

per-record-zone basis

Reduce payloads and roundtripsHandling Many Record Zones

CKDatabaseSubscription• Receive a push for each change in a database

CKFetchDatabaseChangesOperation• Fetch ids of record zones with changes

CKFetchRecordZonesOperation • Poll for all record zones in a database

CKFetchRecordChangesOperation • Track and fetch record changes on a

per-record-zone basis

Reduce payloads and roundtripsHandling Many Record Zones

CKDatabaseSubscription• Receive a push for each change in a database

CKFetchDatabaseChangesOperation• Fetch ids of record zones with changes

CKFetchRecordZonesOperation • Poll for all record zones in a database

Reduce payloads and roundtripsHandling Many Record Zones

CKDatabaseSubscription• Receive a push for each change in a database

CKFetchDatabaseChangesOperation• Fetch ids of record zones with changes

CKFetchRecordZonesOperation • Poll for all record zones in a database

CKFetchRecordChangesOperation • Track and fetch record changes on a

per-record-zone basis

Reduce payloads and roundtripsHandling Many Record Zones

CKFetchRecordZoneChangesOperation • Fetch record changes over multiple record

zones in a single operation

CKDatabaseSubscription• Receive a push for each change in a database

CKFetchDatabaseChangesOperation• Fetch ids of record zones with changes

CKFetchRecordZonesOperation • Poll for all record zones in a database

CKFetchRecordChangesOperation • Track and fetch record changes on a

per-record-zone basis

CKDatabaseSubscriptionHandling Many Record Zones

Record Zone

Record Zone

Record Zone

Record Zone

Record

Record

Record

Record

Database

CKDatabaseSubscriptionHandling Many Record Zones

Record Zone

Record Zone

Record Zone

Record Zone

Record

Record

Record

Record

Database

Record

Record

CKDatabaseSubscriptionHandling Many Record Zones

Record Zone

Record Zone

Record Zone

Record Zone

Push

Record

Record

Record

Record

Database

Record

Record

CKDatabaseSubscriptionHandling Many Record Zones

Record Zone

Record Zone

Record Zone

Record Zone

Push

Record

Record

Record

Record

Database

Record

Record

CKFetchDatabaseChangesOperationHandling Many Record Zones

Record Zone

Record Zone

Record Zone

Record Zone

Record

Record

Record

Record

Database

Record

Record

CKFetchDatabaseChangesOperationHandling Many Record Zones

Record Zone

Record Zone

Record Zone

Record Zone

Record

Record

Record

Record

Database

Record

Record

CKFetchRecordZoneChangesOperationHandling Many Record Zones

Database

Record Zone

Record Zone

Record Zone

Record Zone

Record

Record

Record

Record

Record

Record

CKFetchRecordZoneChangesOperationHandling Many Record Zones

Database

Record Zone

Record Zone

Record Zone

Record Zone

Record

Record

Record

Record

Record

Record

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record ZonesFetching Multiple Change Sets

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record ZonesFetching Multiple Change Sets

Fetch Multiple Change Sets

public class CKFetchRecordChangesOperation : CKDatabaseOperation {

public var moreComing: Bool { get }

}

Remember this?

Fetch Multiple Change Sets

public class CKFetchRecordChangesOperation : CKDatabaseOperation {

public var moreComing: Bool { get }

}

Remember this?

Client code responsible for fetching next batch

Fetch Multiple Change Sets

public class CKFetchRecordChangesOperation : CKDatabaseOperation {

public var moreComing: Bool { get }

}

Remember this?

Client code responsible for fetching next batchCloudKit idle

Fetch Multiple Change SetsUse this instead

public class CKFetchRecordZoneChangesOperation : CKDatabaseOperation {

public var fetchAllChanges: Bool

}

Fetch Multiple Change SetsUse this instead

public class CKFetchRecordZoneChangesOperation : CKDatabaseOperation {

public var fetchAllChanges: Bool

}

CloudKit keeps pipeline full

Fetch Multiple Change SetsUse this instead

public class CKFetchRecordZoneChangesOperation : CKDatabaseOperation {

public var fetchAllChanges: Bool

}

// fetchAllChanges is true by default

CloudKit keeps pipeline full

Fetch Multiple Change SetsNew callback

public class CKFetchRecordZoneChangesOperation : CKDatabaseOperation {

public var recordZoneChangeTokensUpdatedBlock: ((CKRecordZoneID, CKServerChangeToken?,

Data?) -> Void)?

}

Fetch Multiple Change SetsNew callback

public class CKFetchRecordZoneChangesOperation : CKDatabaseOperation {

public var recordZoneChangeTokensUpdatedBlock: ((CKRecordZoneID, CKServerChangeToken?,

Data?) -> Void)?

}

Earlier record changes are safe to commit

Fetch Multiple Change SetsNew callback

public class CKFetchRecordZoneChangesOperation : CKDatabaseOperation {

public var recordZoneChangeTokensUpdatedBlock: ((CKRecordZoneID, CKServerChangeToken?,

Data?) -> Void)?

}

Earlier record changes are safe to commitNew server change token can be used on a new CKFetchRecordZoneChangesOperation

API Improvements

Long Lived OperationsCKOperation TimeoutsHandling Many Record Zones Fetching Multiple Change Sets

You and I are going to share some recordsSharing UI

Jacob Farkas

Sharing Records

public class CKShare : CKRecord

Sharing Records

What is shared? public class CKShare : CKRecord

Sharing Records

What is shared?Who is it shared with?

public class CKShare : CKRecord

Shared databaseSharing Overview

CloudKit Container

Public Database Shared DatabasePrivate Database

What is shared?Sharing Records

Private Database

What is shared?Sharing Records

Note

Private Database

What is shared?

Note

Sharing Records

Private Database

What is shared?

Note

Sharing Records

Private Database

Share public class CKShare : CKRecord {

public init(rootRecord : CKRecord)

}

What is shared?

Note

Sharing Records

Private Database

Share

public class CKShare : CKRecord {

public init(rootRecord : CKRecord)

}

Note

What is shared?

Note

Sharing Records

Private Database

Share

public class CKShare : CKRecord {

public init(rootRecord : CKRecord)

}

public class CKRecord {

public var share: CKReference? { get }

}Note

Who is it shared with?

Note

Sharing Records

Private Database

Share

Note

Who is it shared with?Sharing Records

Share

Note

Private Database

Who is it shared with?Sharing Records

Share

Note

Private Database

user@icloud.com

Who is it shared with?Sharing Records

Share

Note

Private Database

Share

Note

Private Database

Who is it shared with?Sharing Records

Share

Note

Private Database

Who is it shared with?Sharing Records

Who is it shared with?Sharing Records

Share

Note

Private Database

Share

Note

Private Database

Sharing RecordsShare URLs

Share

Note

Private Database

Sharing Records

https://www.icloud.com/notes/000Y4qow0owP6NOxDzs4qgi8Q

Share URLs

Share

Note

Private Database

Sharing Records

Family Grocery list”icloud.com/notes

Share URLs

Sharing Records

Owner Other User

Share

Note

Private Database

Accepting a share

Sharing Records

Owner Other User

Share

Note

Private Database

Accepting a share

Sharing Records

Share

Note

Private Database

Owner Other User

Accepting a share

Share

Note

Shared Database

Sharing Records

Share

Note

Private Database

Owner Other User

Accepting a share

Share

Note

Private Database

Share

Note

Shared Database

Sharing Records

Owner Other User

Share

Note

Private Database

Share

Note

Shared Database

Sharing Records

Share

Note

Private Database

Owner Other User

DemoSystem Sharing UI

Where does it live?CloudKit Sharing UI NEW

CloudKit

Where does it live?CloudKit Sharing UI NEW

CKRecord

CKShare

CKModifyRecordsOperation

CloudKit

Where does it live?CloudKit Sharing UI NEW

CKRecord

CKShare

CKModifyRecordsOperation

CloudKit

NSSharingService

NSItemProvider

AppKit

UICloudSharingController

UIKit

UICloudSharingControlleriOS Sharing API

// Create a CloudKit share record

let share = CKShare(rootRecord: rootRecord)

share[CKShareTitleKey] = "Shopping List”

share[CKShareThumbnailImageDataKey] = shoppingListThumbnail

// Create a CloudKit share record

let share = CKShare(rootRecord: rootRecord)

share[CKShareTitleKey] = "Shopping List”

share[CKShareThumbnailImageDataKey] = shoppingListThumbnail

// Create a CloudKit share record

let share = CKShare(rootRecord: rootRecord)

share[CKShareTitleKey] = "Shopping List”

share[CKShareThumbnailImageDataKey] = shoppingListThumbnail

// Create a CloudKit share record

let share = CKShare(rootRecord: rootRecord)

share[CKShareTitleKey] = "Shopping List”

share[CKShareThumbnailImageDataKey] = shoppingListThumbnail

// Create a cloud sharing controller

let sharingController = UICloudSharingController(share: share) {

(controller: UICloudSharingController,

prepareCompletionHandler : (CKShare?, CKContainer?, NSError?) -> Void) in

// Create a cloud sharing controller

let sharingController = UICloudSharingController(share: share) {

(controller: UICloudSharingController,

prepareCompletionHandler : (CKShare?, CKContainer?, NSError?) -> Void) in

// Save the share

let sharingController = UICloudSharingController(share: share) {

(controller: UICloudSharingController,

prepareCompletionHandler : (CKShare?, CKContainer?, NSError?) -> Void) in

let modifyOp = CKModifyRecordsOperation(recordsToSave: [rootRecord, share],

recordIDsToDelete: nil)

modifyOp.modifyRecordsCompletionBlock = { (_, _, error) in

prepareCompletionHandler(share, ckContainer, error)

}

self.container.privateCloudDatabase.add(modifyOp)

}

// Save the share

let sharingController = UICloudSharingController(share: share) {

(controller: UICloudSharingController,

prepareCompletionHandler : (CKShare?, CKContainer?, NSError?) -> Void) in

let modifyOp = CKModifyRecordsOperation(recordsToSave: [rootRecord, share],

recordIDsToDelete: nil)

modifyOp.modifyRecordsCompletionBlock = { (_, _, error) in

prepareCompletionHandler(share, ckContainer, error)

}

self.container.privateCloudDatabase.add(modifyOp)

}

// Save the share

let sharingController = UICloudSharingController(share: share) {

(controller: UICloudSharingController,

prepareCompletionHandler : (CKShare?, CKContainer?, NSError?) -> Void) in

let modifyOp = CKModifyRecordsOperation(recordsToSave: [rootRecord, share],

recordIDsToDelete: nil)

modifyOp.modifyRecordsCompletionBlock = { (_, _, error) in

prepareCompletionHandler(share, ckContainer, error)

}

self.container.privateCloudDatabase.add(modifyOp)

}

// Set sharing options

sharingController.availablePermissions = [.publicOnly, .readWrite]

sharingController.popoverPresentationController?.sourceView = myShareButton

sharingController.delegate = self

self.present(sharingController, animated:true, completion:nil)

// Set sharing options

sharingController.availablePermissions = [.publicOnly, .readWrite]

sharingController.popoverPresentationController?.sourceView = myShareButton

sharingController.delegate = self

self.present(sharingController, animated:true, completion:nil)

// Set sharing options

sharingController.availablePermissions = [.publicOnly, .readWrite]

sharingController.popoverPresentationController?.sourceView = myShareButton

sharingController.delegate = self

self.present(sharingController, animated:true, completion:nil)

// Set sharing options

sharingController.availablePermissions = [.publicOnly, .readWrite]

sharingController.popoverPresentationController?.sourceView = myShareButton

sharingController.delegate = self

self.present(sharingController, animated:true, completion:nil)

// Set sharing options

sharingController.availablePermissions = [.publicOnly, .readWrite]

sharingController.popoverPresentationController?.sourceView = myShareButton

sharingController.delegate = self

self.present(sharingController, animated:true, completion:nil)

NSSharingServicemacOS Sharing API

// Save the share

let itemProvider = NSItemProvider()

itemProvider.registerCloudKitShare { (prepareCompletionHandler :

(CKShare?, CKContainer?, NSError?) -> Void) in

// Save the share and root record

}

let sharingService = NSSharingService(named: NSSharingServiceNameCloudSharing)!

sharingService.delegate = self

sharingService.perform(withItems: [itemProvider])

// Save the share

let itemProvider = NSItemProvider()

itemProvider.registerCloudKitShare { (prepareCompletionHandler :

(CKShare?, CKContainer?, NSError?) -> Void) in

// Save the share and root record

}

let sharingService = NSSharingService(named: NSSharingServiceNameCloudSharing)!

sharingService.delegate = self

sharingService.perform(withItems: [itemProvider])

// Save the share

let itemProvider = NSItemProvider()

itemProvider.registerCloudKitShare { (prepareCompletionHandler :

(CKShare?, CKContainer?, NSError?) -> Void) in

// Save the share and root record

}

let sharingService = NSSharingService(named: NSSharingServiceNameCloudSharing)!

sharingService.delegate = self

sharingService.perform(withItems: [itemProvider])

// Save the share

let itemProvider = NSItemProvider()

itemProvider.registerCloudKitShare { (prepareCompletionHandler :

(CKShare?, CKContainer?, NSError?) -> Void) in

// Save the share and root record

}

let sharingService = NSSharingService(named: NSSharingServiceNameCloudSharing)!

sharingService.delegate = self

sharingService.perform(withItems: [itemProvider])

// Save the share

let itemProvider = NSItemProvider()

itemProvider.registerCloudKitShare { (prepareCompletionHandler :

(CKShare?, CKContainer?, NSError?) -> Void) in

// Save the share and root record

}

let sharingService = NSSharingService(named: NSSharingServiceNameCloudSharing)!

sharingService.delegate = self

sharingService.perform(withItems: [itemProvider])

// Define sharing options

func options(for: NSSharingService, share: NSItemProvider)-> NSCloudKitSharingServiceOptions

{

return [.allowPublic, .allowReadWrite]

}

// Define sharing options

func options(for: NSSharingService, share: NSItemProvider)-> NSCloudKitSharingServiceOptions

{

return [.allowPublic, .allowReadWrite]

}

// User clicked a share

public class NSApplication {

public func application(application: NSApplication,

userAcceptedCloudKitShareWith: CKShareMetadata)

}

// User clicked a share

public class NSApplication {

public func application(application: NSApplication,

userAcceptedCloudKitShareWith: CKShareMetadata)

}

public class UIApplication {

public func application(application: UIApplication,

userAcceptedCloudKitShareWith: CKShareMetadata)

}

// Add an Info.plist key for CloudKit Sharing

<key>CKSharingSupported</key>

<true/>

Web Sharing UICloudKit JS

Sharing In Depth

Vanessa Hong

Deep diveCommon Use Cases

Sharing multiple recordsZones in shared databaseCKShare internalsSharing APIsSpecial notes

A Note is not a single recordSharing Multiple Records

Note

A Note consists of many recordsSharing Multiple Records

Note

Asset

Media

A Note consists of many recordsSharing Multiple Records

Note

Asset

Media Links

Data

A Note consists of many recordsSharing Multiple Records

Note

Asset

Media Links

Data

Info

Participant should only see a subsetSharing Multiple Records

Note

Asset

Media Links

Data

Info

Tell us what should be sharedSharing Multiple Records

Note

Asset

Media Links

Data

Info

Records have a new propertypublic var parent: CKReference

Parent references define the hierarchy for sharingSharing Multiple Records

Note

Asset

Media Links

Data

Info

Parent Field

Records have a new propertypublic var parent: CKReference

Descendants linked to root record via the parent fieldSharing Multiple Records

Note

Asset

Media Links

Data

Info

Parent Field

Records have a new propertypublic var parent: CKReference

Create Share using CKShare(rootRecord:)Sharing Multiple Records

Note

Asset

Media Links

Data

Info

Share

Parent Field

Records have a new propertypublic var parent: CKReference

Shared DB is only a View into the owner’s private DBSharing Multiple Records

Shared Database

Participant

Private Database

Owner

After accepting, Participant sees only records with parentSharing Multiple Records

Shared Database

ParticipantOwner

Private Database

After accepting, Participant sees only records with parentSharing Multiple Records

Shared Database

ParticipantOwner

Private Database

After accepting, Participant sees only records with parentSharing Multiple Records

Shared Database

ParticipantOwner

Private Database

readWrite Participant cannot add a dangling CKRecordSharing Multiple Records

Shared Database

Participant

Private Database

Owner

readWrite Participant cannot add a dangling CKRecordSharing Multiple Records

Shared Database

Participant

Private Database

Owner

NEW

readWrite Participant cannot add a dangling CKRecordSharing Multiple Records

Shared Database

Participant

Private Database

Owner

NEW

Error

readWrite Participant cannot add a dangling CKRecordSharing Multiple Records

Shared Database

Participant

Private Database

Owner

NEW

Error

NEW

readWrite Participant cannot add a dangling CKRecordSharing Multiple Records

Shared Database

Participant

Private Database

Owner

Error: No Parent

NEW

Error

NEW

readWrite Participant can add a new parented CKRecordSharing Multiple Records

Shared Database

Participant

Private Database

Owner

readWrite Participant can add a new parented CKRecordSharing Multiple Records

Shared Database

Participant

Private Database

Owner

NEWNEW

Two owners, two sharesZones in Shared Database

Shared Database

“ShoppingList” Share “Shopping

List” Share

Two owners, two shares, two zonesZones in Shared Database

Shared Database

“ShoppingList” Share “Shopping

List” Share

Record Zone Record Zone

Two owners, two shares, two zonesZones in Shared Database

Shared Database

“ShoppingList” Share “Shopping

List” Share

Record Zone Record Zone

public class CKRecordZoneID {

public var zoneName: String

public var ownerName: String

}

Two owners, two shares, two zonesZones in Shared Database

public class CKRecordZoneID {

public var zoneName: String

public var ownerName: String

}

Shared Database

“ShoppingList” Share “Shopping

List” Share

zoneName: “Notes” zoneName: “Notes”

Two owners, two shares, two zonesZones in Shared Database

public class CKRecordZoneID {

public var zoneName: String

public var ownerName: String

}

Shared Database

“ShoppingList” Share “Shopping

List” Share

zoneName: “Notes” zoneName: “Notes”

Two owners, two shares, two zonesZones in Shared Database

public class CKRecordZoneID {

public var zoneName: String

public var ownerName: String

}

Shared Database

“ShoppingList” Share “Shopping

List” Share

zoneName: “Notes” zoneName: “Notes”ownerName: “_abcxyz” ownerName: “_1234567”

Two owners, two shares, two zonesZones in Shared Database

public class CKRecordZoneID {

public var zoneName: String

public var ownerName: String

}

Shared Database

“ShoppingList” Share “Shopping

List” Share

zoneName: “Notes” zoneName: “Notes”ownerName: “_abcxyz” ownerName: “_1234567”

Two owners, three shares, three zonesZones in Shared Database

“ShoppingList” Share “Shopping

List” Share

zoneName: “Notes” zoneName: “Notes”ownerName: “_abcxyz” ownerName: “_1234567”

“Recipe” Share

zoneName: “OtherZone”ownerName: “_abcxyz”

Shared Database

Two owners, three shares, three zonesZones in Shared Database

“ShoppingList” Share “Shopping

List” Share

zoneName: “Notes” zoneName: “Notes”ownerName: “_abcxyz” ownerName: “_1234567”

“Recipe” Share

zoneName: “OtherZone”ownerName: “_abcxyz”

Shared Database

Two owners, four shares, three zonesZones in Shared Database

“ShoppingList” Share “Shopping

List” Share

zoneName: “Notes” zoneName: “Notes”ownerName: “_abcxyz” ownerName: “_1234567”

“Recipe” Share

zoneName: “OtherZone”ownerName: “_abcxyz” “Great

Hiking Trails”

Share

Shared Database

Two owners, four shares, three zonesZones in Shared Database

“ShoppingList” Share

zoneName: “Notes” zoneName: “Notes”ownerName: “_abcxyz” ownerName: “_1234567”

“Recipe” Share

zoneName: “OtherZone”ownerName: “_abcxyz”

Shared Database

“ShoppingList” Share

“Great Hiking Trails”

Share

Prerequisite—Owner has existing Record(s) to shareCKShare

“Shopping List”

Prerequisite—Owner has existing Record(s) to shareCKShare

“Shopping List”

What to Share

Prerequisite—Owner has existing Record(s) to shareCKShare

“Shopping List”

What to Share

Share

How to Share

Is a CKRecord containing access controls for shared dataCKShare

Every CKShare has additional properties beyond a basic CKRecord

Is a CKRecord containing access controls for shared dataCKShare

Every CKShare has additional properties beyond a basic CKRecord

public class CKShare : CKRecord {

public var participants: [CKShareParticipant]

}

Share

public class CKShareParticipantParticipantParticipantParticipantParticipant

Owner sets up the ShareCKShare Lifecycle—Invite-Only

Share

Owner sets up the ShareCKShare Lifecycle—Invite-Only

1. Create a Share

Share

Owner sets up the ShareCKShare Lifecycle—Invite-Only

1. Create a Share2. publicPermission=none

publicPermission: none

Share

Owner sets up the ShareCKShare Lifecycle—Invite-Only

Participant #1

acceptanceStatus: invited

permission: readWrite

Participant #2

acceptanceStatus: invited

permission: readOnly

1. Create a Share2. publicPermission=none3. Add Participant

1. acceptanceStatus=invited2. Owner determines each

participant’s permission

publicPermission: noneparticipants:

Share

Owner sets up the ShareCKShare Lifecycle—Invite-Only

Participant #1

acceptanceStatus: invited

permission: readWrite

Participant #2

acceptanceStatus: invited

permission: readOnly

1. Create a Share2. publicPermission=none3. Add Participant

1. acceptanceStatus=invited2. Owner determines each

participant’s permission

4. Save the Share

publicPermission: noneparticipants:

Share

Owner sets up the ShareCKShare Lifecycle—Invite-Only

Participant #1

acceptanceStatus: invited

permission: readWrite

Participant #2

acceptanceStatus: invited

permission: readOnly

1. Create a Share2. publicPermission=none3. Add Participant

1. acceptanceStatus=invited2. Owner determines each

participant’s permission

4. Save the Share5. Owner gets URL

publicPermission: none

“Shopping List”icloud.com/notes

url:

participants:

Participant joins the ShareCKShare Lifecycle—Invite-Only

Share

publicPermission: none

“Shopping List”icloud.com/notes

url:

participants:

Participant #1

acceptanceStatus: invited

permission: readWrite

Participant #2

acceptanceStatus: invited

permission: readOnly

Participant joins the ShareCKShare Lifecycle—Invite-Only

Share 1. Participants accept via URLacceptanceStatus=accepted

publicPermission: none

“Shopping List”icloud.com/notes

url:

participants:

Participant #1

acceptanceStatus: invited

permission: readWrite

Participant #2

acceptanceStatus: invited

permission: readOnly

Participant #1

acceptanceStatus: accepted

permission: readWrite

Participant #2

acceptanceStatus: accepted

permission: readOnly

Owner sets up the ShareCKShare Lifecycle—readOnly or readWrite

Share

Owner sets up the ShareCKShare Lifecycle—readOnly or readWrite

1. Create a Share

Share

Owner sets up the ShareCKShare Lifecycle—readOnly or readWrite

1. Create a Share2. publicPermission=readOnly

or readWritepublicPermission: readOnly or readWrite

Share

Owner sets up the ShareCKShare Lifecycle—readOnly or readWrite

1. Create a Share2. publicPermission=readOnly

or readWrite3. Save the SharepublicPermission: readOnly or readWrite

Share

Owner sets up the ShareCKShare Lifecycle—readOnly or readWrite

1. Create a Share2. publicPermission=readOnly

or readWrite3. Save the Share4. Owner gets URL

“Shopping List”icloud.com/notes

url:

publicPermission: readOnly or readWrite

Participant joins the ShareCKShare Lifecycle—readOnly or readWrite

Share

Participant #1

acceptanceStatus: accepted

1. Anyone can join via URL. acceptanceStatus=accepted, permission is the same as the publicPermission

“Shopping List”icloud.com/notes

url:

publicPermission: readOnly or readWriteparticipants:

Lifecycle—end the share for a participantCKShare

Private DB

Owner

Shared DB

ParticipantParticipant leaves the Share by deleting the Share from their Shared DB

Lifecycle—end the share for a participantCKShare

Private DB

Owner

Shared DB

ParticipantParticipant leaves the Share by deleting the Share from their Shared DB

Lifecycle—end the share for a participantCKShare

Private DB

Owner

Shared DB

ParticipantParticipant leaves the Share by deleting the Share from their Shared DB

Owner can always remove any Participant

Lifecycle—End the share for everyoneCKShare

“Shopping List” Share

Owner deletes the Share from his private DB

Lifecycle—End the share for everyoneCKShare

“Shopping List”

Owner deletes the Share from his private DB

CKUserIdentityCKShareParticipant

Participant public class CKShareParticipant {

public var userIdentity: CKUserIdentity

}

public class CKUserIdentity {

public var lookupInfo: CKUserIdentityLookupInfo

public var nameComponents: PersonNameComponents

}

CKUserIdentityCKShareParticipant

Participant public class CKShareParticipant {

public var userIdentity: CKUserIdentity

}

public class CKUserIdentity {

public var lookupInfo: CKUserIdentityLookupInfo

public var nameComponents: PersonNameComponents

}

CKUserIdentityCKShareParticipant

Participant public class CKShareParticipant {

public var userIdentity: CKUserIdentity

}

public class CKUserIdentity {

public var lookupInfo: CKUserIdentityLookupInfo

public var nameComponents: PersonNameComponents

}

CKUserIdentityCKShareParticipant

Participant public class CKShareParticipant {

public var userIdentity: CKUserIdentity

}

public class CKUserIdentity {

public var lookupInfo: CKUserIdentityLookupInfo

public var nameComponents: PersonNameComponents

}

Mapped to iCloud accountsCKShareParticipant

Mapped to iCloud accounts

Participant #3

userIdentity.lookupInfo: <email>

Participant #4

userIdentity.lookupInfo: <phone>

Participant #2

userIdentity.lookupInfo: <phone>

Participant #1

userIdentity.lookupInfo: <email>

CKShareParticipant

Mapped to iCloud accounts

Participant #3

userIdentity.lookupInfo: <email>

Participant #4

userIdentity.lookupInfo: <phone>

Participant #2

userIdentity.lookupInfo: <phone>

Participant #1

userIdentity.lookupInfo: <email>

CKShareParticipant

Mapped to iCloud accounts

Participant #3

userIdentity.lookupInfo: <email>

Participant #4

userIdentity.lookupInfo: <phone>

Participant #2

userIdentity.lookupInfo: <phone>

Participant #1

userIdentity.lookupInfo: <email>

CKShareParticipant

No iCloud account

Verification flow to prove email ownership

No iCloud account

Verification flow to prove phone ownership

If you want to create your own Custom UISharing APIs

On behalf of the owner• Setting up the Share

On behalf of the participant• Accept the Share

watchOS and tvOS• Shared records available, but no System UI

Adding participantsOwner Sets Up the Share

Adding participantsOwner Sets Up the Share

CKFetchShareParticipantsOperation• Can look up via

- Email- Phone- CloudKit User Record ID

Adding participantsOwner Sets Up the Share

CKFetchShareParticipantsOperation• Can look up via

- Email- Phone- CloudKit User Record ID

• Returns CKShareParticipants

Adding participantsOwner Sets Up the Share

CKFetchShareParticipantsOperation• Can look up via

- Email- Phone- CloudKit User Record ID

• Returns CKShareParticipants

Pass CKShareParticipants to addParticipant

Adding participantsOwner Sets Up the Share

CKFetchShareParticipantsOperation• Can look up via

- Email- Phone- CloudKit User Record ID

• Returns CKShareParticipants

Pass CKShareParticipants to addParticipantCall CKModifyRecordsOperation to save the share

Fetch Share Metadata, then Accept the ShareParticipant Accepts a Share

CKFetchShareMetadataOperation• Converting a URL to CKShareMetadataPass CKShareMetadata to CKAcceptSharesOperation

LimitationsParticipant Accepts a Share

No nameComponents, for privacy reasonspublic class CKUserIdentity {

public var nameComponents: PersonNameComponents // empty

}

Verification flow only available via System UI:CKErrorParticipantMayNeedVerification

shareParticipant.userIdentity.lookupInfo.hasiCloudAccount

Invitees on older platformsSharing

Owner can invite anybody• Invitee may not have installed the latest operating system• Invitee may not have an Apple product

1280 x 800

1280 x 800

1280 x 800

1280 x 800

1280 x 800

Get your container ready for SharingSharing

CKRecordTypeShare• Behaves like any other Record Type in CloudKit• Can create custom fields• Can run queries

To trigger its creation• Share a record in a custom zone in any private database in the development environment• Deploy schema to productionNow, users in production can create Shares

What’s new is now oldSummary

CloudKit is available on all platformsTelemetry available on CloudKit DashboardAPI ImprovementsNew Feature—Sharing• Sharing System UI• Sharing APIs, Objects, and Lifecycle• Configure your fallback URL!

More Information

https://developer.apple.com/wwdc16/226

Related Sessions

CloudKit Best Practices Pacific Heights Friday 9:00AM

Labs

CloudKit and iCloud Lab Frameworks Lab D Thursday 4:00PM

CloudKit and iCloud Lab Frameworks Lab B Friday 12:00PM