Notification Payload là một cấu trúc JSON mà máy chủ gửi qua APNS đến thiết bị iOS, xác định nội dung của thông báo push và hành vi khi nhận được nó. Payload bao gồm các key bắt buộc và tùy chọn kiểm soát văn bản, âm thanh, huy hiệu, tập tin đính kèm phương tiện và xử lý nền. Theo Apple Developer Documentation, 2026, kích thước payload tối đa là 4096 byte cho thông báo thông thường và 5120 byte cho VoIP push, áp đặt giới hạn nghiêm ngặt về lượng dữ liệu truyền tải.
Điểm Chính
Notification Payload là một đối tượng JSON mà máy chủ gửi đến APNS (Apple Push Notification Service) để chuyển đến thiết bị iOS. Payload chứa tất cả dữ liệu hệ thống cần để hiển thị thông báo: tiêu đề, văn bản, âm thanh, huy hiệu và siêu dữ liệu cho xử lý nền. Cấu trúc payload được Apple quy định nghiêm ngặt và bao gồm các key bắt buộc để hệ thống xử lý chính xác.
Khi máy chủ gửi thông báo push qua APNS HTTP/2 API, yêu cầu chứa header ủy quyền và phần thân JSON — payload. APNS xác thực payload: nếu JSON không hợp lệ hoặc vượt quá giới hạn kích thước, máy chủ Apple trả về lỗi 400 Bad Request. Sau khi xác thực, APNS chuyển payload đến thiết bị, nơi iOS phân tích nó và xác định cách xử lý thông báo — hiển thị banner, chạy tác vụ nền hoặc phát âm thanh.
Định dạng payload APNS đã phát triển từ một payload văn bản đơn giản trong iOS 2 thành cấu trúc JSON nhiều thành phần trong các phiên bản hiện đại. iOS 10 đã giới thiệu hỗ trợ tập tin đính kèm phương tiện qua mutable-content, iOS 12 thêm tính năng nhóm thông báo qua thread-id, và iOS 15 giới thiệu supports-live-activities cho Live Activities. Ngày nay, một payload có thể chứa tới 15 key khác nhau tùy thuộc vào hành vi thông báo mong muốn.
Đối tượng gốc của payload chứa một từ điển aps và các trường tùy chỉnh tùy chọn ở cấp cao nhất. Từ điển aps là phần tử bắt buộc duy nhất, nhưng bên trong nó có thể xuất hiện nhiều tổ hợp key khác nhau tùy thuộc vào loại thông báo: alert, badge, sound, content-available, mutable-content, interruption-level và các key khác.
| Key aps | Loại | Mục đích |
|---|---|---|
| alert | String hoặc Dictionary | Văn bản thông báo hoặc đối tượng có title, subtitle, body và bản địa hóa |
| badge | Number | Số trên biểu tượng ứng dụng; 0 xóa huy hiệu |
| sound | String | Tên tệp âm thanh hoặc default cho âm thanh hệ thống |
| content-available | Number (1) | Cờ kích hoạt nền; 1 = push ẩn |
| mutable-content | Number (1) | Cờ kích hoạt Service Extension để sửa đổi nội dung |
| category | String | Định danh danh mục cho nút và Content Extension |
| thread-id | String | Định danh nhóm để nhóm thông báo |
| interruption-level | String | Mức độ gián đoạn: passive, active, time-sensitive, critical |
| relevance-score | Number (0–1) | Ưu tiên thông báo cho hệ thống xếp hạng thông minh |
Key alert có thể là một chuỗi đơn giản (trở thành nội dung thông báo) hoặc một từ điển với các trường title, subtitle, body. Định dạng từ điển cho phép đặt tiêu đề và phụ đề riêng biệt với văn bản chính. Đối với thông báo đã địa phương hóa, các key title-loc-key, title-loc-args, loc-key và loc-args được sử dụng, tham chiếu đến Localizable.strings của ứng dụng. Điều này cho phép gửi một payload mà không có văn bản ngôn ngữ cụ thể — ứng dụng thay thế bản dịch.
Bắt đầu từ iOS 15, Apple đã giới thiệu cơ chế Focus Mode, yêu cầu nhà phát triển chỉ định mức độ gián đoạn của thông báo. interruption-level chấp nhận các giá trị: passive (không âm thanh, không đánh thức màn hình), active (hành vi tiêu chuẩn), time-sensitive (xuyên qua Focus, yêu cầu ủy quyền đặc biệt) và critical (tình huống y tế/khẩn cấp). Key relevance-score (0–1) giúp hệ thống Focus xếp hạng các thông báo trong cùng một danh mục.
Key thread-id nhóm các thông báo trong Trung tâm thông báo. Tất cả thông báo có cùng thread-id được hiển thị dưới dạng một nhóm duy nhất mà người dùng có thể mở rộng. Điều này đặc biệt hữu ích cho trình nhắn tin, nơi tin nhắn từ cùng một liên hệ được nhóm lại, hoặc cho các ứng dụng gửi nhiều thông báo cùng loại.
Trường tùy chỉnh là bất kỳ key nào bên ngoài từ điển aps mà nhà phát triển thêm vào để truyền dữ liệu bổ sung đến thiết bị. Máy chủ bao gồm chúng trong đối tượng JSON gốc của payload, và ứng dụng truy xuất chúng qua userInfo trong UNNotificationContent. Các trường tùy chỉnh không được trùng tên key với aps để tránh xung đột khi phân tích.
Giới hạn chính là tổng kích thước payload không được vượt quá 4096 byte. Các trường tùy chỉnh cạnh tranh giới hạn này với các key bắt buộc của aps, vì vậy điều quan trọng là giảm thiểu kích thước dữ liệu truyền. Sử dụng tên key ngắn (ví dụ: “uid” thay vì “user-id”), tránh cấu trúc JSON lớn và chỉ truyền định danh thay vì toàn bộ đối tượng dữ liệu.
Trường tùy chỉnh đến từ máy chủ và không nên được tin cậy mà không xác thực. Luôn xác thực loại và giá trị của trường tùy chỉnh khi phân tích: kiểm tra sự tồn tại của key thông qua liên kết tùy chọn, chuyển đổi sang loại mong đợi bằng as? String/Int/Dictionary và xử lý trường hợp không có giá trị. Đừng bao giờ sử dụng force unwrap (!) cho dữ liệu từ payload — máy chủ có thể gửi dữ liệu không hợp lệ, khiến ứng dụng bị treo.
{
"aps": {
"alert": {
"title": "Tin nhắn mới",
"body": "Xin chào! Bạn có khỏe không?"
},
"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"
}
Sử dụng kiểu đặt tên nhất quán cho các trường tùy chỉnh trong tất cả các payload của dự án. kebab-case (message-type) hoặc camelCase (messageType) — cả hai phương pháp đều chấp nhận được, nhưng tính nhất quán trong dự án là quan trọng. Tránh tên dài: “uid” thay vì “user-identifier”, “img” thay vì “profile-image-url”. Mỗi ký tự trong tên key tiêu thụ một byte trong giới hạn 4096.
Các kịch bản khác nhau của thông báo push yêu cầu các tổ hợp key khác nhau trong payload. Hãy xem một số ví dụ điển hình: thông báo văn bản đơn giản, thông báo đã địa phương hóa, Silent Push và Thông báo Rich với tập tin đính kèm phương tiện.
Một payload cơ bản với văn bản và âm thanh — cấu hình tối thiểu để hiển thị thông báo cho người dùng. Alert dưới dạng chuỗi cung cấp một thông điệp ngắn, sound default phát âm thanh hệ thống tiêu chuẩn. Badge là tùy chọn và đặt số trên biểu tượng ứng dụng. category và thread-id được thêm vào để nhóm và tương tác.
{
"aps": {
"alert": "Nhắc nhở: cuộc họp trong 15 phút",
"badge": 3,
"sound": "default"
}
}
Để gửi thông báo đến các thiết bị có ngôn ngữ khác nhau, hãy sử dụng các key bản địa hóa thay vì văn bản cứng. title-loc-key tham chiếu đến một key trong Localizable.strings của ứng dụng, và title-loc-args cung cấp đối số. Điều này cho phép gửi một payload duy nhất đến tất cả các thiết bị và ứng dụng hiển thị văn bản bằng ngôn ngữ thích hợp.
{
"aps": {
"alert": {
"title-loc-key": "NEW_MESSAGE_TITLE",
"title-loc-args": ["Anna"],
"loc-key": "NEW_MESSAGE_BODY",
"loc-args": ["Xin chào!"]
},
"sound": "message.caf"
}
}
Để đồng bộ nền mà không hiển thị thông báo, hãy sử dụng content-available: 1 mà không có alert. Các trường tùy chỉnh chỉ định loại hoạt động và dữ liệu để xử lý. Hệ thống kích hoạt ứng dụng trong nền, gọi didReceiveRemoteNotification với fetchCompletionHandler, và ứng dụng thực hiện đồng bộ.
{
"aps": {
"content-available": 1
},
"sync-type": "invalidate-cache",
"timestamp": "2026-07-03T12:00:00Z"
}
Để hiển thị tập tin đính kèm phương tiện, cần có mutable-content: 1 để kích hoạt Service Extension, cùng với URL hình ảnh trong trường tùy chỉnh. mutable-content: 1 báo hiệu hệ thống khởi chạy UNNotificationServiceExtension, tải hình ảnh từ URL và thêm nó dưới dạng UNNotificationAttachment. Key category chỉ định một danh mục đã đăng ký để hiển thị các nút hành động.
{
"aps": {
"alert": {
"title": "Sản phẩm mới",
"body": "Xem bộ sưu tập mới"
},
"category": "product",
"mutable-content": 1
},
"media-url": "https://cdn.example.com/product.jpg"
}
UNNotificationContent.userInfo chứa từ điển đầy đủ của payload đã nhận sau khi hệ thống xử lý. Ứng dụng truy cập payload trong ủy quyền UNUserNotificationCenter khi nhận thông báo (ở tiền cảnh), khi chạm vào thông báo, cũng như trong Service Extension và Content Extension. Việc phân tích chính xác là cần thiết để trích xuất dữ liệu tùy chỉnh và xác định các hành động tiếp theo.
Khi người dùng chạm vào thông báo, hệ thống gọi phương thức didReceive response trong UNUserNotificationCenterDelegate. response.notification.request.content.userInfo chứa payload đầy đủ. Nhà phát triển trích xuất các trường tùy chỉnh, xác định loại hành động (ví dụ: mở trò chuyện, điều hướng đến sản phẩm) và kích hoạt điều hướng tương ứng trong ứng dụng.
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 nhận payload trước khi thông báo được hiển thị và có thể sửa đổi nó. Xác thực payload là bước đầu tiên trong didReceive: kiểm tra các trường tùy chỉnh bắt buộc, xác thực URL tập tin đính kèm và kiểm tra loại dữ liệu. Nếu payload không hợp lệ, hãy gọi completion handler với nội dung gốc ngay lập tức để tránh lãng phí thời gian vào xử lý không cần thiết.
Để gỡ lỗi thông báo push trong sản xuất, hãy sử dụng ghi nhật ký payload có cấu trúc. OSLog cho phép ghi nhật ký payload với danh mục “notifications” ở mức debug. Về phía máy chủ, hãy giám sát các phản hồi APNS: phản hồi thành công chứa apns-id để khớp với payload đã gửi, trong khi lỗi 400 cho biết JSON không hợp lệ hoặc vượt quá kích thước.
Câu hỏi thường gặp
Kích thước tối đa của payload là 4096 byte cho thông báo push thông thường và 5120 byte cho VoIP push (PushKit). Vượt quá giới hạn này sẽ khiến APNS trả về lỗi 400 Bad Request. Kích thước được tính bằng byte, không phải ký tự — hãy tính đến mã hóa UTF-8.
Sử dụng các key loc-key, title-loc-key, loc-args và title-loc-args trong alert. Ứng dụng thay thế bản dịch từ Localizable.strings dựa trên ngôn ngữ thiết bị. Điều này cho phép gửi một payload duy nhất đến tất cả các thiết bị bất kể ngôn ngữ của chúng.
content-available kích hoạt ứng dụng trong nền để xử lý dữ liệu (silent push) mà không hiển thị thông báo. mutable-content kích hoạt Service Extension để sửa đổi nội dung trước khi hiển thị. Cả hai key có thể được sử dụng cùng nhau để xử lý nền và sửa đổi thông báo sau đó.
Sử dụng APNS Sandbox để kiểm tra và xác minh phản hồi HTTP của máy chủ Apple: 200 OK có nghĩa là gửi thành công. Để xác thực cấu trúc, hãy sử dụng lược đồ JSON trong đường ống CI/CD. Trong Xcode, gửi thông báo thử nghiệm qua trình mô phỏng bằng xcrun simctl push.
apns-id là một định danh thông báo push duy nhất trong hệ thống APNS, được trả về trong phản hồi khi gửi thành công. Nó được sử dụng để theo dõi việc gửi qua API Logs và để gỡ lỗi. Máy chủ nên lưu trữ apns-id cho mỗi thông báo đã gửi.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm