iOS Rich notifications from FCM in foreground using Notification Service Extension

414 views Asked by At

I'm trying to implement rich notifications in our React Native app, using firebase. Rich notifs are not yet supported by react native so I had to use a mix of swift, in my NotificationServiceExtension, and Objective C, in my AppDelegate.m. I'm not experienced in either of those. The rich notifications show correctly if the app is in the background or closed, but they don't if the app is in the foreground even though I always get them (using a breakpoint). The weird part is that sometimes they do...

class NotificationService: UNNotificationServiceExtension {
  var contentHandler: ((UNNotificationContent) -> Void)?
  var bestAttemptContent: UNMutableNotificationContent?
  override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    let title = request.content.title
    let subtitle = request.content.subtitle
    let body = request.content.body
    self.contentHandler = contentHandler
    bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
    guard let bestAttemptContent = bestAttemptContent,
      let attachmentURLAsString = bestAttemptContent.userInfo["image"] as? String,
      let attachmentURL = URL(string: attachmentURLAsString) else {
        return
    }
    downloadImageFrom(url: attachmentURL, title: title, subtitle: subtitle, body: body) { (attachment) in
      if let attachment = attachment {
        bestAttemptContent.attachments = [attachment]
        contentHandler(bestAttemptContent)
      }
    }
  }
  private func downloadImageFrom(url: URL, title: String, subtitle: String, body: String, with completionHandler: @escaping (UNNotificationAttachment?) -> Void) {
    let task = URLSession.shared.downloadTask(with: url) { (downloadedUrl, response, error) in
      guard let downloadedUrl = downloadedUrl else {
        completionHandler(nil)
        return
      }
      var urlPath = URL(fileURLWithPath: NSTemporaryDirectory())
      let uniqueURLEnding = ProcessInfo.processInfo.globallyUniqueString + ".png"
      urlPath = urlPath.appendingPathComponent(uniqueURLEnding)
      try? FileManager.default.moveItem(at: downloadedUrl, to: urlPath)
      let notificationContent = UNMutableNotificationContent()
      notificationContent.title = title
      notificationContent.subtitle = subtitle
      notificationContent.body = body
      notificationContent.sound = UNNotificationSound.default
      notificationContent.badge = 0
      do {
        let attachment = try UNNotificationAttachment(identifier: "notifImg", url: urlPath, options: nil)
        notificationContent.attachments = [attachment]
        let request = UNNotificationRequest(identifier: "notif",
                                            content: notificationContent,
                                            trigger: nil)
        UNUserNotificationCenter.current().add(request) { (error) in
          completionHandler(attachment)
        }
        completionHandler(attachment)
      } catch {
        completionHandler(nil)
      }
    }
    task.resume()
  }
  override func serviceExtensionTimeWillExpire() {
    if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
      contentHandler(bestAttemptContent)
    }
  }
}

I got this code from the many articles that I read. The approval request for notifications is in AppDelegate.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
  [application registerUserNotificationSettings:
  [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | 
    UIUserNotificationTypeSound | UIUserNotificationTypeAlert)
                                    categories:nil]];
  [application registerForRemoteNotifications];
...
}

I'm sending the notifications using https://fcm.googleapis.com/fcm/send like this:

{
    "notification": {
        "mutable_content": true,
        "title": "title",
        "body": "body"
    },
    "to" : "__token__",
    "data": {
        "image": "https://ilyarm.ru/assets/949163b5edd92aa1ec0379734-697x403.jpg"
    }
}

Could someone guide me or share some articles? Thank you very much!

0

There are 0 answers