- Overview of Background Execution
- Best practices
- New BackgroundTasks framework
Apple Document: BackgroundTasks ์ฐธ๊ณ
- background execution์ด๋ ์ฑ์ด foreground ์ํ๊ฐ ์๋ ์ํฉ์์ ๋์ํ๊ณ ์คํ๋๋ ๊ฒ์ ๋งํ๋ค.
- App request
- Event trigger
- Power
- Performance
- Privacy
- User expects immediate completion
- Protect completion
- Protect by using Background Task Completion
- Start based on user action
Gives app additional time to run in the background before being suspended
UIApplication.beginBackgroundTask(expirationHandler:)
ProcessInfo.performExpiringActivity(withReason:using:)
Complete work started in the foreground
- Saving files to disk, completing user-initiated requests
// Guarding Important Tasks while App is Still in the Foreground
func send(_ message: Message) {
var sendOperation = SendOperation(message: message)
var identifier: UIBackgroundTaskIdentifier!
identifier = UIApplication.shared.beginBackgroundTask(expirationHandler: {
sendOperation.cancel()
postUserNotification("Message not sent, please resend")
// Background task will be ended in the operation's completion block below
})
sendOperation.completionBlock = {
UIApplication.shared.endBackgroundTask(identifier)
}
operationQueue.addOperation(sendOperation)
}
- VoIP push notificatons
- Special type of push that launches your app
func registerForVoIPPushes() {
self.voipRegistry = PKPushRegistry(queue: nil)
self.voipRegistry.delegate = self
self.voipRegistry.desiredPushTypes = [.voIP]
}
- Must report incoming call with CallKit in
didReceiveIncomingPush
callback - If not, system may stop launching your app for VoIP pushes
let provider = CXProvider(configuration: providerConfiguration)
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
if type == .voIP {
if let handle = payload.dictionaryPayload["handle"] as? String {
let callUpdate = CXCallUpdate()
callUpdate.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
let callUUID = UUID()
provider.reportNewIncomingCall(with: callUUID, update: callUpdate) { _ in
completion()
}
establishConnection(for: callUUID)
}
}
}
- Other tips
- Caller info in push payload
- Set
apns-expiration
on push to0
or something small - Prefer a banner? Use standard pushes
- Notification Service Extension to modify content
-
Many different threads
-
User may not want alerts for specific thread
-
Message content may be relevant
-
Alert device, not user
-
Use background push as best effort way to download content
-
Can always download when app re-enters foreground
-
Mechanism to tell device new data is available without alerting user
-
Send push with
"content-available: 1"
without"alert"
,"sound"
, or"badge"
-
System intelligently decides when to launch app to download content
-
Must set
apns-priority = 5
or app will not launch -
Should set
apns-push-type = background
- User signs into account
- Download conversation list, recent messages immediately
- Defer download of older content
- Defer work if possible to minimize user-visible impact
- Same principles to any deferrable download or upload
- Batching analytics uploads
- Photos
-
Allows the system to defer the download until a better time
-
Provide information to system for smarter scheduling
// Set up background URL session let config = URLSessionConfiguration.background(withIdentifier: "com.app.attachments") let session = URLSession(configuration: config, delegate: ..., delegateQueue: ...) // Set discretionary config.discretionary = true // Set timeout intervals config.timeoutIntervalForResource = 24 * 60 * 60 config.timeOutIntervalForRequest = 60 // Create request and task var request = URLRequest(url: url) request.addValue("...", forHTTPHeaderField: "...") let task = session.downloadTask(with: request) // Set time window task.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60 * 60) // Set workload size task.countOfBytesClientExpectsToSend = 160 task.countOfBytesClientExpectsToReceive = 4096 task.resume()
BackgroundTasks๊ฐ ์คํ๋๋ ์์ ์กฐ์
- A new framework for scheduling background work
- Available on iOS, iPadOS, tvOS, and iPad Apps on Mac
- Several minutes of runtime at system-friendly times
- Deferrable maintenance work
- Core ML training/inference
- Can turn off CPU Monitoring for intensive work
- Eligible if requested in foreground or if app has been recently used
-
New API, same policies
- 30 seconds of runtime
- Keep app up-to-date throughout the day
-
Eligibility based on usage patterns
-
Old UIApplication fetch API is deprecated, and not supported on Mac
UIApplication.setMinimumBackgroundFetchInterval(_:) UIApplicationDelegate.application(_:performFetchWithCompletionHandler:)
- Don't set
earliestBeginDate
too far into the future - Ensure files are accessible while device is locked
FileProtectionType.completeUntilFirstUserAuthentication
- UIScene apps should call
UIApplication.requestSceneSessionRefresh(_:)
- Consider calling
BGTaskScheduler.submit(_:)
on a background queue if submitting at launch
- Be conscientious when running in the background
- Use the right background mode for the job
- Schedule deferrable work with BackgroundTasks
BackgroundTasks์ ๋ํ ๊ฒฝํ์ด ๊ฑฐ์ ์ ๋ฌดํ๋ค ๋ณด๋ ์ดํด์ ์ข ๋ถ์กฑํจ์ด ์๋ ๊ฒ ๊ฐ๋ค. ๋ฌธ์๋ ์์ ์ฝ๋๋ฅผ ๋ค์ ์ดํด๋ณผ ํ์๊ฐ ์๋ค.