Skip to content

feat(ios): UIScene Support#8536

Open
theproducer wants to merge 13 commits into
mainfrom
RMET-5224
Open

feat(ios): UIScene Support#8536
theproducer wants to merge 13 commits into
mainfrom
RMET-5224

Conversation

@theproducer

@theproducer theproducer commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Description

Adds UIScene support to Capacitor, which is required in iOS 27

Change Type

  • Fix
  • Feature
  • Refactor
  • Breaking Change
  • Documentation
  • Other (CI, chores, etc.)

Rationale / Problems Fixed

fixes: #7961

Tests or Reproductions

Screenshots / Media

Platforms Affected

  • Android
  • iOS
  • Web

Notes / Comments

@theproducer
theproducer requested review from a team and markemer and removed request for a team July 22, 2026 16:53
@theproducer
theproducer marked this pull request as ready for review July 22, 2026 16:54
@theproducer theproducer changed the title feat: UIScene Support feat(ios): UIScene Support Jul 22, 2026
var window: UIWindow?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this one need all the UIWindow stuff?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably use this same logic for the pods-template SceneDelegate right? that way we aren't overriding the window?

])
}

// TODO: Not until Phase 2 of the UI modernization project

@markemer markemer Jul 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipping this with 9? Or just later in 8.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, I'll remove these comments for now. The planned UI modernization is "planned" for 10, but im pushing for 9.

Either way these can be removed for the time being.

var window: UIWindow?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably use this same logic for the pods-template SceneDelegate right? that way we aren't overriding the window?

Comment on lines +20 to +26
if !connectionOptions.urlContexts.isEmpty {
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
}

for userActivity in connectionOptions.userActivities {
self.scene(scene, continue: userActivity)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found one more gap when testing the @capacitor/app plugin with cold-start deep links. They never reach the appUrlOpen listener. I believe this is because the URL arrives before the bridge has fully loaded.

This fix suggested by Claude worked on my end:

Suggested change
if !connectionOptions.urlContexts.isEmpty {
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
}
for userActivity in connectionOptions.userActivities {
self.scene(scene, continue: userActivity)
}
// Plugins haven't loaded yet on a cold start, so notifications posted here are
// missed. Deliver them on the first capacitorViewDidAppear, once plugins are
// registered.
var token: NSObjectProtocol?
token = NotificationCenter.default.addObserver(forName: .capacitorViewDidAppear, object: nil, queue: .main) { _ in
if let token {
NotificationCenter.default.removeObserver(token)
}
if !connectionOptions.urlContexts.isEmpty {
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
}
for userActivity in connectionOptions.userActivities {
self.scene(scene, continue: userActivity)
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLIENT OF UIKIT REQUIRES UPDATE: This process does not adopt UIScene lifecycle. This will become an assert in a future version.

4 participants