Notification Payload — to struktura JSON, którą serwer wysyła przez APNS na urządzenie iOS, określając zawartość powiadomienia push i zachowanie przy jego otrzymaniu. Payload zawiera obowiązkowe i opcjonalne klucze sterujące tekstem, dźwiękiem, badge, załącznikami multimedialnymi i przetwarzaniem w tle. Według Apple Developer Documentation, 2026, maksymalny rozmiar payloadu wynosi 4096 bajtów dla zwykłych powiadomień i 5120 bajtów dla VoIP push, co nakłada ścisłe ograniczenia na ilość przesyłanych danych.
Najważniejsze
Notification Payload (payload powiadomienia) — to obiekt JSON, który serwer wysyła do APNS (Apple Push Notification Service) w celu dostarczenia na urządzenie iOS. Payload zawiera wszystkie dane niezbędne systemowi do wyświetlenia powiadomienia: tytuł, tekst, dźwięk, badge i metadane do przetwarzania w tle. Struktura payloadu jest ściśle regulowana przez Apple i zawiera obowiązkowe klucze do prawidłowego przetwarzania przez system.
Gdy serwer wysyła powiadomienie push przez HTTP/2 API APNS, żądanie zawiera nagłówki autoryzacji i ciało JSON — payload. APNS sprawdza poprawność payloadu: jeśli JSON jest nieprawidłowy lub przekracza limit rozmiaru, serwer Apple zwraca błąd 400 Bad Request. Po walidacji APNS dostarcza payload na urządzenie, gdzie system iOS go parsuje i określa, jak przetworzyć powiadomienie — wyświetlić baner, uruchomić zadanie w tle lub odtworzyć dźwięk.
Format payloadu APNS ewoluował od prostego tekstowego payloadu w iOS 2 do wieloskładnikowej struktury JSON w nowoczesnych wersjach. iOS 10 przyniosła obsługę załączników multimedialnych przez mutable-content, iOS 12 dodała grupowanie powiadomień przez thread-id, a iOS 15 wprowadziła supports-live-activities dla Live Activities. Obecnie payload może zawierać do 15 różnych kluczy w zależności od wymaganego zachowania powiadomienia.
Obiekt główny payloadu zawiera słownik aps i opcjonalne niestandardowe pola na najwyższym poziomie. Słownik aps — jedyny obowiązkowy element, ale wewnątrz niego mogą występować różne kombinacje kluczy w zależności od typu powiadomienia: alert, badge, sound, content-available, mutable-content, interruption-level i inne.
| Klucz aps | Typ | Przeznaczenie |
|---|---|---|
| alert | String lub Dictionary | Tekst powiadomienia lub obiekt z title, subtitle, body, lokalizacją |
| badge | Number | Liczba na ikonie aplikacji; 0 usuwa badge |
| sound | String | Nazwa pliku dźwiękowego lub default dla systemowego dźwięku |
| content-available | Number (1) | Flaga aktywacji w tle; 1 = silent push |
| mutable-content | Number (1) | Flaga aktywacji Service Extension do modyfikacji treści |
| category | String | Identyfikator kategorii dla przycisków i Content Extension |
| thread-id | String | Identyfikator grupy do grupowania powiadomień |
| interruption-level | String | Poziom przerwania: passive, active, time-sensitive, critical |
| relevance-score | Number (0–1) | Priorytet powiadomienia dla systemu inteligentnego rankingu |
Klucz alert może być prostym ciągiem znaków (który staje się treścią powiadomienia) lub słownikiem z polami title, subtitle, body. Format słownikowy pozwala ustawić tytuł i podtytuł oddzielnie od głównego tekstu. Dla zlokalizowanych powiadomień używane są klucze title-loc-key, title-loc-args, loc-key, loc-args, które odwołują się do Localizable.strings aplikacji. Pozwala to wysyłać payload bez tekstu w konkretnym języku — aplikacja podstawia tłumaczenie.
Począwszy od iOS 15 Apple dodała mechanizm Focus Mode, który wymaga od programisty określenia poziomu przerwania powiadomienia. interruption-level przyjmuje wartości: passive (bez dźwięku, bez budzenia ekranu), active (standardowe zachowanie), time-sensitive (przebija focus, wymaga special entitlement) i critical (sytuacje medyczne/awaryjne). Klucz relevance-score (0–1) pomaga systemowi Focus rankingować powiadomienia w ramach jednej kategorii.
Klucz thread-id łączy powiadomienia w grupy w Notification Center. Wszystkie powiadomienia z tym samym thread-id wyświetlają się jako jedna grupa, którą użytkownik może rozwinąć. Jest to szczególnie przydatne dla komunikatorów, gdzie wiadomości od jednego kontaktu są grupowane razem, lub dla aplikacji wysyłających wiele powiadomień tego samego typu.
Niestandardowe pola — to wszelkie klucze poza słownikiem aps, które programista dodaje do przesyłania dodatkowych danych na urządzenie. Serwer dołącza je do głównego obiektu JSON payloadu, a aplikacja otrzymuje je przez userInfo w UNNotificationContent. Niestandardowe pola nie powinny powielać nazw kluczy z aps, aby uniknąć konfliktów podczas parsowania.
Główne ograniczenie — całkowity rozmiar payloadu nie może przekraczać 4096 bajtów. Niestandardowe pola konkurują o ten limit z obowiązkowymi kluczami aps, dlatego ważne jest minimalizowanie rozmiaru przesyłanych danych. Używaj krótkich nazw kluczy (np. „uid“ zamiast „user-id“), unikaj dużych struktur JSON i przesyłaj tylko identyfikatory, a nie pełne obiekty danych.
Niestandardowe pola pochodzą z serwera i nie należy im ufać bez sprawdzenia. Zawsze waliduj typy i wartości niestandardowych pól podczas parsowania: sprawdzaj obecność klucza przez optional binding, konwertuj na oczekiwany typ za pomocą as? String/Int/Dictionary i obsługuj przypadek braku wartości. Nigdy nie używaj force unwrap (!) dla danych z payloadu — serwer może wysłać nieprawidłowe dane, a aplikacja ulegnie crashowi.
{
"aps": {
"alert": {
"title": "Nowa wiadomość",
"body": "Cześć! Jak się masz?"
},
"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"
}
Używaj jednolitego stylu nazewnictwa niestandardowych pól we wszystkich payloadach projektu. kebab-case (message-type) lub camelCase (messageType) — oba podejścia są dopuszczalne, ale ważne jest trzymanie się jednego w ramach projektu. Unikaj długich nazw: „uid“ zamiast „user-identifier“, „img“ zamiast „profile-image-url“. Każdy znak w nazwie klucza to bajt z limitu 4096.
Różne scenariusze powiadomień push wymagają różnych kombinacji kluczy w payloadzie. Rozważmy kilka typowych przykładów: proste powiadomienie tekstowe, powiadomienie z lokalizacją, Silent Push i Rich Notification z załącznikiem multimedialnym.
Podstawowy payload z tekstem i dźwiękiem — minimalna konfiguracja do wyświetlenia powiadomienia użytkownikowi. Alert jako ciąg znaków daje krótką wiadomość, sound default odtwarza standardowy systemowy dźwięk. Badge jest opcjonalny i ustawia licznik na ikonie. category i thread-id są dodawane do grupowania i interaktywności.
{
"aps": {
"alert": "Przypomnienie: spotkanie za 15 minut",
"badge": 3,
"sound": "default"
}
}
Do wysyłania na urządzenia z różnymi językami używaj kluczy lokalizacji zamiast sztywno zadanego tekstu. title-loc-key odwołuje się do klucza w Localizable.strings aplikacji, a title-loc-args podstawia argumenty. Pozwala to wysłać jeden payload na wszystkie urządzenia, a aplikacja sama wyświetli tekst w odpowiednim języku.
{
"aps": {
"alert": {
"title-loc-key": "NEW_MESSAGE_TITLE",
"title-loc-args": ["Anna"],
"loc-key": "NEW_MESSAGE_BODY",
"loc-args": ["Cześć!"]
},
"sound": "message.caf"
}
}
Do synchronizacji w tle bez wyświetlania powiadomienia używa się content-available: 1 i braku alert. Niestandardowe pola wskazują typ operacji i dane do przetworzenia. System aktywuje aplikację w tle, wywołuje didReceiveRemoteNotification z fetchCompletionHandler, a aplikacja wykonuje synchronizację.
{
"aps": {
"content-available": 1
},
"sync-type": "invalidate-cache",
"timestamp": "2026-07-03T12:00:00Z"
}
Do wyświetlania załącznika multimedialnego potrzebny jest mutable-content: 1 do aktywacji Service Extension i URL obrazu w niestandardowym polu. mutable-content: 1 sygnalizuje systemowi uruchomienie UNNotificationServiceExtension, który pobierze obraz pod URL i doda go jako UNNotificationAttachment. category wskazuje na zarejestrowaną kategorię do wyświetlania przycisków akcji.
{
"aps": {
"alert": {
"title": "Nowy produkt",
"body": "Zobacz nową kolekcję"
},
"category": "product",
"mutable-content": 1
},
"media-url": "https://cdn.example.com/product.jpg"
}
UNNotificationContent.userInfo zawiera pełny słownik otrzymanego payloadu po przetworzeniu przez system. Aplikacja uzyskuje dostęp do payloadu w delegacie UNUserNotificationCenter przy otrzymaniu powiadomienia (na pierwszym planie), przy kliknięciu powiadomienia, a także w Service Extension i Content Extension. Prawidłowe parsowanie jest obowiązkowe do wyodrębnienia niestandardowych danych i określenia dalszych działań.
Gdy użytkownik klika powiadomienie, system wywołuje metodę didReceive response w UNUserNotificationCenterDelegate. W response.notification.request.content.userInfo zawarty jest pełny payload. Programista wyodrębnia niestandardowe pola, określa typ akcji (np. otwarcie czatu, przejście do produktu) i wywołuje odpowiednią nawigację w aplikacji.
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 otrzymuje payload przed wyświetleniem powiadomienia i może go modyfikować. Walidacja payloadu — pierwszy krok w didReceive: sprawdź obecność obowiązkowych niestandardowych pól, poprawność URL dla załączników i typ danych. Jeśli payload jest nieprawidłowy, wywołaj completion handler z oryginalną treścią natychmiast, nie tracąc czasu na bezużyteczne przetwarzanie.
Do debugowania powiadomień push na produkcji używaj strukturalnego logowania payloadów. OSLog pozwala logować payload z kategorią „notifications“ i poziomem debug. Po stronie serwera śledź odpowiedzi APNS: pomyślna odpowiedź zawiera apns-id do dopasowania z wysłanym payloadem, a błąd 400 wskazuje na nieprawidłowy JSON lub przekroczenie rozmiaru.
Często zadawane pytania
Maksymalny rozmiar payloadu — 4096 bajtów dla zwykłych powiadomień push i 5120 bajtów dla VoIP push (PushKit). Przy przekroczeniu APNS zwraca błąd 400 Bad Request. Rozmiar liczony jest w bajtach, nie w znakach — uwzględniaj kodowanie UTF-8.
Używaj kluczy loc-key, title-loc-key, loc-args i title-loc-args wewnątrz alert. Aplikacja podstawia tłumaczenie ze swojego Localizable.strings na podstawie języka urządzenia. Pozwala to wysłać jeden payload na wszystkie urządzenia niezależnie od ich języka.
content-available aktywuje aplikację w tle do przetwarzania danych (silent push) bez wyświetlania powiadomienia. mutable-content aktywuje Service Extension do modyfikacji treści przed wyświetleniem. Oba klucze mogą być używane razem do przetwarzania w tle i późniejszej modyfikacji powiadomienia.
Używaj APNS Sandbox do testowania i sprawdzaj odpowiedź HTTP serwera Apple: 200 OK oznacza pomyślne wysłanie. Do walidacji struktury używaj schematów JSON w CI/CD pipeline. W Xcode wysyłaj testowe powiadomienia przez symulator komendą xcrun simctl push.
apns-id — unikalny identyfikator powiadomienia push w systemie APNS, który jest zwracany w odpowiedzi na pomyślne wysłanie. Używany do śledzenia dostawy przez Logs API i do debugowania. Serwer powinien zapisywać apns-id dla każdego wysłanego powiadomienia.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również