iOS Notification Service Extension with multiple targets never calls extension methods

3.8k views Asked by At

I'm currently trying to use a Notification Service Extension as a workaround for an app that doesn't obtain a valid badge count in the push notification payload. To fix this I figured I would create a Notification Service Extension that keeps track of the amount of messages that have been received and that will keep track of the count accordingly. I got this working last week now I continued on it and it doesn't work at all anymore and I'm clueless as to why this is.

The Notification Service Extension bundle id is being changed according to the target. This pre-build script looks like this for the 2 targets I have

buildID=${PRODUCT_BUNDLE_IDENTIFIER}
extId="AppPushNotification"

/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $buildID.$extId" "${SRCROOT}/${extId}/Info.plist"

The code I'm using in my extension

import UIKit
import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    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 {
            // Modify the notification content here...
            let userDefaults = UserDefaults.init(suiteName: "group.com.my.bundle.notification-service-extension")
            let unreadMessages = userDefaults?.integer(forKey: "unreadMessages")
            let newUnreadMessages = unreadMessages != nil ? unreadMessages! + 1 : 0

            bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
            bestAttemptContent.badge = NSNumber(value: newUnreadMessages)
            let userInfo = bestAttemptContent.userInfo
            guard let info = userInfo["aps"] as? [AnyHashable: Any],
                let data = info["data"] as? [AnyHashable: Any],
                let chatId = data["chatId"] as? String else { return }

            let unreadMessagesInChat = userDefaults?.integer(forKey: chatId)
            let newUnreadMessagesInChat = unreadMessagesInChat != nil ? unreadMessagesInChat! + 1 : 0

            userDefaults?.set(newUnreadMessages, forKey: "unreadMessages")
            userDefaults?.set(newUnreadMessagesInChat, forKey: chatId)


            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)
        }
    }

}

I'm pushing my test notification payload by using Pusher. The payload I'm sending:

{
   "aps":{
      "mutalbe-content":1,
      "content-available":1,
      "sound":"true",
      "alert":{
         "title":"Vera Pauw",
         "body":"test bericht"
      },
      "data":{
         "type":"test",
         "message":"test bericht",
         "chatId":"3b002aa6-1117-4206-b54f-8bc2bd689f1c",
         "fromId":"",
         "fromname":"Vera Pauw"
      }
   }
}

I get the notification successfully but it doesn't trigger the extensions code ever. I've tried debugging in multiple ways, like selecting the debug target after running the app, or running the app from the extension target but the process of the Notification Service will always say Waiting to Attach. I've tried playing around with my push notification payload but this didn't change the result.

Does anyone have any idea why this is happening or where I'm going wrong.

1

There are 1 answers

1
quellish On BEST ANSWER

Your notification payload is definitely part of the problem. In your question the payload is:

{
   "aps":{
      "mutalbe-content":1,
      "content-available":1,
      "sound":"true",
      "alert":{
         "title":"Vera Pauw",
         "body":"test bericht"
      },
      "data":{
         "type":"test",
         "message":"test bericht",
         "chatId":"3b002aa6-1117-4206-b54f-8bc2bd689f1c",
         "fromId":"",
         "fromname":"Vera Pauw"
      }
   }
}

The aps key should only contain Apple's keys. Your data dictionary should be outside the aps key.

The "content-available" should not be present if the alert, button, or sound keys are there - a notification can not be both silent and user-facing. content-available is only for silent notifications.

The "mutalbe-content" key is also misspelled, which is why your extension is not being activated!

I see many people having the same issues so I wrote a simple push notification validation tool you can use to troubleshoot these problems.

Depending on what you are trying to accomplish a corrected payload might look like this:

{
   "aps":{
      "mutable-content":1,
      "alert":{
         "title":"Vera Pauw",
         "body":"test bericht"
      }
   },
  "data":{
     "type":"test",
     "message":"test bericht",
     "chatId":"3b002aa6-1117-4206-b54f-8bc2bd689f1c",
     "fromId":"",
     "fromname":"Vera Pauw"
  }
}

Try that and see if the extension launches.