0

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)
    }
}
HangarRash
  • 7,314
  • 5
  • 5
  • 32
CodeMan
  • 1
  • 2
  • Your comment "Start task 3 seconds from now" suggests a misunderstanding. This is not when the task will start. That is the **earliest** the task will start. It's not promised to ever start, but it won't start earlier than you request in `earliestBeginDate`. You seem to be trying to poll a server on a set schedule? That's impossible. The server needs to send a push notification when there is new data. – Rob Napier Aug 16 '23 at 18:59
  • I'm going to mark this as a dupe for now. If you believe you have a different question, please update your question to be more precise how what you're asking is different, what behavior you expect to see (and why), and what behavior you actually see. We can reopen it if it isn't really a dupe. – Rob Napier Aug 16 '23 at 19:01

0 Answers0