I am struggling to implement a background refresh feature in App with regular refresh interval. I thought I follow all the necessary steps but the refresh function has never been called.
Can you please check and let me know if there anything I missed out.
Xcode : 12.4
iOS : 14.3 on iPhone 11 Pro Device
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
print("sceneDidEnterBackground")
(UIApplication.shared.delegate as! AppDelegate).cancelAllPandingBGTask()
(UIApplication.shared.delegate as! AppDelegate).scheduleAppRefresh()
}
4. AppDelegate.swift
import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application( application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("application")
registerBackgroundTaks()
return true
}
func applicationDidEnterBackground( application: UIApplication) {
print("applicationDidEnterBackground")
cancelAllPandingBGTask()
scheduleAppRefresh()
}
private func registerBackgroundTaks() {
print("registerBackgroundTaks")
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.SO.apprefresh", using: nil) { task in
//This task is cast with processing request (BGAppRefreshTask)
self.handleAppRefreshTask(task: task as! BGAppRefreshTask)
}
}
// MARK: UISceneSession Lifecycle
func application( application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
extension AppDelegate {
func cancelAllPandingBGTask() {
BGTaskScheduler.shared.cancelAllTaskRequests()
}
func scheduleAppRefresh() {
print("scheduleAppRefresh")
let request = BGAppRefreshTaskRequest(identifier: "com.SO.apprefresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 1 * 60) // App Refresh after 2 minute.
//Note :: EarliestBeginDate should not be set to too far into the future.
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
func handleAppRefreshTask(task: BGAppRefreshTask) {
print("handleAppRefreshTask")
//Todo Work
/*
//AppRefresh Process
*/
task.expirationHandler = {
//This Block call by System
//Canle your all tak's & queues
}
//
task.setTaskCompleted(success: true)
}
}
Can you please check and let me know if there anything I missed out.
Xcode : 12.4
iOS : 14.3 on iPhone 11 Pro Device
Added "Background Modes" under "Sign and Capabilities" (Checked - background refresh and background processing)
Added "Permitted background task scheduler identifiers" in Info.plist.
SceneDelegate.swift
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
print("sceneDidEnterBackground")
(UIApplication.shared.delegate as! AppDelegate).cancelAllPandingBGTask()
(UIApplication.shared.delegate as! AppDelegate).scheduleAppRefresh()
}
4. AppDelegate.swift
import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application( application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("application")
registerBackgroundTaks()
return true
}
func applicationDidEnterBackground( application: UIApplication) {
print("applicationDidEnterBackground")
cancelAllPandingBGTask()
scheduleAppRefresh()
}
private func registerBackgroundTaks() {
print("registerBackgroundTaks")
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.SO.apprefresh", using: nil) { task in
//This task is cast with processing request (BGAppRefreshTask)
self.handleAppRefreshTask(task: task as! BGAppRefreshTask)
}
}
// MARK: UISceneSession Lifecycle
func application( application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
extension AppDelegate {
func cancelAllPandingBGTask() {
BGTaskScheduler.shared.cancelAllTaskRequests()
}
func scheduleAppRefresh() {
print("scheduleAppRefresh")
let request = BGAppRefreshTaskRequest(identifier: "com.SO.apprefresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 1 * 60) // App Refresh after 2 minute.
//Note :: EarliestBeginDate should not be set to too far into the future.
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
func handleAppRefreshTask(task: BGAppRefreshTask) {
print("handleAppRefreshTask")
//Todo Work
/*
//AppRefresh Process
*/
task.expirationHandler = {
//This Block call by System
//Canle your all tak's & queues
}
//
task.setTaskCompleted(success: true)
}
}