最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

swift - Image Push Notification Not Displaying in iOS with Notification Service Extension - Stack Overflow

programmeradmin4浏览0评论

I'm currently working on implementing image push notifications in my iOS app using a Notification Service Extension, but the image is not displaying in the notification. Below are the details of my implementation:

import UIKit
import Flutter
import GoogleMaps
import Firebase
import FirebaseMessaging

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
      
      FirebaseApp.configure()
      UNUserNotificationCenter.current().delegate = self
      if #available(iOS 12.0, *) {
          UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
              print("Permission granted: \(granted)")
          }
      }
      application.registerForRemoteNotifications()
      GeneratedPluginRegistrant.register(with: self)
      return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

NotificationService:

import UserNotifications
import os.log

class NotificationService: UNNotificationServiceExtension {
    
    private var contentHandler: ((UNNotificationContent) -> Void)?
    private var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        os_log("Entered didReceive method.", log: .default, type: .info)
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        defer {
            os_log("Completing content handler.", log: .default, type: .info)
            contentHandler(bestAttemptContent ?? request.content)
        }

        guard let attachment = request.attachment else {
            os_log("Attachment not found.", log: .default, type: .error)
            return
        }

        os_log("Attachment found: %@", log: .default, type: .info, attachment.identifier)
        bestAttemptContent?.attachments = [attachment]
    }
    
    override func serviceExtensionTimeWillExpire() {
        os_log("Service extension time will expire.", log: .default, type: .info)
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

extension UNNotificationRequest {
    var attachment: UNNotificationAttachment? {
        os_log("Attempting to fetch image URL from payload.", log: .default, type: .info)
        guard let attachmentURL = content.userInfo["image_url"] as? String else {
            os_log("Image URL not found in payload.", log: .default, type: .error)
            return nil
        }

        let encodedURLString = attachmentURL.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        os_log("Original URL: %@", log: .default, type: .info, attachmentURL)
        os_log("Encoded URL: %@", log: .default, type: .info, encodedURLString ?? "nil")

        guard let encodedURL = URL(string: encodedURLString ?? ""), let imageData = try? Data(contentsOf: encodedURL) else {
            os_log("Failed to create URL from encoded string.", log: .default, type: .error)
            return nil
        }

        os_log("Creating attachment with fetched image data.", log: .default, type: .info)
        return try? UNNotificationAttachment(data: imageData, options: nil)
    }
}

extension UNNotificationAttachment {

    convenience init(data: Data, options: [NSObject: AnyObject]?) throws {
        let fileManager = FileManager.default
        let temporaryFolderName = ProcessInfo.processInfo.globallyUniqueString
        let temporaryFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(temporaryFolderName, isDirectory: true)

        try fileManager.createDirectory(at: temporaryFolderURL, withIntermediateDirectories: true, attributes: nil)
        let imageFileIdentifier = UUID().uuidString + ".jpg"
        let fileURL = temporaryFolderURL.appendingPathComponent(imageFileIdentifier)
        try data.write(to: fileURL)
        os_log("Image data written to file: %@", log: .default, type: .info, fileURL.absoluteString)
        try self.init(identifier: imageFileIdentifier, url: fileURL, options: options)
    }
}

info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

playload has mutable-content: 1,

Despite the above configurations, the image is not appearing in the notification. I've ensured the image URL is accessible and correctly formatted. Any assistance or insights on resolving this issue would be greatly appreciated.

I'm currently working on implementing image push notifications in my iOS app using a Notification Service Extension, but the image is not displaying in the notification. Below are the details of my implementation:

import UIKit
import Flutter
import GoogleMaps
import Firebase
import FirebaseMessaging

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
      
      FirebaseApp.configure()
      UNUserNotificationCenter.current().delegate = self
      if #available(iOS 12.0, *) {
          UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
              print("Permission granted: \(granted)")
          }
      }
      application.registerForRemoteNotifications()
      GeneratedPluginRegistrant.register(with: self)
      return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

NotificationService:

import UserNotifications
import os.log

class NotificationService: UNNotificationServiceExtension {
    
    private var contentHandler: ((UNNotificationContent) -> Void)?
    private var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        os_log("Entered didReceive method.", log: .default, type: .info)
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        defer {
            os_log("Completing content handler.", log: .default, type: .info)
            contentHandler(bestAttemptContent ?? request.content)
        }

        guard let attachment = request.attachment else {
            os_log("Attachment not found.", log: .default, type: .error)
            return
        }

        os_log("Attachment found: %@", log: .default, type: .info, attachment.identifier)
        bestAttemptContent?.attachments = [attachment]
    }
    
    override func serviceExtensionTimeWillExpire() {
        os_log("Service extension time will expire.", log: .default, type: .info)
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

extension UNNotificationRequest {
    var attachment: UNNotificationAttachment? {
        os_log("Attempting to fetch image URL from payload.", log: .default, type: .info)
        guard let attachmentURL = content.userInfo["image_url"] as? String else {
            os_log("Image URL not found in payload.", log: .default, type: .error)
            return nil
        }

        let encodedURLString = attachmentURL.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        os_log("Original URL: %@", log: .default, type: .info, attachmentURL)
        os_log("Encoded URL: %@", log: .default, type: .info, encodedURLString ?? "nil")

        guard let encodedURL = URL(string: encodedURLString ?? ""), let imageData = try? Data(contentsOf: encodedURL) else {
            os_log("Failed to create URL from encoded string.", log: .default, type: .error)
            return nil
        }

        os_log("Creating attachment with fetched image data.", log: .default, type: .info)
        return try? UNNotificationAttachment(data: imageData, options: nil)
    }
}

extension UNNotificationAttachment {

    convenience init(data: Data, options: [NSObject: AnyObject]?) throws {
        let fileManager = FileManager.default
        let temporaryFolderName = ProcessInfo.processInfo.globallyUniqueString
        let temporaryFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(temporaryFolderName, isDirectory: true)

        try fileManager.createDirectory(at: temporaryFolderURL, withIntermediateDirectories: true, attributes: nil)
        let imageFileIdentifier = UUID().uuidString + ".jpg"
        let fileURL = temporaryFolderURL.appendingPathComponent(imageFileIdentifier)
        try data.write(to: fileURL)
        os_log("Image data written to file: %@", log: .default, type: .info, fileURL.absoluteString)
        try self.init(identifier: imageFileIdentifier, url: fileURL, options: options)
    }
}

info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

playload has mutable-content: 1,

Despite the above configurations, the image is not appearing in the notification. I've ensured the image URL is accessible and correctly formatted. Any assistance or insights on resolving this issue would be greatly appreciated.

Share Improve this question edited 21 hours ago WhisperingWinds asked yesterday WhisperingWindsWhisperingWinds 751 silver badge14 bronze badges 4
  • What was the output log you received? – sonle Commented 23 hours ago
  • NotificationService is installed properly but I didn't get any logs, it not entered didReceive function, – WhisperingWinds Commented 23 hours ago
  • Hmm, I'm thinking about mutable-content: 1 is in the incorrect position. Can you share the full payload? – sonle Commented 23 hours ago
  • { "to": "e6Y5o-PcRjS2PQA608K-4p:APA91bHTaFL661B2PBv4cUKji46ccZXSsW0vE4haL-LdnuLqGsr97JvH7srMaSpTydT3zuirvPhxNaliwM0QAEfsKwa8YuTeenyIN9eIuMV5AAjhPaMr2z4", "priority": "high", "content_available": true, "mutable_content": true, "notification": { "title": "test", "body": "test", "image": "dwo18kpwgy0rw.cloudfront/media/push messages/None_employer_19-02-2025-165923.jpg" }, "data": { This is the payload. – WhisperingWinds Commented 18 hours ago
Add a comment  | 

1 Answer 1

Reset to default 0

Based on your comment above, I believe your payload format is incorrect. So, that is why the system does not trigger Notification Extension -> there are no logs at all. The following are mandatory:

The payload must include the mutable-content key with a value of 1.

The payload must include an alert dictionary with title, subtitle, or body information.

You may take a look at this documentation. The remote notification payload should be something like:

{
  "aps" {
    "mutable-content": 1,
    "alert": ...
  }
  "data": ...     //<- your data
  "to": ...       //<- your data
  "priority": ... //<- your data
}

There is a tool for testing this without exporting any APNs .p8 key or certificate. Check it out at Apple Console. Simply get the device token from your app and then paste it at this site.

发布评论

评论列表(0)

  1. 暂无评论