Blog
ENGINEERING

How to migrate AppDelegate to UISceneDelegate (iOS 26 Requirement)

Mike Miller

October 23, 2025

iOS26 Push Notifications Changes

Table of contents

1. TL;DR

2. What’s Changing — and Why It Affects Push Notifications

3. What’s Not Changing — The APNs Flow Remains the Same

4. How to Support Scenes — Step-by-Step (UIKit and SwiftUI)

5. When Enforcement Happens — iOS 26 vs iOS 27 Timeline

6. Final Checklist & Takeaways

Apple is changing how UIKit apps start — and it directly impacts push notifications.
Starting in iOS 26, developers began seeing console warnings urging adoption of the scene-based life cycle (UIScene). With iOS 27, that shift becomes mandatory.
If your app doesn’t use scenes, it won’t launch when built with the new SDK — and without launch, there’s no way to register for remote notifications or receive APNs tokens.

In iOS 26, iPadOS 26, Mac Catalyst 26, tvOS 26, visionOS 26, you'll start seeing the following message:

"UIScene lifecycle will soon be required. Failure to adopt will result in an assert in the future."

This guide explains exactly what’s changing, what stays the same, and the fastest way to migrate — so your push notifications keep flowing and app keeps working.


1. TL;DR

  • iOS 26: Apps must start supporting UISceneDelegate.
  • iOS 27 SDK: Non-scene apps will crash on launch. Enforcement happens when you build with the iOS 27 SDK, not simply by running on the OS.
  • Push fundamentals stay the same: You’ll still request authorization, register for remote notifications, and receive APNs device tokens in AppDelegate.
  • Keep your AppDelegate. Token callbacks still arrive there.
  • Add a UISceneDelegate. Add a UISceneDelegate now to ensure your push registration and Courier token sync continue working with iOS 27 and beyond.
  • But where does didRegisterForRemoteNotificationsWithDeviceToken go now? It stays in your AppDelegate — there’s no UISceneDelegate equivalent. Apple hasn’t introduced a scene-based version of that callback, so keep handling APNs tokens in AppDelegate (or let CourierDelegate handle it automatically).
  • Test on a physical device. We're seeing inconsistent results with the simulator. Simulated devices are not a reliable way to ensure your push notifications are working with iOS 26 at the moment.

2. What’s Changing — and Why It Affects Push Notifications

Apple is retiring the single-window AppDelegate life cycle and making UIScene mandatory for UIKit apps — a shift that started back in iOS 13 but is only now being enforced. Scenes allow each window to manage its own state, enabling features like iPad multitasking and smoother background/foreground transitions.

By iOS 26, Apple began warning developers:

“This process does not adopt the UIScene lifecycle. This will become an assert in a future version.”

That future version is the iOS 27 SDK.
If your app doesn’t declare a scene, it won’t launch — meaning didRegisterForRemoteNotificationsWithDeviceToken() in your App Delegate never runs, and APNs tokens are never issued. No token = no push.

Supporting a scene in your app ensures:

  • Your app launches correctly on iOS 27 and later.
  • Push registration occurs reliably once a scene connects.
  • Your tokens flow through to Courier without interruption.

3. What’s Not Changing — The APNs Flow Remains the Same

Apple hasn’t changed the push fundamentals.
Here’s the core flow that still applies in both UIKit and SwiftUI:

Copied!

// 1. Ask permission
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
if granted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
// 2. Receive the device token
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02x", $0) }.joined()
print("APNs token: \(token)")
// Send to backend / Courier
}
  • Token callbacks still live in AppDelegate.
  • Courier integration doesn’t change. If you use CourierDelegate, all of this is done automatically for you.
  • Permission API is identical. UNUserNotificationCenter is still how you request notification authorization.

4. How to Support Scenes — Step-by-Step (UIKit and SwiftUI)

UIKit Apps

  1. Add the Scene Manifest to Info.plist

Copied!

<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
  1. Create a UIWindowSceneDelegate

Copied!

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
  1. Keep AppDelegate for APNs Callbacks

Copied!

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02x", $0) }.joined()
print("APNs token: \(token)")
// Sync to Courier
}
}

Again, if you use CourierDelegate, this is done automatically for you.

SwiftUI Apps

SwiftUI already uses scenes. You just need to bridge an AppDelegate to keep receiving push callbacks.

Copied!

@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
...
}

5. When Enforcement Happens — iOS 26 vs iOS 27 Timeline

iOS 26 — Warning Stage
Your legacy app still launches but logs:

Copied!

This process does not adopt the UIScene lifecycle.
This will become an assert in a future version.

Push registration still works, but you’re officially on borrowed time.

iOS 27 — Enforcement Stage
When you build with the iOS 27 SDK, UIKit enforces the assert.
No scene manifest = immediate crash on launch — before AppDelegate methods fire.

Summary Table

iOS VersionBehaviorMigration Status
≤ 25Legacy AppDelegate lifecycle worksOptional
26Console warningStrongly recommended
27 SDKLaunch assert (crash)Required

Bottom line: migrate now, not when Xcode 17 flips the SDK default.


6. Final Checklist & Takeaways

Quick Checklist

  • Add SceneDelegate to your app (UIKit).
  • Keep your AppDelegate for APNs callbacks. (Or use CourierDelegate to automatically sync push notification tokens)
  • Register for remote notifications once your first scene connects. (CourierDelegate does this automatically)
  • Confirm there are no UIScene warnings in Xcode.
  • Test push delivery on a real device.

Key Takeaway
Supporting the UIScene lifecycle isn’t just future-proofing — it’s required for your app to launch and receive push notifications once you adopt the iOS 27 SDK.
Add scene support, validate token registration, and your Courier push pipeline will stay reliable for iOS 27, 28, and beyond.

Similar resources

quite hours and delivery windows
EngineeringNotifications Landscape

How Top Notification Platforms Handle Quiet Hours & Delivery Windows in 2026

No platform offers per-template delivery windows in 2026—it's either per-workflow (Customer.io, Knock), per-campaign (Braze), or global settings. This comparison shows exactly how six platforms handle quiet hours and send time controls based on their documentation and API specs. Braze leads on AI timing (23% open rate lift from Intelligent Timing across their customer base). Novu is the only platform letting subscribers set their own delivery windows. Customer.io and Knock require manual workflow configuration. OneSignal's strength is push-specific optimization across 300K+ apps. Courier combines per-node flexibility with API control. Includes feature matrix, timezone handling, and frequency capping differences.

By Kyle Seyler

January 16, 2026

what is observability
GuideIntegrationsEngineering

Notification Observability: How to Monitor Delivery, Engagement, and Provider Health

Notification observability is the practice of monitoring notification delivery, engagement, and provider health using the same tools and discipline you apply to the rest of your application infrastructure. It means tracking whether messages are delivered, opened, and acted on across email, SMS, push, and in-app channels, then surfacing that data in dashboards alongside your other application metrics. Key metrics include delivery rate by channel, bounce and failure rates, provider latency, open rate trends, and click-through rates by template. Teams can build notification observability through DIY webhook handlers that pipe provider events to Datadog or Prometheus, log aggregation from application send logs, or notification platforms with built-in observability integrations. This matters most for multi-channel systems, business-critical notifications like password resets and payment confirmations, and teams using multiple providers with fallback routing.

By Kyle Seyler

January 15, 2026

sms opt out rules 2026
Notifications LandscapeEngineeringProduct Management

SMS Opt-Out Rules in 2026

TCPA consent rules changed in April 2025. Consumers can now revoke consent using any reasonable method, including keywords like "stop," "quit," "end," "revoke," "opt out," "cancel," or "unsubscribe." Businesses must honor opt-out requests within 10 business days, down from 30. The controversial "revoke all" provision, which would require opt-outs to apply across all automated messaging channels, has been delayed until January 2027 and may be eliminated entirely. SMS providers like Twilio handle delivery infrastructure and STOP keyword responses at the number level. They don't sync opt-outs to your email provider, push notification service, or in-app messaging. That cross-channel gap is your responsibility. Courier provides unified preference management that enforces user choices across SMS, email, push, and chat automatically.

By Kyle Seyler

January 13, 2026

Multichannel Notifications Platform for SaaS

Products

Platform

Integrations

Customers

Blog

API Status

Subprocessors


© 2026 Courier. All rights reserved.