Особенности фоновой работы ios-приложения на примере...
DESCRIPTION
Особенности фоновой работы iOS-приложения на примере синхронизации Яндекс.ДискаTRANSCRIPT
Патосин Алексей, ведущий iOS разработчик Яндекс.Диска
Особенности фоновой работы iOS приложения на примере синхронизации Яндекс.Диска
Autoloading
Offline
Agenda
Agenda
〉Background on iOS Before
Agenda
〉Background on iOS Before
〉Background on iOS Now
Agenda
〉Background on iOS Before
〉Background on iOS Now
〉How we did it
Agenda
〉Background on iOS Before
〉Background on iOS Now
〉How we did it
〉Our secrets
Closed
Closed
Foreground
Closed
ForegroundSleep
Closed
ForegroundSleep
Closed
Foreground
Background
Sleep
Closed
Foreground
Background
up to 10 min
Sleep
Closed
Foreground
Background
Sleep
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
up to 30 sec
Closed
Foreground
Background
Sleep
Background fetch
Silent notifications
NSURLSession
up to 30 sec up to 3 min (was 10)
Background Fetch
Sleep Background
Background Fetch
Sleep Background
Silent Push Notifications
Sleep Background
Silent Push Notifications
Sleep Background
NSURLSession
NSURLSession
NSURLSession
NSURLSession
NSURLSession
Connection
! Configuration
Connection
! Configuration
Connection
! Configuration
NSURLSession
NSURLSession
!
!
!
!
!
Connection
! Configuration
Connection
! Configuration
Connection
! Configuration
NSURLSession
NSURLSession
!
!
!
!
!
Connection
! Configuration
Configuration
Connection
! Configuration
Connection
! Configuration
NSURLSession
NSURLSession
!
!
!
!
!
Task
Task
Task
Connection
! Configuration
Configuration
Connection
! Configuration
Connection
! Configuration
NSURLSession Tasks
NSURLSession Tasks
Data Task
NSURLSession Tasks
Data Task Upload Task
NSURLSession Tasks
Data Task Upload Task Download Task
NSURLSession Tasks
Data Task Upload Task Download Task
background background
NSURLSession Tasks
Background transfer is supported only when WiFi is available!
Data Task Upload Task Download Task
background background
NSURLSession
class NSURLSession : NSObject { //.. init(configuration: NSURLSessionConfiguration) -> NSURLSession //.. func dataTaskWithURL(url: NSURL) -> NSURLSessionDataTask //.. func uploadTaskWithRequest(request: NSURLRequest, fromFile fileURL: NSURL) -> NSURLSessionUploadTask ! //.. func downloadTaskWithURL(url: NSURL) -> NSURLSessionDownloadTask ! //.. }
nsurlsessiond
nsurlsessiond
Task
Task
Task
✓
✘
✓
nsurlsessiond nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
✓
✘
✓
nsurlsessiond nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
✓
✘
✓
nsurlsessiond nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
✓
✘
✓
nsurlsessiond nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
✓
✘
✓
nsurlsessiond nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
✓
✘
✓
nsurlsessiond nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
✓
✘
✓
completionHandler: ((UIBackgroundFetchResult) -> Void)!)
NSURLSessionDataTask
iOS Non-deterministic System
Petri Dishes Experiment
Background Fetch Alarm Experiment
Background Fetch Alarm Experiment
00:00 03:00 06:00 09:00 12:00 15:00 18:00 21:00 24:00
Background Fetch Alarm Experiment
00:00 03:00 06:00 09:00 12:00 15:00 18:00 21:00 24:00
Background Fetch Alarm Experiment
00:00 03:00 06:00 09:00 12:00 15:00 18:00 21:00 24:00
Background Fetch Alarm Experiment
00:00 03:00 06:00 09:00 12:00 15:00 18:00 21:00 24:00
Background Fetch Alarm Experiment
00:00 03:00 06:00 09:00 12:00 15:00 18:00 21:00 24:00
Background Fetch Alarm Experiment
00:00 03:00 06:00 09:00 12:00 15:00 18:00 21:00 24:00
Non-deterministic NSURLSession
nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
Delivery of remote notifications is not guaranteed!
Delivery of remote notifications is not guaranteed!
Delivery of remote notifications is not guaranteed!
Delivery of remote notifications is not guaranteed!
Delivery of remote notifications is not guaranteed!
Best Practices
Divide and Conquer
Divide and Conquer
NSURLSession
(background)
Upload
NSURLSession
(background)
Download
NSURLSession
!
Data
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
var taskDescription: String
Logic Restoration
successBlock(…);
failureBlock(…);
progressBlock(…); nsurlsessiond
!
!
func getTasksWithCompletionHandler(_ completionHandler: ([AnyObject]!, [AnyObject]!, [AnyObject]!) -> Void)
var taskDescription: String
CompletionHandler
CompletionHandler
optional func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void)
CompletionHandler
optional func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void)
optional func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
CompletionHandler
optional func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void)
optional func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
optional func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler completionHandler: () -> Void)
How to support long-running operations in background
How to support long-running operations in background
Parsing
How to support long-running operations in background
30 sec
Parsing
parsingOffset = 12 424 523
How to support long-running operations in background
30 sec
Parsing
parsingOffset = 12 424 523
30 sec
parsingOffset = 25 992 012
How to support long-running operations in background
30 sec
Parsing
parsingOffset = 12 424 523
30 sec 30 sec
parsingOffset = 25 992 012parsingOffset = 34 436 001
How to support long-running operations in background
30 sec
Parsing
parsingOffset = 12 424 523
30 sec 30 sec 30 sec
parsingOffset = 25 992 012parsingOffset = 34 436 001parsingOffset = 41 928 528
How to support long-running operations in background
30 sec
Parsing
parsingOffset = 12 424 523
30 sec 30 sec 30 sec 12 sec
parsingOffset = 25 992 012parsingOffset = 34 436 001parsingOffset = 41 928 528
How to support long-running operations in background
url type was_processed
1
1
0
0
How to support long-running operations in background
url type was_processed
1
1
0
0
How to support long-running operations in background
url type was_processed
1
1
0
0
ALAssetsLibrary
ALAssetsLibrary
func uploadTaskWithRequest(_ request: NSURLRequest, fromFile fileURL: NSURL) -> NSURLSessionUploadTask
ALAssetsLibrary
assets-library://
func uploadTaskWithRequest(_ request: NSURLRequest, fromFile fileURL: NSURL) -> NSURLSessionUploadTask
NSURLSessionTask Bug
nsurlsessiond
!
!
!
!
!
!
Task
Task
Task
var discretionary: Bool
Redirect in background
Redirect in background
Authorization
Redirect in background
Authorization
User-Agent
Redirect in background
Authorization
User-Agent
Yandex-Authorization
How to test activity in background?
Logs
Logs #upload_queue_manager Upload next file in queue. (0 left) #upload_queue_manager nextFileInQueue #upload_queue_manager nextFileInQueueForForegroundUpload #upload_queue_manager nextFileInQueue, was selected (null) file #upload_queue_manager There are no more files in upload queue. #upload_queue_manager nextFileInQueue #upload_queue_manager nextFileInQueueForForegroundUpload #upload_queue_manager nextFileInQueue, was selected (null) file #upload_queue_manager endBackgroundTask invoked #completion_handlers_manager endedWithoutAnyData Failed to download thumbnail for https://webdav.yandex.ru/disk/2014-07-02%2018-17-31.jpg, resend request in 1.000 #offline_updater update root offline status 1 for file <YOFile: 0x7fadde15e440> https://webdav.yandex.ru/disk/_test/_DSC2502%20copy%202.ARW #download_queue_manager download offline files {( <YOFile: 0x7fadde15e440> https://webdav.yandex.ru/disk/_test/_DSC2502%20copy%202.ARW )} #download_queue_manager looking for next offline file.. #download_queue_manager Found file for download https://webdav.yandex.ru/disk/_test/_DSC2502%20copy%202.ARW (mask: 4) #connection_manager Start download https://webdav.yandex.ru/disk/_test/_DSC2502%20copy%202.ARW #task_description description now contains: {"kURLSessionTaskDescriptionWasCreatedInBackground":0,"kURLSessionTaskDescriptionURLString":"https:\/\/webdav.yandex.ru\/disk\/_test\/_DSC2502%20copy%202.ARW"} #connection_manager NSURLSessionDownloadTask <__NSCFBackgroundDownloadTask: 0x7faddbc40750>{ taskIdentifier: 1 } started, invoking completionHandler if it has now #completion_handlers_manager urlSessionTaskStarted: #completion_handlers_manager current properties state: sessionCompletionHandlers { } backgroundFetchCompletionHandler (null) remoteNotificationCompletionHandler (null) backgroundFetchCompletionHandlerCreationDate (null) processIdentifiers {( )} !#completion_handlers_manager there's no URLSession completionHandler right now #offline_updater update root offline status 1 for file <YOFile: 0x7fadde1926a0> https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW #download_queue_manager download offline files {(
Logs
#download_queue_manager looking for next offline file.. #download_queue_manager Found file for download https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (mask: 4) #connection_manager Start download https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW #session_manager completed task <__NSCFBackgroundDownloadTask: 0x7faddbc4e700>{ taskIdentifier: 4 } with URL https://webdav.yandex.ru/disk/_test/101@2x~iphone.png error (null) #task_description description now contains: {"kURLSessionTaskDescriptionWasCreatedInBackground":0,"kURLSessionTaskDescriptionURLString":"https:\/\/webdav.yandex.ru\/disk\/_test\/_DSC2502%20copy.ARW"} #connection_manager NSURLSessionDownloadTask <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } started, invoking completionHandler if it has now #completion_handlers_manager urlSessionTaskStarted: #completion_handlers_manager current properties state: sessionCompletionHandlers { } backgroundFetchCompletionHandler (null) remoteNotificationCompletionHandler (null) backgroundFetchCompletionHandlerCreationDate (null) processIdentifiers {( )} #completion_handlers_manager there's no URLSession completionHandler right now #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (15711916/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (15761068/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (15793836/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (15859372/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (15924908/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16006828/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16072364/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16137900/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16203436/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16285356/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16350892/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16416428/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16498348/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16563884/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16645804/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16711340/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16776876/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16809644/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16858796/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16924332/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (16989868/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (17071788/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (17137324/24936448) #session_manager data written for task <__NSCFBackgroundDownloadTask: 0x7fadde03e140>{ taskIdentifier: 5 } with URL https://webdav.yandex.ru/disk/_test/_DSC2502%20copy.ARW (17219244/24936448)
Logs
Logs
Sniffer
Sniffer
Wireshark
Sniffer
Wireshark Charles
Local Notifications
One more secret…
How to prolong Background activity
How to prolong Background activity
How to prolong Background activity
30 sec
How to prolong Background activity
30 sec
How to prolong Background activity
30 sec
30 sec
How to prolong Background activity
30 sec
30 sec
func beginBackgroundTaskWithExpirationHandler(_ handler: () -> Void) -> UIBackgroundTaskIdentifier
How to prolong Background activity
30 sec
30 sec
func beginBackgroundTaskWithExpirationHandler(_ handler: () -> Void) -> UIBackgroundTaskIdentifier
up to 3 min
Results
!Up to 2M !
files are being uploaded each day from iOS client
70% files are uploaded in background
Uploading in background
Uploading in background
Background
Foreground
1M Background Fetches per day
less than 5%
Итак
Thanks!
Теперь питание компьютера можно отключить
Alexey Patosin
Senior iOS Software Engineer – Yandex
Contacts