2

Quick overview over the problem:

Clicking run the app selecting the notification extension target, files within the notification are debugged normally, function just as expected. However when I run the app selecting the main app target, the same files are not debugged and my own functions are not being called, except that the didReceive() function does its work by modifying the notification content as expect in all cases. bellow you will find a function called apiCall(), the function is called and an api call is performed normally when running the app from the notification extension target, however it is not called when running from the main target.

Solutions not to think about:

  • mutable-content: 1 is available otherwise content won't be modified.
  • NotificationExtension is available inside the Target dependencies under Build phases section of the main target,
  • All used libraries are under Link Binary With Libraries under Build phases section of the notification extension target.
  • Background Modes: Background fetch, Remote notifications are already checked in capabilities
  • don't look for a code problem since in works when building from the extension target.

My notification extension code:

class NotificationService: UNNotificationServiceExtension, UNUserNotificationCenterDelegate {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            
            ...
            
            bestAttemptContent.title = "[modified]"
            bestAttemptContent.body = "[modified]"

            DispatchQueue.main.asyncAfter(deadline: .now() + 30){
                apiCall()
            }
            
            contentHandler(bestAttemptContent)
        }
    }
    
    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {

            contentHandler(bestAttemptContent)
        }
    }
}
HangarRash
  • 7,314
  • 5
  • 5
  • 32
  • It might be working when run from the extension scheme because Xcode is keeping the process alive longer. Your code has several paths where it will never call the completion handler and some where it will be called twice. Once you call the completion handler, iOS could kill your extension and that could happen before the 5 second delay before you make your API call. – Geoff Hackworth Apr 26 '23 at 13:50
  • It looks like you are trying to automatically reject a trip if the user doesn’t explicitly accept or reject the notification with an action. But I think trying to make the notification extension the delegate of the Notification Centre is very risky. The extension could be killed as soon as the notification has been modified, the callback called and the notification is displayed. – Geoff Hackworth Apr 26 '23 at 14:00
  • ignore the `serviceExtensionTimeWillExpire()` function, it is never called. it is supposed to run when the notification is about to expire (apx 30sec) but for some reason it is not. when running the extension scheme the api call is called even with 30 sec delay. – raouf Mehdid Apr 26 '23 at 14:00
  • Yes, `serviceExtensionTimeWillExpire` will not be called because you call the completion handler just after setting up the dispatch work item to run in 5 seconds time. The point I am trying to make is that your extension process might be killed before those 5 seconds have passed. – Geoff Hackworth Apr 26 '23 at 14:02
  • what do you suggest as edit to make that happen. I am trying to achieve just what you said, let's say the delay originally is 30 sec (5 just for debugging). – raouf Mehdid Apr 26 '23 at 14:04
  • I don’t think it is possible to do what you want because you have no control over when iOS will kill your process once you have called the content handler. The notification won’t appear until you call the handler so you cannot delay that. I think the only reason it works when debugging the extension target directly is because the act of debugging is keeping the process alive. I could be wrong, so let’s see if other people add any comments. – Geoff Hackworth Apr 26 '23 at 14:14
  • I would appreciate an upvote to reach some audience. – raouf Mehdid Apr 26 '23 at 14:18

0 Answers0