I wrote a function that checks if any notifications are added in the array and whenever notifications are added, it triggers a push notification function. It is executing fine in foreground but not in background or when app closes. In background modes, I added Background Fetch, Remote Notifications and Background processing. Could anyone suggest a better approach or correction in my approach
In the Info.plist, I added permitted background task identifier, "com.showfa.fetchNotifications. I wrote the fetchNotification function, the app delegate and imported BackgroundTasks framework. It is working as it is supposed to in foreground but doesn't work in background or when app closes. The function is as follows:
func fetchNotifications() {
guard let url = URL(string: "http://example.com") else {
return
}
var request = URLRequest(url: url)
request.setValue(accessTkn, forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, _, error in
if let error = error {
print("Error fetching data: \(error)")
return
}
if let data = data {
do {
let decoder = JSONDecoder()
let fetchedNotifications = try decoder.decode([Notification].self, from: data)
DispatchQueue.main.async {
self.notifications = fetchedNotifications
if let decodedNotifications = self.loadNotificationsFromUserDefaults() {
let newValue = self.notifications.filter { newNoti in
!decodedNotifications.contains { newData in
newNoti.message == newData.message
}
}
if newValue.isEmpty {
print("1")
} else {
for newNoti in newValue {
self.notiCat = newNoti.category
self.notiMess = newNoti.message
self.sendPushNotificationIfNeeded(category: self.notiCat, message: self.notiMess)
}
}
} else {
print("E1")
}
// Save notifications to UserDefaults
self.saveNotificationsToUserDefaults(notifications: self.notifications)
}
} catch {
print("Error decoding data: \(error)")
}
}
}.resume()
}
the app delegate is as follows:
@main
struct CabsPointApp: App {
let persistenceController = PersistenceController.shared
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
init() {
// Request background task processing identifier
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.showfa.fetchNotifications", using: nil) { task in
if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let appRefreshTask = task as? BGAppRefreshTask {
appDelegate.handleAppRefreshTask(task: appRefreshTask)
}
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var notificationViewModel = NotificationViewModel()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Notification authorization granted")
} else {
print("Notification authorization denied")
}
}
scheduleBackgroundTask()
return true
}
}
extension AppDelegate {
// Handle notification when the app is in the foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
// Handle notification when the user taps on it
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
// Handle the user's action here
completionHandler()
}
func scheduleBackgroundTask() {
let request = BGAppRefreshTaskRequest(identifier: "com.showfa.fetchNotifications")
request.earliestBeginDate = Date(timeIntervalSinceNow: 3 * 1) // Start task 3 seconds from now
do {
try BGTaskScheduler.shared.submit(request)
print("Scheduled background task for fetching notifications")
} catch {
print("Unable to schedule background task: \(error)")
}
}
func handleAppRefreshTask(task: BGAppRefreshTask) {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
let operation = BlockOperation {
self.notificationViewModel.startBackgroundTask()
self.scheduleBackgroundTask()
task.setTaskCompleted(success: true)
}
queue.addOperation(operation)
}
}