Background Tasks and time running in background

Our application allows people to back up their content (Photos / Videos) into the cloud. To have our backup working more efficiently while the application is in background, we have implemented background tasks. We schedule refresh and processing task (BGProcessingTask). Processing task is used for uploading content. We are looking into improving the number of triggers for processing tasks. There are one or two triggers in 24 hours but not as frequently as we expected. We did an exercise to compare google photo v/s our application: the time google gets to execute in background is 6 times more than personal cloud. What are the possible reason for this difference. 

See some sample code below.

We were lucky to have an appointment for a tech talk with @George V. from Apple and he suggested to use BGProcessingTask and set a flag to defer those tasks to run at a time where the device was less used. We do work with BGProcessingTask and are using the flags request.requiresNetworkConnectivity and request.requiresExternalPower.

Where it's not clear for me is: would setting requiresExternalPower to true prevent our app to run in background while the device is not plugged?

Any guidance would be appreciated :) Maybe @George, if you're available. Thanks

import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        registerBgTasks()
        //registerBatteryBgTasks()
        return true
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    }

    func registerBgTasks() {
        BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.photos-upload",
                                           using: nil) { (task) in
            self.handleProcessingTask(task: task as! BGProcessingTask)
        }
    }

    func registerBatteryBgTasks() {
        BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.photos-upload-power",
                                           using: nil) { (task) in
            self.handlePowerProcessingTask(task: task as! BGProcessingTask)
        }
    }
    func handlePowerProcessingTask(task: BGProcessingTask) {
        let startTime = Date()
        let taskId = task.identifier
        if let url = URL(string: "https://imaging.nikon.com/lineup/dslr/df/sample.htm") {
            let session = URLSession.shared
            let networkTask = session.dataTask(with: url) { data, _, _ in
            }
            networkTask.resume()
        }

        task.expirationHandler = {
            let endTime = Date()
            let diffComponents = Calendar.current.dateComponents([.second], from: startTime, to: endTime)
            let taskEntry = TaskEntry(taskId: taskId, taskLaunchedTime: DateUtility.readableDate(date: startTime),
                                      taskExpirationTime: DateUtility.readableDate(date: endTime),
                                      taskTotalTime: "\(diffComponents.second ?? 0)")
            let fileName = "\(Date().timeIntervalSince1970)power.plist"
            APIPreferencesLoaderPower.write(preferences: TaskArray(tasks: [taskEntry]), fileName: fileName)
            task.setTaskCompleted(success: true)
        }
    }

    func handleProcessingTask(task: BGProcessingTask) {
        let startTime = Date()
        let taskId = task.identifier
        if let url = URL(string: "https://imaging.nikon.com/lineup/dslr/df/sample.htm") {
            let session = URLSession.shared
            let networkTask = session.dataTask(with: url) { data, _, _ in
            }
            networkTask.resume()
        }

        task.expirationHandler = {
            let endTime = Date()
            let diffComponents = Calendar.current.dateComponents([.second], from: startTime, to: endTime)
            let taskEntry = TaskEntry(taskId: taskId, taskLaunchedTime: DateUtility.readableDate(date: startTime),
                                      taskExpirationTime: DateUtility.readableDate(date: endTime),
                                      taskTotalTime: "\(diffComponents.second ?? 0)")
            let fileName = "\(Date().timeIntervalSince1970)normal.plist"
            APIPreferencesLoader.write(preferences: TaskArray(tasks: [taskEntry]), fileName: fileName)
            task.setTaskCompleted(success: true)
        }
    }
}

other class:

func scheduleBgTask() {
        let request = BGProcessingTaskRequest(identifier: "com.synchronoss.cloud.photos-upload")
        request.requiresNetworkConnectivity = true
        request.requiresExternalPower = false
        do {
            try BGTaskScheduler.shared.submit(request)
        } catch {
            print("error")
        }
    }

    func schedulePowerBgTask() {
        let request = BGProcessingTaskRequest(identifier: "com.synchronoss.cloud.photos-upload-power")
        request.requiresNetworkConnectivity = true
        request.requiresExternalPower = true
        do {
            try BGTaskScheduler.shared.submit(request)
        } catch {
            print("error")
        }
    }

Replies

Check out this video and it will give you a better understanding. Especially the first 5 minutes https://developer.apple.com/videos/play/wwdc2020/10063.

  • Yes! Highly recommended.

Add a Comment

thank you for your answers. back on nearly the same topic: @eskimo we are using BGProcessingTask and NSURLSession with URLSessionConfiguration.background(withIdentifier:) for our uploads. the system will split the time allocated to our app to run in the background between BGProcessingTask and NSURL Session or will it consider time allocated for those 2 separately?

  • in the video shared above, it seems that the system will treat NSURL session with background configuration separately from BGProcessingTask but I wanted to confirm with you.

Add a Comment

the system will treat NSURLSession with background configuration separately from BGProcessingTask

That’s correct. These are completely separate subsystems for getting stuff done in the background.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"