Search code examples
iosswiftapple-push-notifications

Remote communication notifications not working iOS 18


I'm trying to make communication notifications work with the remote push notifications I have set up, specifically so that I can get user avatars to appear in the notification. I have successfully set up a Notification Service Extension for my app, which I've verified works (breakpoints hit in the NotificationService class, and I'm able to modify the title), and by following guide, I end up with this code:

override func didReceive(
  _ request: UNNotificationRequest,
  withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
  self.contentHandler = contentHandler
  bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

  if let bestAttemptContent {
    contentHandler(bestAttemptContent)
  }

  let personHandle = INPersonHandle(value: "senderID", type: .unknown)
  let person = INPerson(
    personHandle: personHandle,
    nameComponents: .init(givenName: "senderName", familyName: "family name"),
    displayName: "senderName",
    image: nil,
    contactIdentifier: nil,
    customIdentifier: "some-unique-id"
  )

  let intent = INSendMessageIntent(
    recipients: nil,
    outgoingMessageType: .outgoingMessageText,
    content: "some content",
    speakableGroupName: nil,
    conversationIdentifier: "unique-user-id-conv",
    serviceName: nil,
    sender: person,
    attachments: nil
  )

  let interaction = INInteraction(intent: intent, response: nil)
  interaction.direction = .incoming
  interaction.donate(completion: nil)

  do {
    let updatedContent = try request.content.updating(from: intent)
    let mutableBestAttemptContent = (updatedContent.mutableCopy() as? UNMutableNotificationContent)!
    mutableBestAttemptContent.userInfo = request.content.userInfo

    contentHandler(mutableBestAttemptContent)

  } catch {

  }
}

When I receive a notification, this code runs and I've verified with breakpoints that contentHandler(mutableBestAttemptContent) is called and that the intent is donated without an error.

For now, I've omitted adding an image, as I want to first get a minimal example working where the name of the person is displayed (though I have also tested this with a hardcoded INImage(url: validURL) without success), but this code is not working.

Additionally, I have the following:

  1. The Notification Service Extension Info.plist file contains the following:
<dict>
    <key>NSExtension</key>
    <dict>
        <key>NSExtensionAttributes</key>
        <dict>
            <key>IntentsSupported</key>
            <array>
                <string>INSendMessageIntent</string>
            </array>
        </dict>
        ...
    </dict>
</dict>
  1. The main app target has the following in its Info.plist
<dict>
    <key>NSUserActivityTypes</key>
    <array>
        <string>INSendMessageIntent</string>
    </array>
    ...
</dict>
  1. The "Communication Notifications" capability is added in the main app target, as well as "Push Notifications", "Background Modes" (with "Remote Notifications" checked), and "Siri".
  2. May be irrelevant but I saw somewhere that the bundle ID of the service extension must be prefixed with the bundle ID of the main app target, which is also the case.

I'm at a bit of a loss for why this is not working, and there's shockingly little documentation on this matter, so I'm not even sure how to approach debugging this. Anyone have any ideas?


Solution

  • It seems you accidentally left in some of the auto generated code in your source, so contentHandler is always being called immediately. It should work if you remove the first block of code calling it

      if let bestAttemptContent {
        contentHandler(bestAttemptContent) // REMOVE this if statement
      }