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

iOS Swift5:APP终止时无法接收带图片的远程推送通知

iOS 终止状态下无法接收带图片的APNs通知问题解决

问题现象

APP处于前台时可正常接收带图片的通知,但完全终止(退出后台)后无法收到通知,已实现Notification Service Extension和Notification Content Extension。

核心原因

  1. 推送Payload缺少mutable-content:1:终止状态下系统不会唤醒主APP,必须依赖Notification Service Extension处理富媒体,而只有当payload包含mutable-content:1时,系统才会触发Extension。
  2. 主APP冗余逻辑无效:AppDelegate中的didReceiveRemoteNotification和processNotificationContent在终止状态下不会触发,这些创建本地通知的逻辑仅在前台有效,无法覆盖终止场景。
  3. Extension代码存在疏漏:未处理系统超时场景、未明确指定文件类型,可能导致Extension处理失败后无通知展示。

解决方案

1. 修正推送Payload结构

确保推送的aps字典中包含mutable-content:1,示例如下:

{
  "aps": {
    "alert": {
      "title": "通知标题",
      "body": "通知内容"
    },
    "sound": "default",
    "mutable-content": 1
  },
  "notificationMediaUrl": "https://your-image-url.com/image.jpg"
}

2. 检查Notification Service Extension配置

  • 确保Extension的Bundle ID为主APP Bundle ID + 后缀(如com.yourapp.NotificationService)
  • 确认Extension的签名配置与主APP一致(使用相同Team ID)
  • 检查Extension的Info.plist配置是否正确:
<key>NSExtension</key>
<dict>
  <key>NSExtensionAttributes</key>
  <dict>
    <key>UNNotificationExtensionCategory</key>
    <string>notificationWithMedia</string>
    <key>UNNotificationExtensionInitialContentSizeRatio</key>
    <real>0.5</real>
  </dict>
  <key>NSExtensionPointIdentifier</key>
  <string>com.apple.usernotifications.service</string>
  <key>NSExtensionPrincipalClass</key>
  <string>$(PRODUCT_MODULE_NAME).NotificationService</string>
</dict>

3. 修正Extension代码(处理超时与文件类型)

import UserNotifications
import MobileCoreServices
import UniformTypeIdentifiers

class NotificationService: UNNotificationServiceExtension {

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

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        guard let bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) else {
            contentHandler(request.content)
            return
        }

        guard let mediaUrlString = bestAttemptContent.userInfo["notificationMediaUrl"] as? String,
              let mediaUrl = URL(string: mediaUrlString) else {
            contentHandler(bestAttemptContent)
            return
        }

        downloadImage(from: mediaUrl) { [weak self] attachment in
            guard let self = self else { return }
            if let attachment = attachment {
                bestAttemptContent.attachments = [attachment]
            }
            contentHandler(bestAttemptContent)
        }
    }

    // 处理系统超时场景,避免无通知展示
    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }

    private func downloadImage(from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) {
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data, error == nil else {
                completion(nil)
                return
            }

            let temporaryDirectory = FileManager.default.temporaryDirectory
            let fileURL = temporaryDirectory.appendingPathComponent("\(UUID().uuidString).jpg")

            do {
                try data.write(to: fileURL)
                // 明确指定文件类型,避免系统识别错误
                let options: [UNNotificationAttachmentOptionsKey: Any] = [
                    .typeHint: UTType.jpeg.identifier
                ]
                let attachment = try UNNotificationAttachment(identifier: UUID().uuidString, url: fileURL, options: options)
                completion(attachment)
            } catch {
                print("创建图片附件失败: \(error)")
                completion(nil)
            }
        }.resume()
    }
}

4. 精简主APP逻辑(移除冗余代码)

删除AppDelegate中didReceiveRemoteNotification里创建本地通知的逻辑,同时简化willPresent方法:

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    // 直接展示通知,Extension已处理图片
    completionHandler([.alert, .sound, .badge])
}

测试步骤

  1. 完全退出APP(从后台滑动删除)
  2. 发送包含mutable-content:1的推送
  3. 查看Xcode控制台,确认Extension的didReceive方法被调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:24:52