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 |1 Answer
Reset to default 0Based 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.
mutable-content: 1
is in the incorrect position. Can you share the full payload? – sonle Commented 23 hours ago