$30 off During Our Annual Pro Sale. View Details »

Apps in the Background

Apps in the Background

When building an app, a lot of focus and effort is put on crafting the best foreground experience for users. However, our apps also have a hidden life when we move them the background. And the system watchdog is here to make sure they all behave! In this talk, you will learn what the common pitfalls of background execution are, how you can make sure you don’t exceed system resources by applying best practices, and finally, how to optimize network requests when your app is not in the foreground.

Alexis Aubry

April 29, 2019
Tweet

Other Decks in Programming

Transcript

  1. Apps in the Background
    The secret life of apps when you minimize them.
    Alexis Aubry — App Builders 2019

    @_alexaubry

    View Slide

  2. Delivering a good UX means
    More than a foreground experience

    View Slide

  3. Our Plan
    How do we provide the best experience to our users even when they
    don’t interact with the app?
    1. What does it mean to be in the background?

    2. What are the common problems and how to detect them?

    3. How can we fix these issues and improve the UX?

    View Slide

  4. What does it mean to
    be in the background?

    View Slide

  5. Possible States
    Minimized App Push Notification Background Refresh

    View Slide

  6. Moving to the Background
    applicationWillResignActive(_:)
    UI Snapshot Suspended
    applicationDidEnterBackground(_:)

    View Slide

  7. Handling Background Events
    UI Snapshot
    Process the events
    applicationDidEnterBackground(_:)
    Launch if needed
    Suspended

    View Slide

  8. How to identify issues?

    View Slide

  9. Common Exception Codes
    • 0x8badf00d = took too long to respond to a system event
    • 0xdead10cc = forgot to release a file lock after suspension
    • 0xc51bad01 = CPU usage too high in the background

    • 0xc51bad02 = took too long to move to the background
    • 0xc51bad03 = system resources too low to continue
    • 0xbada5e47 = exceeded the limit of background tasks

    View Slide

  10. Other Symptoms
    • Missing data or expected event not happening
    • Example: taking too long to process a push payload.

    • Routinely check your crash reports for the aforementioned codes.

    View Slide

  11. Other Symptoms
    • Unexpectedly high battery usage

    • If you take a lot of time to process events, but stay under the limit, the
    system will probably not terminate your app.

    • Example: you can spend 20 seconds for each push notification, under
    the limit, but will have an impact on user’s battery.

    • At Wire: reduced background activity by 5 hours a week.

    View Slide

  12. What are the techniques for the
    best background experience?

    View Slide

  13. Use background tasks
    1

    View Slide

  14. ✅ Get more time to complete
    your background work

    View Slide

  15. How it Works
    UIApplication
    Your Code

    View Slide

  16. Starting a Task
    beginBackgroundTask
    Your Code
    Expiration Handler

    View Slide

  17. Starting a Task
    beginBackgroundTask
    Your Code
    Expiration Handler

    View Slide

  18. Starting a Task
    beginBackgroundTask
    Your Code
    Expiration Handler
    Task Identifier

    View Slide

  19. Check for Expiration
    beginBackgroundTask
    Your Code
    Expiration Handler
    .invalid

    View Slide

  20. Performing your work
    UIApplication
    Task Identifier Expiration Handler
    Async Queue
    Your Background Work

    View Slide

  21. Finishing your work
    endBackgroundTask
    Your Code
    Expiration Handler
    Task Identifier

    View Slide

  22. Expiring Properly
    endBackgroundTask
    Your Code
    Expiration Handler
    Task Identifier

    View Slide

  23. For App Extensions
    ProcessInfo.processInfo.performExpiringActivity(withReason: "Request") {
    [weak self] expiring in
    guard let self = self else { return }
    if expiring {
    // Clean up your code before suspension
    self.currentRequest?.cancel()
    } else {
    // Otherwise perform the task
    let request = self.networkingLayer.createRequest()
    self.currentRequest = request
    request.resume()
    }
    }

    View Slide

  24. When to Use It
    • Every time interrupting the work would be detrimental to the UX
    • Example: when sending a message or saving a file.

    • When operating in the foreground
    • Example: asking for extra time to send a message before going in the
    background, so you don’t need to care about the state of the app.

    • Caveat: having too many active background tasks can cause a crash

    View Slide

  25. How to Optimize It
    • Give names to tasks when creating them.

    • Create all your tasks from a single thread.

    • Centralize the tasks creation inside one object.

    View Slide

  26. Benefits of a Task Manager
    • Manages a single background task to keep the app awake.

    • Avoids repeated overhead of creating background tasks.

    • Avoids issues with gaps between tasks.

    • Avoids issues with needing to create tasks from multiple threads.

    View Slide

  27. Building a Task Manager
    BackgroundTasksManager UIKit
    Your
    Code

    View Slide

  28. Building a Task Manager
    beginBackgroundTask UIKit
    Your
    Code

    View Slide

  29. Building a Task Manager
    BackgroundTasksManager
    Begin task
    with UIKit
    Your
    Code
    No Internal Background Task

    View Slide

  30. Building a Task Manager
    BackgroundTasksManager
    Save the
    token of the
    custom task
    When we have an Internal Background Task
    UIKit

    View Slide

  31. Building a Task Manager
    endBackgroundTask UIKit
    Your
    Code
    After ending your work

    View Slide

  32. Building a Task Manager
    When there are no more active tasks
    BackgroundTasksManager
    End the
    internal task
    Your
    Code

    View Slide

  33. Building a Task Manager
    BackgroundTasksManager
    Expire all
    active tasks
    When the extended lifetime expires
    UIKit
    expiration
    callback

    View Slide

  34. Building a Task Manager
    BackgroundTasksManager
    End the
    internal task
    Your
    Code
    When the extended lifetime expires

    View Slide

  35. Building a Task Manager
    BackgroundTasksManager
    Expire
    immediately
    When creating tasks while the app is expiring
    UIKit cannot
    start a real
    task

    View Slide

  36. Implementation on GitHub
    github.com/alexaubry/background-tasks-manager

    View Slide

  37. Keep your memory usage
    under control
    2

    View Slide

  38. Reducing Memory Usage
    • Makes the system more likely to keep your app suspended for a longer
    period of time.

    • Example: Use a purgeable cache with a disk counterpart.

    • Example: Reduce your use of images.

    • Recommended Reads
    • https://developer.apple.com/library/archive/technotes/tn2434/_index.html

    • http://www.thomashanning.com/building-memory-efficient-apps/

    View Slide

  39. Use the right API for the
    right task
    3

    View Slide

  40. Using the Right API
    • Processing notifications in the background?

    • Use a notification service extension.
    • Downloading files in the background?

    • Use a background URLSession with sessionSendsLaunchEvents.
    • https://developer.apple.com/documentation/foundation/
    url_loading_system/downloading_files_in_the_background

    View Slide

  41. Design for immediately
    cancellable tasks and restoration
    4

    View Slide

  42. “Apps must be prepared for

    termination to happen at any time.”

    View Slide

  43. Architecture Tips
    • Don’t wait for the user to close the app to save data.

    • Make every task cancellable, so that you can stop them during expiration.

    • Design background behavior with UX in mind.

    • Example: if we cancel sending a message, how do we communicate
    that to the user?

    View Slide

  44. What should happen if we cancel a
    running task? Is it recoverable? Does it
    need user interaction to recover?

    View Slide

  45. Wrapping Up
    • Different scenarios, different rules.

    • Comply to stay frozen in the background as long as possible.

    • Look for the signs to detect potential bottlenecks.

    • Use background tasks as often and efficiently as possible.

    • Use the latest APIs and tools to optimize background work.

    • Design for immediately cancellable tasks, think about the UX.

    View Slide

  46. Thank you!
    Questions? Tweet me @_alexaubry

    View Slide