Notification Payload — 什么是通知负载,JSON结构与解析

作者: IT Sectr 发布日期: 2026-03-20 阅读时间: 10 分钟

Notification Payload — 是服务器通过APNS发送到iOS设备的JSON结构,定义推送通知的内容及其接收时的行为。负载包含必需和可选的键,用于控制文本、声音、badge、媒体附件和后台处理。根据Apple Developer Documentation, 2026负载的最大大小对于普通通知为4096字节,对于VoIP推送为5120字节,这对传输的数据量施加了严格的限制。

要点

  • aps结构 — 包含alert、badge、sound和content-available键的必需字典,定义了通知的视觉和声音行为。
  • 大小限制 — APNS负载的最大大小为4096字节,VoIP推送为5120字节,更大的负载将被Apple服务器拒绝。
  • 自定义字段 — 任何附加数据在与aps相同的级别传输,并在收到通知后在userInfo中可用。
  • alert本地化 — title-loc-key、loc-key和loc-args键允许显示本地化文本,而无需为每种语言发送不同的负载。
  • Request-identifier — APNS响应中的自定义标识符,用于跟踪传递状态和来自Apple服务器的回调。

什么是Notification Payload

Notification Payload(通知负载)— 是服务器发送到APNS(Apple推送通知服务)以传递到iOS设备的JSON对象。负载包含系统显示通知所需的所有数据:标题、文本、声音、badge和用于后台处理的元数据。负载结构由Apple严格规定,并包含系统正确处理所需的必需键。

负载在推送传递中的作用

当服务器通过HTTP/2 API APNS发送推送通知时,请求包含授权标头和JSON正文(负载)。APNS检查负载的有效性:如果JSON不正确或超出大小限制,Apple服务器将返回400 Bad Request错误。验证后,APNS将负载传递到设备,iOS系统解析负载并确定如何处理通知 — 显示横幅、启动后台任务或播放声音。

负载格式的演变

APNS负载格式从iOS 2中的简单文本负载演变为现代版本中的多组件JSON结构。iOS 10通过mutable-content带来了对媒体附件的支持,iOS 12通过thread-id添加了通知分组,iOS 15引入了supports-live-activities以支持Live Activities。如今,根据通知所需的行为,负载最多可以包含15个不同的键。

APNS负载结构:必需和可选键

负载的根对象包含aps字典和顶层的可选自定义字段。aps字典是唯一的必需元素,但在其内部,根据通知类型可以出现不同的键组合:alert、badge、sound、content-available、mutable-content、interruption-level等。

aps键类型用途
alertString或Dictionary通知文本或包含title、subtitle、body、本地化的对象
badgeNumber应用程序图标上的数字;0删除badge
soundString音频文件名或default表示系统声音
content-availableNumber (1)后台激活标志;1 = silent push
mutable-contentNumber (1)激活Service Extension以修改内容的标志
categoryString用于按钮和Content Extension的类别标识符
thread-idString用于通知分组的组标识符
interruption-levelString中断级别:passive、active、time-sensitive、critical
relevance-scoreNumber (0–1)通知对智能排名系统的优先级

alert键:字符串和字典格式

alert键可以是简单字符串(成为通知正文)或包含title、subtitle、body字段的字典。字典格式允许将标题和副标题与主文本分开设置。对于本地化通知,使用title-loc-key、title-loc-args、loc-key、loc-args键,它们引用应用程序的Localizable.strings。这允许发送没有特定语言文本的负载 — 应用程序会自动替换翻译。

中断管理:interruption-level和relevance-score

从iOS 15开始,Apple添加了Focus Mode机制,要求开发者指定通知的中断级别。interruption-level接受以下值:passive(无声音、不唤醒屏幕)、active(标准行为)、time-sensitive(穿透焦点,需要特殊授权)和critical(医疗/紧急情况)。relevance-score(0–1)键帮助Focus系统对同一类别内的通知进行排序。

通过thread-id进行通知分组

thread-id键将通知分组到Notification Center中的组。所有具有相同thread-id的通知显示为一个组,用户可以展开。这对于消息应用尤其有用,其中来自同一联系人的消息被分组在一起,或者对于发送许多相同类型通知的应用。

自定义字段和数据传输

自定义字段 — 是开发人员为向设备传输附加数据而添加的aps字典之外的任何键。服务器将它们包含在负载的根JSON对象中,应用程序通过UNNotificationContent中的userInfo接收它们。自定义字段不应重复aps中的键名,以避免解析时的冲突。

自定义数据的限制

主要限制 — 负载的总大小不应超过4096字节。自定义字段与必需的aps键竞争此限制,因此最小化传输数据的大小很重要。使用短的键名(例如,用uid代替user-id),避免大型JSON结构,并仅传输标识符,而不是完整的数据对象。

自定义字段的安全性和验证

自定义字段来自服务器,未经检查不应信任。始终验证解析时自定义字段的类型和值:通过optional binding检查键是否存在,使用as? String/Int/Dictionary转换为期望的类型,并处理值缺失的情况。切勿对来自负载的数据使用force unwrap (!) — 服务器可能发送不正确的数据,应用程序将崩溃。

json
{
    "aps": {
        "alert": {
            "title": "新消息",
            "body": "你好!最近怎么样?"
        },
        "badge": 5,
        "sound": "default",
        "category": "message",
        "thread-id": "chat_4521",
        "mutable-content": 1
    },
    "sender-id": "user_789",
    "chat-id": "chat_4521",
    "message-type": "text",
    "image-url": "https://cdn.example.com/img.jpg"
}

自定义字段命名建议

在项目的所有负载中使用统一的命名风格。kebab-case(message-type)或camelCase(messageType)— 两种方法都可以接受,但重要的是在项目范围内遵循一种。避免长名称:用uid代替user-identifier,用img代替profile-image-url。键名中的每个字符都是4096限制中的一个字节。

不同类型通知的负载示例

不同的场景推送通知需要负载中不同的键组合。让我们看几个典型示例:简单文本通知、本地化通知、Silent Push和带媒体附件的Rich Notification。

简单文本通知

带文本和声音的基本负载 — 向用户显示通知的最小配置。作为字符串的alert提供简短消息,sound default播放标准系统声音。Badge是可选的,在图标上设置计数器。category和thread-id用于分组和交互性。

json
{
    "aps": {
        "alert": "提醒:会议在15分钟后",
        "badge": 3,
        "sound": "default"
    }
}

本地化通知

要发送到不同语言的设备,使用本地化键而不是固定文本。title-loc-key引用应用程序Localizable.strings中的键,title-loc-args替换参数。这允许向所有设备发送一个负载,应用程序以相应语言显示文本。

json
{
    "aps": {
        "alert": {
            "title-loc-key": "NEW_MESSAGE_TITLE",
            "title-loc-args": ["安娜"],
            "loc-key": "NEW_MESSAGE_BODY",
            "loc-args": ["你好!"]
        },
        "sound": "message.caf"
    }
}

带后台同步的Silent Push

对于不显示通知的后台同步,使用content-available: 1和没有alert。自定义字段指示操作类型和要处理的数据。系统在后台激活应用程序,调用带fetchCompletionHandler的didReceiveRemoteNotification,应用程序执行同步。

json
{
    "aps": {
        "content-available": 1
    },
    "sync-type": "invalidate-cache",
    "timestamp": "2026-07-03T12:00:00Z"
}

带图片的Rich Notification

要显示媒体附件,需要mutable-content: 1来激活Service Extension和自定义字段中的图片URL。mutable-content: 1向系统发出信号启动UNNotificationServiceExtension,它将从URL下载图片并作为UNNotificationAttachment添加。category指向注册的类别以显示操作按钮。

json
{
    "aps": {
        "alert": {
            "title": "新产品",
            "body": "查看新系列"
        },
        "category": "product",
        "mutable-content": 1
    },
    "media-url": "https://cdn.example.com/product.jpg"
}

应用程序中负载的处理和解析

UNNotificationContent.userInfo包含系统处理后收到的负载的完整字典。应用程序在UNUserNotificationCenter委托中收到通知时(在前台)、点击通知时以及在Service Extension和Content Extension中访问负载。正确的解析对于提取自定义数据和确定后续操作是必需的。

点击通知时在AppDelegate中解析

当用户点击通知时,系统调用UNUserNotificationCenterDelegate中的didReceive response方法。在response.notification.request.content.userInfo中包含完整负载。开发者提取自定义字段,确定操作类型(例如,打开聊天、转到产品),并在应用程序中调用相应的导航。

swift
func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
) {
    let userInfo = response.notification
        .request.content.userInfo

    guard let chatId = userInfo["chat-id"] as? String
    else {
        completionHandler()
        return
    }

    let messageType = userInfo["message-type"]
        as? String ?? "text"

    NavigationRouter.shared.navigate(
        to: .chat(chatId: chatId,
                  messageType: messageType))
    completionHandler()
}

Service Extension中的负载验证

Service Extension在通知显示前接收负载并可以修改它。负载验证 — didReceive中的第一步:检查必需的自定义字段是否存在、附件URL的正确性和数据类型。如果负载无效,立即使用原始内容调用completion handler,不要浪费时间进行无用的处理。

负载的日志记录和监控

为了在生产中调试推送通知,使用负载的结构化日志记录。OSLog允许以类别notifications和debug级别记录负载。在服务器端,跟踪APNS响应:成功响应包含apns-id以匹配发送的负载,错误400指示无效JSON或超出大小。

常见问题

APNS负载的最大大小是多少?

负载的最大大小 — 普通推送通知为4096字节,VoIP推送(PushKit)为5120字节。超出时,APNS返回400 Bad Request错误。大小以字节计算,而不是字符 — 请考虑UTF-8编码。

如何发送多语言本地化通知?

在alert中使用loc-key、title-loc-key、loc-args和title-loc-args键。应用程序根据设备语言从其自己的Localizable.strings中替换翻译。这允许向所有设备发送一个负载,无论其语言如何。

content-available和mutable-content有什么区别?

content-available在后台激活应用程序进行数据处理(silent push),不显示通知。mutable-content激活Service Extension以在显示前修改内容。两个键可以一起使用,用于后台处理和后续的通知修改。

如何检查服务器发送了正确的负载?

使用APNS Sandbox进行测试,并检查Apple服务器的HTTP响应:200 OK表示成功发送。对于结构验证,在CI/CD pipeline中使用JSON模式。在Xcode中,通过模拟器使用命令xcrun simctl push发送测试通知。

Apple服务器响应中的apns-id是什么?

apns-id — APNS系统中推送通知的唯一标识符,在成功发送的响应中返回。用于通过Logs API跟踪传递和调试。服务器应为每个发送的通知保存apns-id。

总结

  • Notification Payload — 带有必需aps字典的推送通知JSON结构,定义文本、声音、badge和后台处理。
  • 大小限制 — APNS为4096字节,VoIP为5120字节;超出将返回来自Apple服务器的400 Bad Request错误。
  • aps字典包含alert、badge、sound、content-available、mutable-content、category、thread-id、interruption-level和relevance-score键。
  • 自定义字段在aps之外传输并通过userInfo提取;解析时始终验证类型和值。
  • 本地化通过loc-key和title-loc-key实现,它们引用应用程序的Localizable.strings以替换翻译。
  • interruption-level管理Focus模式下的通知行为:passive、active、time-sensitive或critical。
  • Notification Payload — 整个推送通知系统的基础,其正确性决定了设备上每个通知的传递、显示和处理。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读