You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS端FCM推送通知图片不显示问题排查求助

带图片的FCM推送通知在iOS上无法显示的问题排查与解决

问题背景

我在iOS应用中使用Firebase Cloud Messaging (FCM)实现带图片的推送通知,已创建自定义NotificationServiceExtension处理图片下载与附件添加,但通知中的图片始终无法显示。

现有代码

NotificationService.swift

import UIKit
import UserNotifications
import FirebaseMessaging

class NotificationService: UNNotificationServiceExtension {
    private var contentHandler: ((UNNotificationContent) -> Void)?
    private var bestAttemptContent: UNMutableNotificationContent?
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        defer {
            contentHandler(bestAttemptContent ?? request.content)
        }
        
        guard let attachment = request.attachment else {
            return
        }
        
        bestAttemptContent?.attachments = [attachment]
    }
    
    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

extension UNNotificationRequest {
    var attachment: UNNotificationAttachment? {
        guard let attachmentURL = content.userInfo["image"] as? String,
              let imageData = try? Data(contentsOf: URL(string: attachmentURL)!) else {
            return nil
        }
        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)
        try self.init(identifier: imageFileIdentifier, url: fileURL, options: options)
    }
}

FCM服务器端Payload

message = messaging.Message(
    data=convert_to_firebase_compatible(data),
    token=registration_id,
    android=messaging.AndroidConfig(
        priority='high',
        ttl=ttl
    ),
    notification=messaging.Notification(
        title=data.get('title', 'ABC'),
        body=data.get('message', ''),
        image=data.get('image_url', '')
    ),
    apns=messaging.APNSConfig(
        headers={
            'apns-priority': '10',
        },
        payload=messaging.APNSPayload(
            aps=messaging.Aps(
                sound='default',
                mutable_content='1'
            ),
        ),
        fcm_options=messaging.APNSFCMOptions(
            image=data.get('image_url', '')
        )
    ),
)

问题现象

  • iOS设备能正常收到通知,但图片无法显示
  • 已确认userInfo中的图片URL有效且可直接访问

已执行的排查步骤

  • 添加了NotificationServiceExtension用于处理图片附件
  • 验证Payload中的image_url正确且可访问
  • 确认Payload中mutable_content已设置为"1"

疑问

  1. 配置NotificationServiceExtension处理图片时是否遗漏了关键步骤?
  2. 用于iOS通知图片的FCM Payload结构是否正确?
  3. 是否还需要额外配置APNs或FCM以支持通知图片?

解决方案

1. 修正Payload字段映射问题

你的UNNotificationRequest扩展中从userInfo["image"]获取图片URL,但当前Payload里iOS端的图片URL放在apns.fcm_options.image,FCM会将该字段映射到userInfo["gcm.image"]而非image。需要修改扩展的字段获取逻辑:

var attachment: UNNotificationAttachment? {
    guard let attachmentURL = content.userInfo["gcm.image"] as? String,
          let url = URL(string: attachmentURL) else {
        print("无效的图片URL")
        return nil
    }
    
    do {
        let imageData = try Data(contentsOf: url)
        return try UNNotificationAttachment(data: imageData, options: nil)
    } catch {
        print("加载图片或创建附件失败:\(error)")
        return nil
    }
}

也可以直接在data参数中添加"image": data.get('image_url', ''),让图片URL直接出现在userInfo["image"]中。

2. 修复NotificationService的语法与错误处理

  • 补上bestAttemptContent赋值语句后的分号,避免潜在语法问题:
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
  • 替换try?为显式错误处理,方便排查问题,如上述代码中的打印逻辑。

3. 修正Payload参数类型

FCM的messaging.Aps接受布尔值而非字符串,将mutable_content改为布尔值:

aps=messaging.Aps(
    sound='default',
    mutable_content=True
),

4. 检查扩展配置

  • 确认NotificationServiceExtension的Target签名与主应用一致,且在扩展的Capabilities中开启了Push Notifications权限。
  • 必须使用真机测试,模拟器无法正确处理通知附件。

内容的提问来源于stack exchange,提问作者WhisperingWinds

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 09:47:24