Skip to content
App Maintenance & Upgrades

iOS 27 for developers: the changes that break builds

What can break when you rebuild with the iOS 27 SDK: the scene life cycle launch failure, the @State macro, MetricKit crashes, deprecations and Device Hub.

Ingenious Techlab TeamUpdated 9 min read
Contents
  1. 1. Apps that don’t use scenes fail to launch
  2. 2. The new @State can stop code compiling
  3. 3. Behaviour changes when you rebuild
  4. 4. MetricKit: two crashes you avoid by recompiling
  5. 5. Deprecations to schedule
  6. 6. Enterprise: stricter TLS for device management and app installation
  7. 7. Xcode 27: Device Hub
  8. A rebuild checklist

Most “what’s new in iOS 27” coverage is a feature list. This isn’t one. It covers what changes when you rebuild an existing app with the iOS 27 SDK — the changes that turn a routine build into a failed launch, a compile error or a crash.

What happens to an existing app when it is rebuilt with the iOS 27 SDK

Rebuilt: won’t launch

  • No scene-based life cycle

Rebuilt: may not compile

  • Some @State properties with a default that are also set in init
  • Private synthesized init used with @State

Rebuilt: might crash

  • TabView selection set to a hidden or unavailable tab

Not rebuilt: can crash

  • Code using MetricKit hitch-time metrics — Apple says recompile

Rebuilt: behaves differently

  • Selectable Text uses system selection
  • AsyncImage caches via HTTP headers

Deprecated or discouraged

  • canOpenURL:
  • On Demand Resources
  • MXMetricManager for new code
Every item is from Apple’s iOS 27 release notes. The launch failure affects every UIKit-based app that hasn’t adopted scenes, including apps on cross-platform frameworks that haven’t shipped support. The MetricKit item is the exception that argues for rebuilding sooner rather than later.

Xcode 27 ships with Swift 6.4 and requires a Mac running macOS Tahoe 26.6 or later. You will be rebuilding with it whether you want to or not: from April 2027, Apple only accepts App Store uploads built with the iOS 27 SDK or later.

iPhone Duo and iOS 27: the dates that matterA timeline, not to scale. 9 September 2026: iPhone Duo announced. Later in September: Xcode 27.1 beta, with no date given. 16 October: pre-orders. 23 October: on sale with iOS 27.1. 30 October: 28 more countries. April 2027: App Store uploads must be built with the iOS 27 SDK.9 SeptDuo announcedTalks + HIG outLate SeptXcode 27.1 betaNo date given16 OctPre-orders70+ countries23 OctOn saleWith iOS 27.130 Oct28 more countriesApril 2027iOS 27 SDK ruleEvery upload
Not to scale. Dates are from Apple’s Newsroom announcement, Apple Developer News and the iPhone Duo developer page. The April 2027 rule applies to every iOS app you upload, whether or not you care about iPhone Duo.

1. Apps that don’t use scenes fail to launch

This is the one to plan for. It sits under UIKit → Deprecations in the iOS 27 release notes:

Apps built with the latest SDK must adopt the scene-based life cycle or they fail to launch.

Apple has been warning about it since iOS 18.4, when UIKit started logging a message for apps without scene support. In iOS 26 the message said adoption would soon be required. In iOS 27 it is.

A developer building an unmodified Expo SDK 56 app with Xcode 27 quoted the runtime error in expo/expo#46664. Expo has since fixed this — SDK 58 beta uses scenes by default, and SDK 57 can opt in behind one flag, which the Expo SDK 58 beta post covers — but SDK 56 still fails exactly like this:

Application failed to launch: UIScene life cycle is required for apps built
with this SDK. See Technote TN3187 for more information on migration.

Two details keep this from being as alarming as it sounds:

  • Existing binaries keep working. The requirement applies to apps built with the new SDK. What’s in the App Store today is unaffected until you ship an update.
  • Only the life cycle is required. TN3187 is explicit: supporting multiple scenes is encouraged, but only adopting the scene life cycle is required.

Does your app need to migrate?

TN3187 gives two tests. You need to migrate if either is true:

  • Your Info.plist has no UIApplicationSceneManifest key, or it has no configurations.
  • Your app delegate doesn’t implement application(_:configurationForConnecting:options:).

SwiftUI apps that use the App protocol and WindowGroup are already scene-based.

From the app-delegate life cycle to the scene-based life cycleLeft: the older pattern, where the app delegate creates the window and root view controller directly. Apps built this way with the iOS 27 SDK fail to launch. Right: the scene-based pattern. The app delegate handles only the process life cycle; a scene manifest in Info.plist configures a window scene delegate, one per scene, which creates the window and root view controller.App delegate owns the UIScene-based life cycleconfiguresUIApplicationDelegatecreates the windowUIWindowRoot view controllerUIApplicationDelegateprocess life cycle onlyUIApplicationSceneManifestInfo.plistUIWindowSceneDelegateone per scene · UI life cycleUIWindowUIWindow(windowScene:)Root view controller
Apple’s iOS 27 release notes, verbatim: “Apps built with the latest SDK must adopt the scene-based life cycle or they fail to launch.” The app delegate keeps process events; everything about visible UI moves to the scene delegate.

The migration, in Apple’s code

First, declare a scene configuration in Info.plist. This is TN3187’s example, with the storyboard line removed for apps that build their UI in code:

<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>

Second, move window creation into a scene delegate. The window is now created from the scene rather than from the screen:

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        guard let windowScene = scene as? UIWindowScene else { return }

        window = UIWindow(windowScene: windowScene)
        window?.rootViewController = YourRootViewController()
        window?.makeKeyAndVisible()
    }
}

Third, move UI life-cycle logic. After migrating, UIKit sends UI state changes to the scene delegate, not the app delegate. TN3187 maps the four methods:

Was on UIApplicationDelegate Moves to UISceneDelegate
applicationDidBecomeActive(_:) sceneDidBecomeActive(_:)
applicationWillResignActive(_:) sceneWillResignActive(_:)
applicationDidEnterBackground(_:) sceneDidEnterBackground(_:)
applicationWillEnterForeground(_:) sceneWillEnterForeground(_:)

Where migrations actually go wrong

The steps above are short. The breakage is in everything that quietly depended on the old structure. In our experience these are the places to look first:

  • Code that reads the app delegate’s window. In a scene-based app the window belongs to the scene. React Native hit exactly this: facebook/react-native#53602 was a crash in code that still expected a window on the app delegate.
  • Deep links and universal links. Once a scene delegate exists, URLs opened while the app runs arrive at the scene through UIOpenURLContext, and a URL that launched the app arrives in the scene’s connection options. A handler that only lives in the app delegate stops seeing them. A commenter on the Expo issue reports exactly this breaking React Native’s initial-URL handling.
  • Third-party SDKs initialised from UI callbacks. Analytics, attribution and session-replay SDKs often hook app-delegate activation events. Check each one’s release notes for iOS 27 support.
  • Anything keyed to a single window. A scene-based app can have more than one window, and on iPhone Duo — the first iPhone to support multiple instances of an app’s UI — that is no longer theoretical. Don’t turn on multiple scenes until your state model can cope. TN3187 notes this “may require restructuring your app.”

After migrating, test in every multitasking mode you support. TN3187 recommends Split View, Slide Over and Stage Manager on iPad, and on iPhone Duo Split View applies to every app.

Framework status

If your app is built on a cross-platform framework, the framework owns most of this migration — and the frameworks are in very different places:

Scene life cycle support by stack, checked 2026-09-20
StackStatusWhat it means for you
UIKit / SwiftUI (native)You migrateAdopt a scene manifest and a window scene delegate. SwiftUI apps using the App protocol already use scenes.TN3187
FlutterShipped in 3.41Default since 3.41; unmodified AppDelegates migrate automatically on build. Custom AppDelegates, and older Flutter versions, migrate by hand.Flutter migration guide
React Native0.88 release candidateScene life cycle support, including linking, is in the 0.88 release candidates — 0.88.0-rc.1 is current — and in no stable release. 0.88 stable is scheduled for 12 October. On 0.87 or earlier, add a SceneDelegate to your iOS project yourself.Commit · 0.88 on npm · Release schedule · Template PR for 0.87
ExpoShipped, opt-in on 57SDK 58 beta uses scenes by default. On SDK 57 the runtime shipped too, but you opt in: set ios.enableSceneSupport in expo-build-properties and run expo 57.0.23 or newer. SDK 56 still fails to launch under Xcode 27.SDK 58 beta · enableSceneSupport · SDK 57 runtime · Original issue
Status of the scene life cycle requirement by stack, checked on . This changes weekly — follow the links for the current state before you plan around it.

The framework guides cover the practical steps: React Native and Expo on iPhone Duo and iOS 27, Expo SDK 58 beta, iOS 27 scenes and iPhone Duo and Flutter on iPhone Duo and iOS 27.

2. The new @State can stop code compiling

Xcode 27 replaces SwiftUI’s @State property wrapper with a Swift macro. The change is good: a @State private var model = Model() no longer re-runs Model.init() every time the view struct is recreated. Apple says the new behaviour back-deploys to iOS 17-aligned OS versions.

It is “largely source compatible” — with exceptions that surface as build errors.

Assigning a @State in init when the declaration already has a value. The initializer value was always discarded, but this now fails to compile. Apple’s example:

struct StickerPageView: View {
    @State private var page = StickerPage()
    let title: String

    init(title: String) {
        // `title` won't have any effect
        // this also won't compile with @State macro
        self.page = StickerPage(title: title)
        self.title = title
    }
}

The fix is to drop the initial value from the declaration:

struct StickerPageView: View {
    @State private var page: StickerPage // no initial value expression
    let title: String

    init(title: String) {
        self.page = StickerPage(title: title) // works!
        self.title = title
    }
}

Also no longer supported:

  • The synthesized initializer. The macro disables it for structs whose stored members are all private, so an extension that called self.init(page:title:) must assign each member explicitly.
  • Generic inference. It is less flexible, so write the type out in full.
  • Composing @State with other property wrappers or macros isn’t supported.

3. Behaviour changes when you rebuild

These don’t fail the build. They change what the app does once it’s built with the iOS 27 SDK.

  • TabView enforces a visible selection. Apple warns that TabView “might crash” if its selection is set to a hidden or unavailable tab. Check any code that restores a saved tab, or selects a tab you sometimes hide.
  • Selectable text uses the system selection UI. Text with .textSelection(.enabled) now uses system text selection instead of a callout menu, and may add gestures. If you attach custom gestures to selectable text, Apple suggests .highPriorityGesture().
  • AsyncImage now caches downloaded images using standard HTTP caching headers. A custom URLSession can be set for a subtree with .asyncImageURLSession(_:). If your server sends aggressive cache headers, images may now stay stale where they previously refreshed.
  • Status bar styling from SwiftUI: .toolbarColorScheme(_, for: .statusBar) sets it directly, and .toolbarVisibility(_, for: .statusBar) hides it.

4. MetricKit: two crashes you avoid by recompiling

These two run the other way from everything else in this post: the risk is to builds you haven’t recompiled. Apple flags both with the same instruction — recompile with the latest SDK:

  • HitchTimeMetric.ratio changed type to the new HitchTimeRatio. Apple says to recompile “to pick up this type change and avoid any crashes on launch.”
  • ScrollHitchTimeMetric is no longer part of the new Swift MetricKit API. Code that references it risks “a missing symbol crash” until rebuilt; use HitchTimeMetric instead.

Separately, the original MXMetricManager, MXMetricManagerSubscriber, MXMetricPayload and MXDiagnosticPayload APIs are no longer recommended for new adoption. Their replacement, MetricManager, delivers MetricReport and DiagnosticReport values through AsyncStream.

5. Deprecations to schedule

  • canOpenURL: is deprecated. Apple’s guidance is to attempt to open the URL and handle failure, or to use universal links so no check is needed.
  • On Demand Resources and NSBundleResourceRequest are deprecated. Move to Background Assets, which in iOS 27 also supports localized asset packs.
  • The Neural Engine in the background needs an entitlement. The system now restricts background access, similar to GPU restrictions. Background inference requires com.apple.developer.background-tasks.continued-processing.inference.

6. Enterprise: stricter TLS for device management and app installation

In 27.0 operating systems, selected system processes enforce stricter TLS. The affected processes handle MDM, declarative device management, Automated Device Enrollment, configuration profiles, app installation and software updates. Servers must support at least TLS 1.2, with cipher suites and certificates that meet App Transport Security requirements.

This doesn’t affect your app’s own network calls. It does matter if you distribute apps in-house from your own server or run device management — check those servers before your fleet updates.

7. Xcode 27: Device Hub

In Xcode 27, simulated and physical devices are managed from Device Hub. Some changes affect day-to-day work and tooling:

  • Scripts that assumed the old Simulator app can break. Expo CLI’s run:ios failed on the Xcode 27 beta because it looked for Simulator.app (expo/expo#46882); Expo has merged a fix in its CLI. Check any in-house build or test scripts that launch or activate the simulator by app name. simctl and devicectl still work, and both gained a reboot command.
  • Mac mouse and trackpad gestures now drive standard UIKit components. Scrolling emits UIEvent.EventType.scroll, pinching and rotating emit UIEvent.EventType.transform, and you may see pointer effects. Apple is clear this hybrid behaviour exists for Device Hub and does not reflect real devices.
  • Downloaded app data containers land in a folder named after the bundle identifier, not an .xcappdata bundle. Apple’s release notes give the rename workaround.

Xcode 27’s release notes don’t mention iPhone Duo. Apple directs developers to Xcode 27.1 for the iPhone Duo simulator, and that shipped as a beta on 18 September 2026 — build 27A9269, carrying the iOS 27.1 SDK. Install it alongside Xcode 27 rather than over it, and read what its simulator cannot do before you plan a test pass around it.

A rebuild checklist

  1. Build with Xcode 27 on a branch, early, before you need to ship on it.
  2. Adopt the scene life cycle — or upgrade to a framework version that has — and retest deep links, notifications and every third-party SDK.
  3. Fix @State compile errors, then check TabView selection restoration.
  4. Recompile anything using MetricKit hitch metrics.
  5. Replace canOpenURL: checks and plan the On Demand Resources migration.
  6. Update scripts that depended on the Simulator app.
  7. Test on the iPhone Duo simulator, which you can do now — it is in the Xcode 27.1 beta. Our owner’s guide to iPhone Duo and iOS 27 covers what to look for.

Apple sources

Checked against these sources on . Apple’s written “Preparing your app for iPhone Duo” documentation and Xcode 27.1 beta were still listed as coming later this month on that date, so the Tech Talks and the Human Interface Guidelines are the authoritative references. We will update this post when the written documentation ships.

This post is part of our work onApp maintenance that keeps you ahead of every deadline

Related reading

Let's talk

Find out what iPhone Duo and iOS 27 mean for your app

Send us your App Store link and the stack it is built on. An engineer replies with what breaks, what to fix first, and a realistic effort estimate — no call and no obligation.

  • A written reply from an engineer
  • No call required
  • No obligation