Push Notifications sind einer der wirkungsvollsten Mechanismen, um Nutzer zurück in deine App zu holen – vorausgesetzt, du setzt sie richtig ein. In iOS läuft jede Push Notification über den Apple Push Notification service (APNs), Apples hochverfügbare, gesicherte Infrastruktur für Benachrichtigungen. Diese Anleitung zeigt dir, wie du APNs konfigurierst, Berechtigungen anforderst, lokale und remote Notifications versendest und auf Nutzerinteraktionen reagierst – vollständig in Swift.
APNs – Die Infrastruktur hinter iOS-Push-Nachrichten
Der Apple Push Notification service (APNs) ist ein weltweit verteilter Dienst, der Nachrichten zwischen deinem Server und den iOS-Geräten deiner Nutzer vermittelt. Der Ablauf ist immer gleich:
- Deine App registriert sich bei APNs und erhält ein geräte- und app-spezifisches Device Token
- Dein Backend speichert dieses Token für den jeweiligen Nutzer
- Wenn eine Benachrichtigung versendet werden soll, schickt dein Server eine HTTPS/2-Anfrage an APNs mit dem Token und der Nachricht
- APNs leitet die Nachricht sicher an das Gerät weiter
- iOS zeigt die Benachrichtigung an – auch wenn die App nicht geöffnet ist
APNs verwendet TLS-Verschlüsselung für alle Verbindungen. Zur Authentifizierung deines Servers gegenüber APNs gibt es zwei Methoden: Token-basierte Authentifizierung (JWT mit einem .p8-Key – empfohlen) und zertifikatbasierte Authentifizierung (ältere Methode mit .p12-Dateien).
Xcode-Konfiguration: Entitlement einrichten
Bevor du auch nur eine Zeile Code schreibst, muss das Push Notifications Entitlement in deinem Xcode-Projekt aktiviert sein:
- Öffne dein Projekt in Xcode und wähle das App-Target
- Gehe zum Tab Signing & Capabilities
- Klicke auf "+ Capability" und füge "Push Notifications" hinzu
- Optional: Füge "Background Modes" hinzu und aktiviere "Remote notifications" (für Silent Push)
Xcode fügt automatisch das Entitlement aps-environment zu deiner .entitlements-Datei hinzu (development oder production, abhängig vom Build-Typ). Im Apple Developer Portal wird die entsprechende App ID automatisch aktualisiert, wenn du automatisches Signing verwendest.
Berechtigung anfragen mit UNUserNotificationCenter
iOS zeigt Benachrichtigungen nur an, wenn der Nutzer explizit zugestimmt hat. Die Berechtigungsabfrage solltest du zum richtigen Zeitpunkt zeigen – nicht sofort beim App-Start, sondern im Kontext (z.B. nachdem der Nutzer eine Funktion aktiviert hat, die Notifications sinnvoll macht):
import UserNotifications
func requestNotificationPermission() {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if let error = error {
print("Fehler bei der Berechtigungsanfrage: \(error)")
return
}
if granted {
print("Berechtigung erteilt – registriere bei APNs")
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
} else {
print("Berechtigung verweigert")
}
}
}
Die Optionen .alert, .badge und .sound steuern, welche Benachrichtigungstypen du anforderst. Mit .criticalAlert kannst du Benachrichtigungen anfordern, die auch im Lautlos-Modus klingen – dafür brauchst du aber eine spezielle Entitlement-Genehmigung von Apple.
Device Token empfangen
Nach dem Aufruf von registerForRemoteNotifications() ruft iOS eine Delegate-Methode in deinem AppDelegate auf:
// AppDelegate.swift
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
// Token als Hex-String konvertieren
let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
print("Device Token: \(tokenString)")
// Token an deinen Server senden
sendTokenToServer(tokenString)
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
print("APNs-Registrierung fehlgeschlagen: \(error)")
}
In SwiftUI-Apps ohne UIApplicationDelegate kannst du den AppDelegate über den @UIApplicationDelegateAdaptor-Wrapper einbinden.
Lokale vs. Remote Notifications
Lokale Notifications
Lokale Notifications werden direkt vom Gerät ausgelöst – kein Server nötig. Typische Anwendungsfälle: Erinnerungen, Kalendereinträge, Timer-Ablauf. Du erstellst dafür einen UNNotificationRequest:
func scheduleLocalNotification() {
let content = UNMutableNotificationContent()
content.title = "Deine Aufgabe wartet"
content.body = "Vergiss nicht, deine Notizen für heute zu ergänzen."
content.sound = .default
content.badge = 1
// Trigger: In 10 Sekunden
let trigger = UNTimeIntervalNotificationTrigger(
timeInterval: 10,
repeats: false
)
// Alternativ: Kalender-Trigger für täglich 9 Uhr
// var dateComponents = DateComponents()
// dateComponents.hour = 9
// let trigger = UNCalendarNotificationTrigger(
// dateMatching: dateComponents, repeats: true
// )
let request = UNNotificationRequest(
identifier: UUID().uuidString,
content: content,
trigger: trigger
)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("Fehler beim Planen: \(error)")
}
}
}
Remote Notifications (Push)
Remote Notifications werden von deinem Server via APNs ausgelöst. Das JSON-Payload hat eine standardisierte Struktur:
{
"aps": {
"alert": {
"title": "Neue Nachricht",
"body": "Lukas hat dir geantwortet.",
"subtitle": "Direktnachricht"
},
"badge": 3,
"sound": "default",
"content-available": 1,
"mutable-content": 1,
"category": "MESSAGE_CATEGORY",
"thread-id": "chat-lukas-42"
},
"customKey": "beliebige eigene Daten"
}
Mit "content-available": 1 sendest du eine Silent Push-Benachrichtigung: keine sichtbare Anzeige, aber deine App wird im Hintergrund geweckt, um Daten zu aktualisieren. Mit "mutable-content": 1 aktivierst du Notification Service Extensions, die den Inhalt vor der Anzeige modifizieren können (z.B. zum Entschlüsseln oder Anhängen von Bildern).
Notification Categories und Actions
Nutzer können auf Benachrichtigungen reagieren, ohne die App öffnen zu müssen – mit Notification Actions. Du definierst sie beim App-Start:
func registerNotificationCategories() {
let antwortAction = UNTextInputNotificationAction(
identifier: "ANTWORT_ACTION",
title: "Antworten",
options: [],
textInputButtonTitle: "Senden",
textInputPlaceholder: "Nachricht eingeben..."
)
let ignorierenAction = UNNotificationAction(
identifier: "IGNORIEREN_ACTION",
title: "Ignorieren",
options: [.destructive]
)
let messageCategory = UNNotificationCategory(
identifier: "MESSAGE_CATEGORY",
actions: [antwortAction, ignorierenAction],
intentIdentifiers: [],
options: [.customDismissAction]
)
UNUserNotificationCenter.current().setNotificationCategories([messageCategory])
}
Notifications in AppDelegate und SceneDelegate verarbeiten
Um auf Nutzerinteraktionen mit Benachrichtigungen zu reagieren, implementierst du UNUserNotificationCenterDelegate:
extension AppDelegate: UNUserNotificationCenterDelegate {
// Wird aufgerufen, wenn Nutzer auf Notification tippt (oder Action auswählt)
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
let userInfo = response.notification.request.content.userInfo
switch response.actionIdentifier {
case "ANTWORT_ACTION":
if let textResponse = response as? UNTextInputNotificationResponse {
print("Antwort: \(textResponse.userText)")
}
case UNNotificationDefaultActionIdentifier:
// Nutzer hat auf die Notification selbst getippt
handleNotificationTap(userInfo: userInfo)
default:
break
}
completionHandler()
}
// Wird aufgerufen, wenn Notification angezeigt wird während App offen ist
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
// Banner auch anzeigen, wenn App im Vordergrund ist
completionHandler([.banner, .sound, .badge])
}
}
Hintergrundmodi und Silent Push
Mit Silent Push Notifications (Background Fetch via APNs) kannst du deine App im Hintergrund wecken, um Daten zu aktualisieren, bevor der Nutzer sie öffnet. Dafür musst du in Xcode unter "Background Modes" die Option "Remote notifications" aktivieren und im App Delegate implementieren:
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
// Neue Daten laden
Task {
do {
try await syncNewestData()
completionHandler(.newData)
} catch {
completionHandler(.failed)
}
}
}
iOS begrenzt, wie oft und wie lange deine App im Hintergrund aktiv sein darf. Plane maximal 30 Sekunden für den Background-Fetch ein und ruf completionHandler immer auf.
Best Practices für Push Notifications
- Relevanz vor Quantität: Zu viele Notifications führen dazu, dass Nutzer sie deaktivieren oder die App löschen. Sende nur dann, wenn es wirklich relevant ist.
- Personalisierung: Eine gute Notification spricht den Nutzer mit seinem echten Kontext an – nicht generisch.
- Stille Zeiten respektieren: Nutze das
apns-expiration-Feld im APNs-Request und vermeide Notifications nachts (außer der Nutzer hat Kritische Alerts aktiviert). - Deep Linking: Notifications sollten direkt in den relevanten Bereich der App führen, nicht auf den Homescreen. Implementiere Universal Links oder URL Schemes für sauberes Deep Linking.
- Token-Rotation handeln: Device Tokens können sich ändern. Implementiere immer
didRegisterForRemoteNotificationsWithDeviceTokenund sende den aktuellen Token bei jedem App-Start an deinen Server.
Mehr zur iOS-App-Entwicklung findest du in der SwiftUI Grundlagen-Anleitung und bei den iOS Apps von Arthur Kotsch.
Häufige Fragen
Wozu brauche ich einen eigenen Server für Push Notifications?
Du brauchst einen Server (oder einen Backend-as-a-Service wie Firebase, OneSignal oder AWS SNS), weil nur du entscheiden kannst, wann und an wen eine Notification gesendet wird. Apple stellt nur die Infrastruktur (APNs) bereit – das Triggern der Nachrichten liegt bei dir. Dienste wie Firebase Cloud Messaging (FCM) abstrahieren APNs und bieten zusätzliche Features wie Topics und Analytics.
Kann ich Push Notifications im Simulator testen?
Ja, ab Xcode 11.4 und dem iOS 13-Simulator kannst du Push Notifications simulieren. Erstelle eine .apns-JSON-Datei und ziehe sie in den laufenden Simulator oder nutze den Befehl xcrun simctl push <device-id> <bundle-id> payload.apns. Für echte APNs-Tests brauchst du allerdings ein physisches Gerät.
Was ist der Unterschied zwischen APNs Development und Production?
APNs betreibt zwei getrennte Umgebungen: Development (für Debug-Builds aus Xcode) und Production (für App Store und TestFlight-Builds). Das Entitlement in der App (aps-environment) bestimmt, welchen Endpunkt du ansprechen musst. Verwendest du einen Development-Token mit dem Production-Endpunkt (oder umgekehrt), schlägt die Zustellung stillschweigend fehl.
Wie gehe ich mit Nutzern um, die Notifications abgelehnt haben?
Frage den aktuellen Status mit UNUserNotificationCenter.current().getNotificationSettings() ab. Falls die Berechtigung verweigert wurde, kannst du dem Nutzer in der App erklären, warum Notifications nützlich wären, und ihn mit UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!) direkt in die Systemeinstellungen führen, wo er sie aktivieren kann.
Wie viele Notifications kann ich pro Gerät pro Tag senden?
Apple setzt keine strikten numerischen Limits pro Gerät, aber APNs begrenzt die Rate pro Token. Zu hohe Frequenzen können dazu führen, dass APNs Nachrichten verwirft (nur die neueste wird zugestellt). Für Massen-Benachrichtigungen nutze den collapse-id-Header im APNs-Request, damit bei mehreren ausstehenden Notifications nur eine angezeigt wird.