Background Refresh: Keeping Your App Updated and Responsive

Background app refresh

Background app refresh is a powerful feature in iOS that allows your app to periodically fetch new data and update its content even when it's not actively running in the foreground. This functionality enhances the user experience by ensuring users see the latest information upon to your app.

There are certain important points to consider when refreshing the app in the background.

  • Resource Management: iOS carefully manages app execution in the background to conserve battery life. Background app refresh provides a controlled way for apps to perform essential tasks without significantly impacting battery or network resources.
  • Opportunistic Execution: The system initiates Background app refresh events at opportune moments based on various factors like network connectivity, device charging status, and user app usage patters. This ensures efficient background execution.
  • Limited Time Window: Background app refresh events grant apps a limited window of execution, which typically takes around 30 seconds to complete their refresh tasks. This necessitates efficient code and network calls.

Enabling Background app refresh

1. Capabilities Configuration

  • Open your project in XCode and navigate to Project Settings > Capabilities.
  • Under Background Modes, enable the Background fetch capability.

2. AppDelegate Setup

  • Open your AppDelegate.Swift file and implement the application(_: application:,didFinishLaunchingWithOptions:) method:
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
            BackgroundAppScheduler.shared.registerBackgroundRefreshTask()
            return true
    }
    
    //BackgroundAppScheduler class code
    
    import Foundation
    import BackgroundTasks
    
    class BackgroundAppScheduler  {
        
        static let shared = BackgroundAppScheduler()
        
    //MARK: Task Refresh
    func registerBackgroundRefreshTask() {
            // Register handler for task
            BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.appRefresh.BackgroundAppRefresh.refresh", using: nil) { bgTask in
                //handle the task when its run
                guard let task = bgTask as? BGAppRefreshTask else { return }
                self.handleAppRefreshTask(task: task, completion: {
                    task.setTaskCompleted(success: true) // Call completion after all work is done
                })
            }
    }
    
    private func handleAppRefreshTask(task:BGAppRefreshTask,completion: @escaping () -> Void){
            scheduleAppRefreshTask()
            //Server API implementation
            task.expirationHandler = {
                //Cancel network call
            }
            //After completion, you can set this method
            task.setTaskCompleted(success: true)
    
    }
    
    func scheduleAppRefreshTask(){
            //You can test App refresh implementaiton in debug mode just run that command.
            //e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:"com.appRefresh.BackgroundAppRefresh.refresh"]
            BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: "com.appRefresh.BackgroundAppRefresh.refresh")
            BGTaskScheduler.shared.getPendingTaskRequests { requests in
                guard requests.isEmpty else{ return }
                //Submit a task to be scheduled
                do {
                    let newTask = BGAppRefreshTaskRequest(identifier: "com.appRefresh.BackgroundAppRefresh.refresh")
                    newTask.earliestBeginDate = Date(timeIntervalSinceNow: 1*60)
                    try BGTaskScheduler.shared.submit(newTask)
                } catch {
                    // Handle any errors that occur during submission
                    print("Error scheduling background task: \(error)")
                }
            }
        }
        
    }

I have created a separate class called 'BackgroundAppScheduler' where I register the app's Background Task.

  • Open your AppDelegate.Swift file and implement the application(_: performFetchWithCompletionHandler:) method.

Best Practices and Considerations

  • Prioritize Network Efficiency: Use lightweight network protocols(e.g. JSON) and focus on fetching only essential data. Compress data if possible.
  • Minimize CPU Usage: Avoid overly complex processing or long-running tasks during background app refresh. If necessary, consider scheduling more extensive work for a later time in the foreground.
  • Respect User Opt-In: Users have control over the Background app refresh in Settings. Handle scenarios where Background app refresh might be disabled on their device.
  • Test Thoroughly: XCode provides options to sumulate Background app refresh events. Validate that your implementation functions correctly and does't drain battery excessively.

Note. While Background app refresh offers a convenient way to keep data up-to-date, it's not guaranteed that the system will trigger it at specific time intervals. Consider alternate approaches like silent push notifications to keep data up-to-date.


Similar Articles