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

Flutter iOS端Firebase Messaging推送图片不显示问题求助

Flutter iOS Firebase推送图片不显示:Notification Service Extension配置方案

一、Swift版Notification Service Extension配置步骤

    1. 添加Extension目标:打开Xcode主项目,点击顶部菜单栏File > Target > Notification Service Extension,命名(如NotificationService),语言选择Swift,完成创建。
    1. 配置Pod依赖:在项目根目录的Podfile中新增Extension的Target块,添加Firebase Messaging依赖:
target 'NotificationService' do
  use_frameworks!
  pod 'Firebase/Messaging'
end

执行终端命令pod install,确保依赖安装完成。

    1. 替换Extension核心代码:打开NotificationService.swift,替换默认代码为以下内容,实现图片下载与附件添加逻辑:
import UserNotifications
import FirebaseMessaging

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        guard let bestAttemptContent = bestAttemptContent else {
            contentHandler(request.content)
            return
        }
        
        // 从推送payload中获取图片URL(key可根据实际自定义)
        guard let imageURLString = bestAttemptContent.userInfo["image"] as? String,
              let imageURL = URL(string: imageURLString) else {
            contentHandler(bestAttemptContent)
            return
        }
        
        // 下载图片并添加为通知附件
        downloadAttachment(from: imageURL) { attachment in
            if let attachment = attachment {
                bestAttemptContent.attachments = [attachment]
            }
            contentHandler(bestAttemptContent)
        }
    }
    
    override func serviceExtensionTimeWillExpire() {
        // 超时场景下返回原始通知内容
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
    
    private func downloadAttachment(from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) {
        let task = URLSession.shared.downloadTask(with: url) { tempURL, _, error in
            guard let tempURL = tempURL, error == nil else {
                completion(nil)
                return
            }
            
            let fileManager = FileManager.default
            let tempDir = NSTemporaryDirectory()
            let fileName = url.lastPathComponent
            let destinationURL = URL(fileURLWithPath: tempDir).appendingPathComponent(fileName)
            
            do {
                // 清理已存在的旧文件
                if fileManager.fileExists(atPath: destinationURL.path) {
                    try fileManager.removeItem(at: destinationURL)
                }
                try fileManager.copyItem(at: tempURL, to: destinationURL)
                
                // 创建通知附件
                let attachment = try UNNotificationAttachment(identifier: "", url: destinationURL, options: nil)
                completion(attachment)
            } catch {
                completion(nil)
            }
        }
        task.resume()
    }
}
    1. 配置Extension的Info.plist:确保NSExtension节点下的NSExtensionAttributes包含以下配置(用于通知展开显示):
    • 添加键UNNotificationExtensionInitialContentSizeRatio,值设为0.5(可根据需求调整)
    • 可选:添加键UNNotificationExtensionCategory,值与推送payload中的category字段对应
    1. 推送Payload格式要求:必须包含mutable-content: 1(开启通知可修改权限),并携带图片URL字段,示例:
{
  "aps": {
    "alert": {
      "title": "测试图片推送",
      "body": "这是一条带图片的通知"
    },
    "mutable-content": 1
  },
  "image": "https://example.com/your-image.jpg"
}

二、Objective-C版报错修复方案

若选择Objective-C语言创建Extension后出现编译/链接报错,按以下步骤修复:

    1. 配置Pod依赖:同样在Podfile中为Extension Target添加Firebase依赖:
target 'NotificationService' do
  use_frameworks!
  pod 'Firebase/Messaging'
end

执行pod install后,重新打开项目。

    1. 替换Extension核心代码:打开NotificationService.m,替换为以下代码:
#import "NotificationService.h"
#import <FirebaseMessaging/FirebaseMessaging.h>
#import <UserNotifications/UserNotifications.h>

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    // 解析推送中的图片URL
    NSString *imageURLString = self.bestAttemptContent.userInfo[@"image"];
    if (imageURLString && imageURLString.length > 0) {
        NSURL *imageURL = [NSURL URLWithString:imageURLString];
        [self downloadAttachmentFromURL:imageURL completion:^(UNNotificationAttachment *attachment) {
            if (attachment) {
                self.bestAttemptContent.attachments = @[attachment];
            }
            self.contentHandler(self.bestAttemptContent);
        }];
    } else {
        self.contentHandler(self.bestAttemptContent);
    }
}

- (void)serviceExtensionTimeWillExpire {
    self.contentHandler(self.bestAttemptContent);
}

- (void)downloadAttachmentFromURL:(NSURL *)url completion:(void (^)(UNNotificationAttachment *))completion {
    NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithURL:url completionHandler:^(NSURL *tempFileURL, NSURLResponse *response, NSError *error) {
        if (error || !tempFileURL) {
            completion(nil);
            return;
        }
        
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSString *tempDir = NSTemporaryDirectory();
        NSString *fileName = url.lastPathComponent;
        NSURL *destinationURL = [NSURL fileURLWithPath:[tempDir stringByAppendingPathComponent:fileName]];
        
        NSError *fileError;
        if ([fileManager fileExistsAtPath:destinationURL.path]) {
            [fileManager removeItemAtURL:destinationURL error:&fileError];
        }
        [fileManager copyItemAtURL:tempFileURL toURL:destinationURL error:&fileError];
        
        if (fileError) {
            completion(nil);
            return;
        }
        
        NSError *attachmentError;
        UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:destinationURL options:nil error:&attachmentError];
        completion(attachment);
    }];
    [task resume];
}

@end
    1. 排查编译错误:若出现头文件找不到,检查Extension Target的Build Settings > Framework Search Paths是否包含Pods/Headers/Public路径;若出现链接错误,添加Other Linker Flags为-ObjC。
    1. 推送Payload要求与Swift版一致,必须包含mutable-content:1和图片URL字段。

内容的提问来源于stack exchange,提问作者Sulaymon Ne'matov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:06:22