keeping your watch app up to date - apple developer · 2016-07-08 · austen green watchos...

196
© 2016 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple. App Frameworks #WWDC16 Session 218 Keeping Your Watch App Up to Date Eric Lanz watchOS Engineer Austen Green watchOS Engineer

Upload: others

Post on 26-May-2020

12 views

Category:

Documents


0 download

TRANSCRIPT

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

App Frameworks #WWDC16

Session 218

Keeping Your Watch App Up to Date

Eric Lanz watchOS EngineerAusten Green watchOS Engineer

Overview

Walkthrough

Scheduling

Best Practices

Case Study

User modelOverview

User modelOverview

Waiting for Coffee

User modelOverview

Waiting for Coffee

Check Weather

User modelOverview

Waiting for Coffee

Check Weather

Find a Lunch Spot

User modelOverview

Waiting for Coffee

Check Weather

Find a Lunch Spot

Receive Notification

User modelOverview

Waiting for Coffee Check Traffic

Check Weather

Find a Lunch Spot

Receive Notification

User modelOverview

Waiting for Coffee Find a Lunch Spot Check Traffic

Check Weather Receive Notification Quick Reply

User modelOverview

Waiting for Coffee Check Traffic

Check Weather Quick Reply

Find a Lunch Spot

Receive Notification

SchedulingOverview

Check Weather

Background Foreground

SchedulingOverview

Update UI

Background Foreground

Check Weather

SchedulingOverview

Update UIFetch Data

Background Foreground

Check Weather

SchedulingOverview

Background Foreground

Check Weather

Update UIFetch DataWake Up

Tasks

watchOS

Suspended

Task

Task Task

Task

Task

Task Task Task

Applications

Tasks

Active

ApplicationswatchOS

Task

Task Task

Task

Task Task Task

Task

Tasks

Active

ApplicationswatchOS

Task

Task Task

Task

Task Task Task

Task

Tasks

Active

watchOS Applications

Task

Task Task

Task

Task Task Task

Taskfunc handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>)

Tasks

Suspended

watchOS Applications

Task

Task Task

Task

Task Task Task

Task

Tasks

Suspended

watchOS Applications

Task

Task Task

Task

Task Task Task

Task

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

WKExtension: scheduleBackgroundRefresh

Schedule using URLSession

WKExtension: scheduleSnapshotRefresh

Schedule using Watch Connectivity

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

Schedule using URLSession

Schedule using Watch Connectivity

WKExtension: scheduleBackgroundRefresh

WKExtension: scheduleSnapshotRefresh

Wake upTasks

Check Weather

Background Foreground

Application Task

Update UIFetch DataWake Up

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

Schedule using Watch Connectivity

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKExtension: scheduleBackgroundRefresh

Schedule using URLSession

WKExtension: scheduleSnapshotRefresh

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

Schedule using Watch Connectivity

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKExtension: scheduleBackgroundRefresh

Schedule using URLSession

WKExtension: scheduleSnapshotRefresh

Fetch dataTasks

Check Weather

Background Foreground

URLSession Task

Update UIFetch DataWake Up

Snapshots

Snapshots

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

WKExtension: scheduleBackgroundRefresh

Schedule using URLSession

WKExtension: scheduleSnapshotRefresh

Schedule using Watch Connectivity

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

WKExtension: scheduleBackgroundRefresh

Schedule using URLSession

WKExtension: scheduleSnapshotRefresh

Schedule using Watch Connectivity

SnapshotTasks

Check Weather

Background Foreground

Snapshot Task

Update UIFetch DataWake Up

Meet expectationsSnapshots

Optional default stateSnapshots

More informationSnapshots

Designing Great Apple Watch Experiences Presidio Wednesday 1:40PM

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

WKExtension: scheduleBackgroundRefresh

Schedule using URLSession

WKExtension: scheduleSnapshotRefresh

Schedule using Watch Connectivity

SummaryTasks

WKWatchConnectivityRefreshBackgroundTask

WKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

WKSnapshotRefreshBackgroundTask

WKExtension: scheduleBackgroundRefresh

Schedule using URLSession

WKExtension: scheduleSnapshotRefresh

Schedule using Watch Connectivity

Watch connectivityTasks

Watch connectivityTasks

User Info

File

Context

Complication

Watch connectivityTasks

Is Session Active

NEW

Watch connectivityTasks

hasContentPendingIs Session Active

hasContentPending

Watch connectivityTasks

Is Session Active Complete Task

Schedule Background Runtime

Schedule Background Runtime

Receive Tasks

Schedule Background Runtime

Receive Tasks Do Work

Schedule Background Runtime

Receive Tasks Do Work

Schedule More Runtime

Schedule Background Runtime

Receive Tasks Do Work

Schedule More Runtime

Tell System When Done

Be a Good Citizen

Be a Good Citizen

User Launches App

3:00 PM

Be a Good Citizen

4:00 PM

Wake UpUser Launches App

3:00 PM

Be a Good Citizen

4:00 PM

Wake UpUser Launches App

3:50 PM

Be a Good Citizen

4:50 PM

Wake UpUser Launches App

3:50 PM

Walkthrough

Football scoresWalkthrough

7:00 PM 9:00 PM

Football scoresWalkthrough

7:00 PM 9:00 PM

Update Score Update Score Update Score

7:30 PM 8:00 PM 8:30 PM

Football scoresWalkthrough

7:00 PM 9:00 PM

7:30 PM 8:00 PM 8:30 PM

Update Score Update Score Update Score

Football scoresWalkthrough

7:00 PM 9:00 PM

7:30 PM 8:00 PM 8:30 PM

Update Score Update Score Update Score

Football scoresWalkthrough

7:00 PM 9:00 PM

7:30 PM 8:00 PM 8:30 PM

Update Score Update Score Update Score

// Scheduling Background Runtime

func myScheduleNextRefreshTask() {

let fireDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes from now

let userInfo = ["lastActiveDate" : Date(), // optional last active time

"reason" : “scoreUpdate”] // optional reason

WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: fireDate

, userInfo: userInfo) { (error) in

if error == nil {

// successfully scheduled

}

}

}

// Scheduling Background Runtime

func myScheduleNextRefreshTask() {

let fireDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes from now

let userInfo = ["lastActiveDate" : Date(), // optional last active time

"reason" : “scoreUpdate”] // optional reason

WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: fireDate

, userInfo: userInfo) { (error) in

if error == nil {

// successfully scheduled

}

}

}

// Scheduling Background Runtime

func myScheduleNextRefreshTask() {

let fireDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes from now

let userInfo = ["lastActiveDate" : Date(), // optional last active time

"reason" : “scoreUpdate”] // optional reason

WKExtension.shared().scheduleBackgroundRefresh(withPreferredDate: fireDate

, userInfo: userInfo) { (error) in

if error == nil {

// successfully scheduled

}

}

}

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up

7:30:00

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up

7:30:02

Fetch Data

// Fetching Data in the Background

func myScheduleURLSession() {

let backgroundConfigObject = URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: "com.example.urlsession")

let backgroundSession = URLSession(configuration: backgroundConfigObject)

let downloadTask = backgroundSession.downloadTask(

with: URL(string: "https://example.com/currentScores.json")!)

downloadTask.resume()

}

// Fetching Data in the Background

func myScheduleURLSession() {

let backgroundConfigObject = URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: "com.example.urlsession")

let backgroundSession = URLSession(configuration: backgroundConfigObject)

let downloadTask = backgroundSession.downloadTask(

with: URL(string: "https://example.com/currentScores.json")!)

downloadTask.resume()

}

// Fetching Data in the Background

func myScheduleURLSession() {

let backgroundConfigObject = URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: "com.example.urlsession")

let backgroundSession = URLSession(configuration: backgroundConfigObject)

let downloadTask = backgroundSession.downloadTask(

with: URL(string: "https://example.com/currentScores.json")!)

downloadTask.resume()

}

// Fetching Data in the Background

func myScheduleURLSession() {

let backgroundConfigObject = URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: "com.example.urlsession")

let backgroundSession = URLSession(configuration: backgroundConfigObject)

let downloadTask = backgroundSession.downloadTask(

with: URL(string: "https://example.com/currentScores.json")!)

downloadTask.resume()

}

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up

7:30:05

Fetch Data

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up Fetch Data Update Model

7:33:00

// Handling Background Tasks// WKExtensionDelegate

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {

for task in backgroundTasks {

if let urlTask = task as? WKURLSessionRefreshBackgroundTask

let backgroundConfigObject

URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: urlTask.sessionIdentifier)

let backgroundSession = URLSession(configuration: backgroundConfigObject,

delegate: self,

delegateQueue: nil)

// receive data via URLSessionDownloadDelegate

pendingBackgroundTasks.append(task)

} else {

task.setTaskCompleted() // make sure to complete all tasks

}

}

}

// Handling Background Tasks// WKExtensionDelegate

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {

for task in backgroundTasks {

if let urlTask = task as? WKURLSessionRefreshBackgroundTask

let backgroundConfigObject

URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: urlTask.sessionIdentifier)

let backgroundSession = URLSession(configuration: backgroundConfigObject,

delegate: self,

delegateQueue: nil)

// receive data via URLSessionDownloadDelegate

pendingBackgroundTasks.append(task)

} else {

task.setTaskCompleted() // make sure to complete all tasks

}

}

}

// Handling Background Tasks// WKExtensionDelegate

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {

for task in backgroundTasks {

if let urlTask = task as? WKURLSessionRefreshBackgroundTask

let backgroundConfigObject

URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: urlTask.sessionIdentifier)

let backgroundSession = URLSession(configuration: backgroundConfigObject,

delegate: self,

delegateQueue: nil)

// receive data via URLSessionDownloadDelegate

pendingBackgroundTasks.append(task)

} else {

task.setTaskCompleted() // make sure to complete all tasks

}

}

}

// Handling Background Tasks// WKExtensionDelegate

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {

for task in backgroundTasks {

if let urlTask = task as? WKURLSessionRefreshBackgroundTask

let backgroundConfigObject

URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: urlTask.sessionIdentifier)

let backgroundSession = URLSession(configuration: backgroundConfigObject,

delegate: self,

delegateQueue: nil)

// receive data via URLSessionDownloadDelegate

pendingBackgroundTasks.append(task)

} else {

task.setTaskCompleted() // make sure to complete all tasks

}

}

}

// Handling Background Tasks// WKExtensionDelegate

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {

for task in backgroundTasks {

if let urlTask = task as? WKURLSessionRefreshBackgroundTask

let backgroundConfigObject

URLSessionConfiguration.backgroundSessionConfiguration(

withIdentifier: urlTask.sessionIdentifier)

let backgroundSession = URLSession(configuration: backgroundConfigObject,

delegate: self,

delegateQueue: nil)

// receive data via URLSessionDownloadDelegate

pendingBackgroundTasks.append(task)

} else {

task.setTaskCompleted() // make sure to complete all tasks

}

}

}

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up

7:33:02

Update UIFetch Data Update Model

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up

7:30:05

Update UIFetch Data Update Model

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up

7:34:00

Update UIFetch Data Update Model

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up

7:34:05

Update UIFetch Data Update Model

// Completing Snapshot Task

func myCompleteSnapshotTask(snapTask : WKSnapshotRefreshBackgroundTask) {

let expireDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes

let userInfo = ["lastActiveDate" : Date()]

let restoredDefaultState = false

snapTask.setTaskCompleted(restoredDefaultState: restoredDefaultState,

estimatedSnapshotExpiration: expireDate,

userInfo: userInfo)

}

// Completing Snapshot Task

func myCompleteSnapshotTask(snapTask : WKSnapshotRefreshBackgroundTask) {

let expireDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes

let userInfo = ["lastActiveDate" : Date()]

let restoredDefaultState = false

snapTask.setTaskCompleted(restoredDefaultState: restoredDefaultState,

estimatedSnapshotExpiration: expireDate,

userInfo: userInfo)

}

// Completing Snapshot Task

func myCompleteSnapshotTask(snapTask : WKSnapshotRefreshBackgroundTask) {

let expireDate = Date(timeIntervalSinceNow: 30 * 60) // 30 minutes

let userInfo = ["lastActiveDate" : Date()]

let restoredDefaultState = false

snapTask.setTaskCompleted(restoredDefaultState: restoredDefaultState,

estimatedSnapshotExpiration: expireDate,

userInfo: userInfo)

}

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up Fetch Data Update Model Update UI

Football scoresWalkthrough

7:30 PM 7:35 PM

Wake Up Fetch Data Update Model Update UI

5 seconds 5 seconds 5 seconds

Scheduling

Austen Green watchOS Engineer

RuntimeScheduling

RuntimeScheduling

Always scheduled in foreground

RuntimeScheduling

Always scheduled in foregroundUsually suspended in background

RuntimeScheduling

Always scheduled in foregroundUsually suspended in backgroundTargeted runtime for specific tasks

Runtime limitsScheduling

Runtime limitsScheduling

On order of seconds

Runtime limitsScheduling

On order of seconds• Time and CPU considered

Runtime limitsScheduling

On order of seconds• Time and CPU considered• Apps killed for exceeding limits

- CPU - 0xc51bad01- Time - 0xc51bad02

Runtime limitsScheduling

On order of seconds• Time and CPU considered• Apps killed for exceeding limits

- CPU - 0xc51bad01- Time - 0xc51bad02

Different allocations by taskWKApplicationRefreshBackgroundTask

WKURLSessionRefreshBackgroundTask

ComplicationsScheduling

ComplicationsScheduling

Multiple updates per hour

ComplicationsScheduling

Multiple updates per hourRequest updates through WKExtension

ComplicationsScheduling

Multiple updates per hourRequest updates through WKExtension50 guaranteed pushes

// Scheduling

// Complications

func modelChangedOniPhone() { let session = WCSession.defaultSession() let transfers = session.remainingComplicationUserInfoTransfers let userInfo // Complication data switch transfers { case 0: // No transfers left. Can still try to send session.transferCurrentComplicationUserInfo(userInfo) break; case 1...10: // Running low on transfers // Conditionally send if it's really important // Otherwise conserve the transfer for a more significant change break; default: // Send data immediately session.transferCurrentComplicationUserInfo(userInfo) } }

NEW

// Scheduling

// Complications

func modelChangedOniPhone() { let session = WCSession.defaultSession() let transfers = session.remainingComplicationUserInfoTransfers let userInfo // Complication data switch transfers { case 0: // No transfers left. Can still try to send session.transferCurrentComplicationUserInfo(userInfo) break; case 1...10: // Running low on transfers // Conditionally send if it's really important // Otherwise conserve the transfer for a more significant change break; default: // Send data immediately session.transferCurrentComplicationUserInfo(userInfo) } }

NEW

// Scheduling

// Complications

func modelChangedOniPhone() { let session = WCSession.defaultSession() let transfers = session.remainingComplicationUserInfoTransfers let userInfo // Complication data switch transfers { case 0: // No transfers left. Can still try to send session.transferCurrentComplicationUserInfo(userInfo) break; case 1...10: // Running low on transfers // Conditionally send if it's really important // Otherwise conserve the transfer for a more significant change break; default: // Send data immediately session.transferCurrentComplicationUserInfo(userInfo) } }

NEW

// Scheduling

// Complications

func modelChangedOniPhone() { let session = WCSession.defaultSession() let transfers = session.remainingComplicationUserInfoTransfers let userInfo // Complication data switch transfers { case 0: // No transfers left. Can still try to send session.transferCurrentComplicationUserInfo(userInfo) break; case 1...10: // Running low on transfers // Conditionally send if it's really important // Otherwise conserve the transfer for a more significant change break; default: // Send data immediately session.transferCurrentComplicationUserInfo(userInfo) } }

NEW

// Scheduling

// Complications

func modelChangedOniPhone() { let session = WCSession.defaultSession() let transfers = session.remainingComplicationUserInfoTransfers let userInfo // Complication data switch transfers { case 0: // No transfers left. Can still try to send session.transferCurrentComplicationUserInfo(userInfo) break; case 1...10: // Running low on transfers // Conditionally send if it's really important // Otherwise conserve the transfer for a more significant change break; default: // Send data immediately session.transferCurrentComplicationUserInfo(userInfo) } }

NEW

// Scheduling

// CLKComplicationDataSource

optional public func getNextRequestedUpdateDate(handler handler: (NSDate?) -> Void)

// Scheduling

// WKExtension

public func scheduleBackgroundRefresh(withPreferredDate preferredFireDate: Date,

userInfo: NSSecureCoding?, scheduledCompletion: (NSError?) -> Swift.Void)

// Scheduling

// CLKComplicationDataSource

optional public func requestedUpdateDidBegin()

// Scheduling

// WKExtensionDelegate

optional public func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>)

Dock appsScheduling

Dock appsScheduling

Minimum one per hour

Dock appsScheduling

Minimum one per hourDistributed budget

Dock appsScheduling

Minimum one per hourDistributed budget

Dock appsScheduling

Minimum one per hourDistributed budgetKept in memory

Recent appScheduling

Recent appScheduling

Most Recently Used app in dock

Recent appScheduling

Most Recently Used app in dock• Treated like a favorite app

Recent appScheduling

Most Recently Used app in dock• Treated like a favorite app

Home screen apps should not expect regular scheduling

System snapshotsScheduling

System snapshotsScheduling

Does not count against budget

System snapshotsScheduling

Does not count against budgetIn addition to app-requested snapshot

System snapshotsScheduling

Does not count against budgetIn addition to app-requested snapshotTriggers

System snapshotsScheduling

Does not count against budgetIn addition to app-requested snapshotTriggers• Complication timeline update

System snapshotsScheduling

Does not count against budgetIn addition to app-requested snapshotTriggers• Complication timeline update• Notification interaction

System snapshotsScheduling

Does not count against budgetIn addition to app-requested snapshotTriggers• Complication timeline update• Notification interaction• Foreground –> Background

System snapshotsScheduling

Does not count against budgetIn addition to app-requested snapshotTriggers• Complication timeline update• Notification interaction• Foreground –> Background• “Default state” one hour after backgrounding

System snapshotsScheduling

Does not count against budgetIn addition to app-requested snapshotTriggers• Complication timeline update• Notification interaction• Foreground –> Background• “Default state” one hour after backgrounding• Boot

Best Practices

Best Practices

Best Practices

Schedule as often as needed

Best Practices

Schedule as often as neededDo not feel obligated to do work • Finish ASAP• Defer work

Best Practices

Schedule as often as neededDo not feel obligated to do work • Finish ASAP• Defer work

Consider all runtime opportunities• Dock and foreground activations• Notifications• Complication updates• Background refresh

WKApplicationRefreshBackgroundTaskBest Practices

WKApplicationRefreshBackgroundTaskBest Practices

Use scheduleBackgroundRefresh for general-purpose runtime

WKApplicationRefreshBackgroundTaskBest Practices

Use scheduleBackgroundRefresh for general-purpose runtime• Polling

WKApplicationRefreshBackgroundTaskBest Practices

Use scheduleBackgroundRefresh for general-purpose runtime• Polling• Scheduling future NSURLSessions

WKApplicationRefreshBackgroundTaskBest Practices

Use scheduleBackgroundRefresh for general-purpose runtime• Polling• Scheduling future NSURLSessions• Known time transitions

WKApplicationRefreshBackgroundTaskBest Practices

Use scheduleBackgroundRefresh for general-purpose runtime• Polling• Scheduling future NSURLSessions• Known time transitions• Triggering complication updates

SnapshotsBest Practices

SnapshotsBest Practices

Invalidate snapshots appropriately

SnapshotsBest Practices

Invalidate snapshots appropriately“Significant content change”

SnapshotsBest Practices

Invalidate snapshots appropriately“Significant content change”Avoid high-frequency invalidation

Data flowBest Practices

Data flowBest Practices

External Event

Data flowBest Practices

External Event

Model

Data flowBest Practices

UpdateComplication

External Event

Request Snapshot Request Background URL Session

Schedule Background Refresh

Model

App lifecycleBest Practices

App lifecycleBest Practices

Finish background tasks ASAP on foreground activation

App lifecycleBest Practices

Finish background tasks ASAP on foreground activationFinish foreground work when entering background

App lifecycleBest Practices

Finish background tasks ASAP on foreground activationFinish foreground work when entering backgroundNSProcessInfo.performExpiringActivity

App lifecycleBest Practices

Finish background tasks ASAP on foreground activationFinish foreground work when entering backgroundNSProcessInfo.performExpiringActivity

WatchKit Tips and Tricks WWDC 2015

App lifecycleBest Practices

Finish background tasks ASAP on foreground activationFinish foreground work when entering backgroundNSProcessInfo.performExpiringActivity

Data protection

WatchKit Tips and Tricks WWDC 2015

TestingBest Practices

TestingBest Practices

Simulator for iterative development

TestingBest Practices

Simulator for iterative developmentKeep the device on charger

TestingBest Practices

Simulator for iterative developmentKeep the device on chargerTest the launch path

TestingBest Practices

Simulator for iterative developmentKeep the device on chargerTest the launch pathVerify tasks are being completed

TestingBest Practices

Simulator for iterative developmentKeep the device on chargerTest the launch pathVerify tasks are being completedLive on it

TestingBest Practices

Simulator for iterative developmentKeep the device on chargerTest the launch pathVerify tasks are being completedLive on it• Vary number of apps in the dock

StocksCase Study

StocksCase Study

StocksCase Study

Characteristics

StocksCase Study

Characteristics• NSURLSession to retrieve server data

StocksCase Study

Characteristics• NSURLSession to retrieve server data• Has a complication

StocksCase Study

Characteristics• NSURLSession to retrieve server data• Has a complication• Periodic cadence for part of the day

StocksCase Study

Characteristics• NSURLSession to retrieve server data• Has a complication• Periodic cadence for part of the day• No updates while markets are closed

Case Study

Boot

Case Study

Boot• Load last data for snapshot

Case Study

Boot• Load last data for snapshot• Schedule a background NSURLSession

Case Study

Boot• Load last data for snapshot• Schedule a background NSURLSession• Use NSURLSessionDownloadTask

Case Study

Boot• Load last data for snapshot• Schedule a background NSURLSession• Use NSURLSessionDownloadTask• NSURLSessionDataTask will fail for

background session on app suspension

Case Study

NSURLSession

Case Study

NSURLSession• Update model

Case Study

NSURLSession• Update model

- Trigger a complication update

Case Study

NSURLSession• Update model

- Trigger a complication update- Request a new snapshot for now

Case Study

NSURLSession• Update model

- Trigger a complication update- Request a new snapshot for now- Request a background refresh for next

expected model update time

Case Study

Background refresh

Case Study

Background refresh• Schedule the next NSURLSession download

Stocks activated from the dock

Case Study

Stocks activated from the dock• Use NSURLSession to update model

Case Study

Stocks activated from the dock• Use NSURLSession to update model

- Request complication update

Case Study

Stocks activated from the dock• Use NSURLSession to update model

- Request complication update- Request new snapshot

Case Study

Stocks activated from the dock• Use NSURLSession to update model

- Request complication update- Request new snapshot- Schedule background refresh for a

later time

Case Study

Case Study

Last update after market close

Case Study

Last update after market close• Data has stopped changing for the day

Case Study

Last update after market close• Data has stopped changing for the day

- Complete update as normal

Case Study

Last update after market close• Data has stopped changing for the day

- Complete update as normal- Schedule next refresh for market open

Summary

Summary

Complete your tasks

Summary

Complete your tasksUse runtime efficiently

Summary

Complete your tasksUse runtime efficientlyTell the system when data changes

Summary

Complete your tasksUse runtime efficientlyTell the system when data changesConsider adoption strategies on case-by-case basis

More Information

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

What’s New in watchOS 3 Presidio Tuesday 5:00PM

Quick Interaction Techniques for watchOS Presidio Wednesday 11:00AM

Designing Great Apple Watch Experiences Presidio Wednesday 1:40PM

Architecting for Performance on watchOS 3 Mission Thursday 3:00PM

Related Sessions

Labs

WatchKit and Background Tasks Lab Frameworks Lab C Thursday 10:30AM

WatchKit and WatchConnectivity Lab Frameworks Lab B Friday 2:00PM