Push notifications
Hub › iOS › Advanced › Push notifications
Goal
Register the app for remote push notifications via Apple Push Notification service (APNs), handle incoming payloads, and display them as banners or in-app alerts.
Prerequisites
- CI/CD with GitHub Actions
- An Apple Developer account with push notification certificate or key
- A physical iOS device (push notifications don't work on simulator)
Capability setup
In Xcode:
- Target → Signing & Capabilities
- Add capability: Push Notifications
This adds the required entitlement:
<key>aps-environment</key>
<string>development</string>Register for notifications
Add notification registration to ListApp.swift:
import SwiftUI
import SwiftData
import UserNotifications
@main
struct ListApp: App {
@State private var notificationGranted = false
var body: some Scene {
WindowGroup {
ContentView()
.task {
await requestNotificationPermission()
}
}
.modelContainer(for: [CachedItem.self])
}
private func requestNotificationPermission() async {
let center = UNUserNotificationCenter.current()
do {
let granted = try await center.requestAuthorization(
options: [.alert, .badge, .sound]
)
notificationGranted = granted
if granted {
await UIApplication.shared.registerForRemoteNotifications()
}
} catch {
print("Notification permission error: \(error)")
}
}
}Handle registration
Add an AppDelegate to receive APNs callbacks:
import UIKit
class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let token = deviceToken.map { String(format: "%02x", $0) }.joined()
print("APNs device token: \(token)")
// Send token to your server for push targeting
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
print("APNs registration failed: \(error)")
}
}Wire the AppDelegate in ListApp.swift:
@main
struct ListApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
// ...
}Handle incoming notifications
Add a notification response handler via UNUserNotificationCenterDelegate:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
// Show banner even when app is in foreground
completionHandler([.banner, .sound])
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
let userInfo = response.notification.request.content.userInfo
// handleDeepLink(userInfo)
completionHandler()
}
}Set the delegate in requestNotificationPermission:
center.delegate = appDelegateSending a test push
Use curl to send a test push through APNs (requires a p8 key from your Apple Developer account):
# You'll need:
# - APNs key (.p8) from developer.apple.com
# - Key ID and team ID
# - Device token from the app's console output
TOKEN="<device-token>"
curl --http2 -v \
-H "apns-topic: com.yourcompany.ListApp" \
-H "apns-push-type: alert" \
--cert-type P12 \
-d '{"aps":{"alert":"Hello from APNs!","sound":"default"}}' \
"https://api.development.push.apple.com/3/device/$TOKEN"Checkpoint
Run the app on a physical device. Grant notification permission. The console prints the device token. Sending a push via curl shows a banner notification on the device, both in foreground and background.
Next: Instruments profiling — find performance bottlenecks with Instruments.