Skip to content

Add visionOS support - #350

Draft
kikeenrique wants to merge 11 commits into
cashapp:mainfrom
kikeenrique:feature/visionos-support
Draft

kikeenrique wants to merge 11 commits into
cashapp:mainfrom
kikeenrique:feature/visionos-support

Conversation

@kikeenrique

Copy link
Copy Markdown

Fixes #349.

Draft for reference alongside the discussion in #349 — happy to reshape it based on the
answers there (e.g. platform conditionals instead of replacing the UIScreen reads, or
holding for the swift-snapshot-testing strategy story).

What this does

  • Package.swift: bumps swift-tools-version to 5.9 and declares .visionOS(.v1).
    The bump required migrating the two remote dependencies off the deprecated
    .package(name:url:) form; target dependencies now reference the products by package
    identity.
  • Removes all UIScreen usage from the visionOS-supported targets.
    UIView.effectiveDisplayScale (in AccessibilitySnapshotParser) reads the scale from
    the view's trait environment, and SnapshotPlatformDefaults (in
    AccessibilitySnapshotCore) supplies the host-window frame that previously came from
    UIScreen.main.bounds, with an explicit 1280×720 default on visionOS. This also
    removes the deprecated UIWindow.screen reads in SnapshotAndLegendView.
  • Gates the three SnapshotTesting strategy files to #if os(iOS) || os(tvOS) —
    swift-snapshot-testing only vends its UIKit image strategies on those platforms. The
    AccessibilitySnapshot product builds for visionOS but vends no strategies there yet;
    the parser, core rendering, and previews layers are fully available.
  • FBSnapshotTestCase-Accessibility(-ObjC) remain iOS-only (ios-snapshot-test-case
    does not support visionOS).
  • CI: Scripts/build.swift gains a visionOS_26 platform (build-only,
    generic/platform=visionOS Simulator, xrsimulator SDK) and the spm job builds it
    in a matrix alongside iOS.
  • No behavior change on iOS: traitCollection.displayScale matches the previous
    UIScreen-derived scale, and the default host-window frame is unchanged there.

Notes

  • ASAccessibilityEnabler needs no changes: the visionOS simulator runtime ships
    usr/lib/libAccessibility.dylib exporting the automation symbols, and CoreSimulator
    sets IPHONE_SIMULATOR_ROOT on visionOS simulators just as on iOS.
  • UIAccessibilityStatusUtility (Smart Invert mocking) compiles for visionOS but is
    unreachable there while the strategies are gated; runtime validation is a follow-up.

Testing

  • Full existing iOS snapshot suites pass unchanged (iOS 17.5 / 18.5 / 26.2 lanes) — the
    display-scale refactor produced zero reference-image diffs.
  • The new visionOS lane builds all visionOS-supported products against the visionOS
    simulator SDK.
  • swift test on AccessibilitySnapshotModel passes.

Follow-ups (intentionally not in this PR)

  • visionOS reference images and test targets.
  • Smart Invert (fishhook) runtime validation on visionOS.
  • visionOS destinations in the Tuist example project (needs the iOSSnapshotTestCase
    dependency split out of the example targets first).
  • A visionOS Snapshotting strategy story, pending upstream support in
    swift-snapshot-testing (open PR: Support visionOS behind compiler directives pointfreeco/swift-snapshot-testing#1116; alternatively
    a local base-strategy implementation). Once that lands, the #if os(iOS) || os(tvOS)
    gates here can widen to include visionOS.

…faults

UIScreen (and UIWindow.screen) are unavailable on visionOS. Reads of the
screen scale now go through the view's trait environment, and the places
that fell back to the main screen's bounds for a host window use a
platform default instead.
…ng supports

swift-snapshot-testing only vends its UIKit image strategies on iOS and
tvOS, so the strategies built on top of them are gated to those platforms.
The AccessibilitySnapshot product still builds for visionOS, where the
parser, core rendering, and previews layers remain fully available.
Xcode 27 rejects iOS deployment targets below 15.0, so the Example targets
and the Tuist-built dependencies (iOSSnapshotTestCase, Paralayout,
SnapshotTesting) now target iOS 15.0. The library's own minimum is
unchanged, since SwiftPM only warns about it.

Apps built with the iOS 27 SDK must also adopt the UIScene life cycle, so
the demo app's window setup moves into a SceneDelegate.
The iOS 26 and visionOS 26 CI legs move to the xcode-27 runner (macOS 27
host, Xcode 27.0) as iOS 27 and visionOS 27, and the model-test and
string-validation jobs move off the deprecated macOS 14 image. The iOS 17
and iOS 18 legs are unchanged.

The build script gains iOS_27 and visionOS_27 alongside the 26 platforms,
and each visionOS platform now pins its own runtime on the Apple Vision Pro
simulator instead of a generic destination. The iOS 27 image ships no
iPhone 17 Pro, so iOS 27 runs on iPhone 18 Pro, which shares its 402x874
@3x screen. Reference images for iOS 27.0 are recorded with Xcode 27.0
(27A266a).
Apps built with the iOS 27 SDK must adopt the scene life cycle, but the
host app's life cycle changes how snapshots render: the snapshot functions
host views in a UIWindow(frame:), which UIKit attaches to the app's scene
only in a legacy app. In a scene-based app that window has no windowScene,
so views laid out against the status bar shift and the iOS 17/18 reference
images no longer match.

The Example now builds both hosts from the same sources. The legacy
AccessibilitySnapshotDemo (app delegate owns the window, as before) hosts
SnapshotTests and UnitTests for toolchains before Xcode 27. The new
AccessibilitySnapshotDemoScenes (scene delegate owns the window) hosts
SnapshotTestsScenes and UnitTestsScenes for Xcode 27 and later. Both apps
share the AccessibilitySnapshotDemo module name, so the tests compile
unchanged against either host. CI picks the host per leg.

The iOS 27 reference images were recorded with the scene-based host, so
they move to the SnapshotTestsScenes folders, and testCustomContentDemo's
iOS 27 reference is replaced with the CI runner's render, which differs
from a local Xcode 27 render by two anti-aliased pixels.
The development requirements listed Xcode 12.5.1/14.3.1 and iOS 16.4/17.2
simulators. They now mirror the CI legs and Scripts/build.swift, explain the
legacy and scene-based host apps and when to use each, and describe how to
record reference images.
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.

visionOS support

1 participant