Skip to content

chore: raise minimum supported platform, Swift, and Xcode versions - #4271

Merged
harsh62 merged 3 commits into
mainfrom
chore/bump-minimum-versions
Aug 13, 2026
Merged

chore: raise minimum supported platform, Swift, and Xcode versions#4271
harsh62 merged 3 commits into
mainfrom
chore/bump-minimum-versions

Conversation

@harsh62

@harsh62 harsh62 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Issue

Apple has required Xcode 26 and the 26 SDKs for App Store Connect uploads since April 28, 2026. The support policy in README.md states that Amplify Swift updates its minimum Swift version within 60 days of Apple's change, so this is overdue.

This also lands ahead of AWS SDK for Swift's own proposed bump (~September 2026), so we move by plan rather than being forced by an upstream dependency.

Description

Platform floors now match Apple's published Xcode 26 support matrix, and the Swift toolchain floor matches AWS SDK for Swift.

Before After
iOS 13 15
tvOS 13 15
macOS 12 12 (unchanged)
watchOS 9 9 (unchanged)
visionOS undeclared 1.0, declared + GA
swift-tools-version 5.9 6.0
Minimum Xcode 16.0 26.0

Notes on the choices:

  • watchOS stays at 9. Apple's Xcode 26 floor is watchOS 8 and the AWS SDK proposal moves to 8, but we are already above that — lowering it would widen support rather than raise it. Same reasoning for macOS 12.
  • visionOS was never declared in Package.swift. It was documented as inherited from the iOS deployment target and built in CI, but had no .visionOS() entry. It is now explicitly declared and marked GA, and the README footnote describing the old inherited behaviour is removed.

Swift 6 language mode is intentionally NOT in this PR

Raising swift-tools-version to 6.0 silently flips the default language mode to Swift 6. To keep this change behaviour-neutral, swiftLanguageModes: [.v5] pins the existing behaviour. Measured separately, the Swift 6 migration is ~350 genuine strict-concurrency sites (concentrated in Storage, DataStore, and Auth); that belongs in its own PR.

CoreML predictions plugin now excludes tvOS explicitly

The tvOS build failed with 'SFSpeechRecognitionResult' is unavailable in tvOS. That type is marked API_UNAVAILABLE(tvos), and the plugin relied on #if canImport(Speech) to compile itself out.

As of the Xcode 26 SDKs the tvOS Speech framework ships a module, so canImport(Speech) now succeeds on tvOS while the type remains unavailable — the guard silently stopped excluding the platform. Adding && !os(tvOS) restores the previous behaviour.

Verified this is an SDK change rather than a consequence of the deployment-target bump: the same file fails to compile against the Xcode 26 tvOS SDK at both tvos13.0 and tvos15.0. The guard is applied to every file in the plugin, not only the Speech types, because the configure/reset/client-behavior files reference those types and were previously compiled out as a unit.

CI changes are limited to what this bump requires

Only version-coupled updates are included: runner images, the Xcode version map (latest 26.3 → 26.5, minimum 16.0.0 → 26.0.1), simulator devices that exist on the new image (iPhone 17 Pro Max, Apple Watch Series 11), visionOS added to the minimum-version build matrix, and swiftformat's --swiftversion raised to 6.0 to match the tools version.

No timeout or cache changes are in this PR — those are unrelated CI reliability work tracked separately in #4269.

Semver

Treated as a minor release, not a breaking change, consistent with how AWS SDK for Swift is handling their equivalent bump.

How did you test these changes?

Locally on Xcode 26.5 (Swift 6.3.2):

  • swift build — clean, 0 errors
  • swift test0 failures
  • xcodebuild build -scheme Amplify-Package verified end-to-end for iOS, macOS, and visionOS
  • All four floors verified to compile against the Xcode 26.5 SDKs: ios15.0, tvos15.0, watchos9.0, xros1.0
  • tvOS verified via SwiftPM cross-compilation (CoreMLPredictionsPlugin and AWSPredictionsPlugin for arm64-apple-tvos15.0-simulator), and confirmed macOS still compiles CoreMLPredictionService so the plugin stays active where Speech genuinely exists
  • swiftformat --lint . --swiftversion 6.0 — clean
  • All 75 workflow/action YAML files parse

Documentation

  • README.md — platform table, Swift version, Xcode requirement, stale visionOS footnote removed
  • CONTRIBUTING.md — Xcode version
  • AGENTS.md / CLAUDE.md
  • README-combine-support.md

Checklist

  • PR description included
  • yarn lint passed (swiftformat + swiftlint equivalents run)
  • Unit tests added/updated — no new tests; this is a configuration change validated by building and testing every supported platform at the new floors
  • Documentation updated

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@harsh62
harsh62 requested review from a team as code owners August 11, 2026 20:02
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 11, 2026 20:02 — with GitHub Actions Inactive
@harsh62
harsh62 temporarily deployed to IntegrationTest August 12, 2026 16:15 — with GitHub Actions Inactive
Apple has required Xcode 26 and the 26 SDKs for App Store Connect uploads
since April 28, 2026. Per the support policy in README.md, Amplify Swift
tracks the Swift version shipped with the minimum Xcode allowed for App
Store Connect uploads.

Platform floors now match Apple's published Xcode 26 support matrix, and
the Swift toolchain floor matches AWS SDK for Swift:

- iOS 13 -> 15
- tvOS 13 -> 15
- macOS 12 (unchanged)
- watchOS 9 (unchanged, already above Apple's floor of 8)
- visionOS: declared in Package.swift for the first time, promoted to GA
- swift-tools-version 5.9 -> 6.0
- Minimum Xcode 16.0 -> 26.0

Adopting the Swift 6 language mode is deliberately out of scope. Raising
swift-tools-version to 6.0 would otherwise flip the default language mode
to Swift 6, so `swiftLanguageModes: [.v5]` pins the existing behavior and
keeps this change behavior-neutral. The strict-concurrency migration is
tracked separately.

CI:
- Runners moved from macos-15 to macos-26
- Latest Xcode 26.3 -> 26.5; minimum 16.0.0 -> 26.0.1
- Removed the Xcode 16 legs and the duplicate hardcoded 16.4.0 pins
- Simulator devices updated to those present on macos-26 (iPhone 17 Pro
  Max, Apple Watch Series 11); minimum-Xcode legs use the 26.2 runtime
  because the image ships 26.0 SDKs but installs no 26.0 runtime
- visionOS added to the minimum-supported-version build matrix, which
  previously never exercised the platform the docs call supported
- Added an advisory, non-blocking nightly build against the Xcode 27
  preview image for early warning on the next Xcode release

Docs: corrected the stale Xcode 13.4 requirement in CONTRIBUTING.md.

Three test files were reformatted because raising swiftformat's
--swiftversion to 6.0 activates the preferCountWhere rule.
The tvOS build failed with "'SFSpeechRecognitionResult' is unavailable in
tvOS". SFSpeechRecognitionResult is marked API_UNAVAILABLE(tvos), and the
CoreML predictions plugin was relying on `#if canImport(Speech)` to compile
itself out on tvOS.

As of the Xcode 26 SDKs, the tvOS Speech framework ships a module
(module.modulemap and Speech.swiftmodule), so canImport(Speech) now
succeeds on tvOS while the type itself remains unavailable. The guard
silently stopped excluding the platform.

Verified this is an SDK change and not a consequence of raising the tvOS
deployment floor: the same file fails to compile against the Xcode 26 tvOS
SDK at both tvos13.0 and tvos15.0.

Adding `&& !os(tvOS)` restores the pre-Xcode-26 behavior. Applied to every
file in the CoreML plugin rather than only the Speech types, because the
plugin's configure/reset/client-behavior files reference those types and
were previously compiled out as a unit.

Verified by building CoreMLPredictionsPlugin and AWSPredictionsPlugin for
arm64-apple-tvos15.0-simulator, and confirming macOS still compiles
CoreMLPredictionService so the plugin stays active where Speech is
genuinely available.
Integration tests failed to build with:

  compiling for iOS 14.0, but module 'Amplify' has a minimum deployment
  target of iOS 15.0

Raising the package floor to iOS 15 left four Xcode projects behind, so they
still tried to link an Amplify built for a newer target than their own:

  APIHostApp            13.0 -> 15.0
  DataStoreHostApp      13.0 -> 15.0
  PredictionsHostApp    14.0 -> 15.0
  canaries/example      14.4 -> 15.0

Checked the other platforms for the same gap and found none: watchOS host
apps are at 9.0/9.4/10.0 against a floor of 9, tvOS is at 16.4 against 15,
macOS is at 14.6/15.0 against 12, and StorageHostApp's Base.xcconfig was
already 15.0/12.0.
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.79%. Comparing base (c2814bc) to head (e502e4c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4271      +/-   ##
==========================================
- Coverage   66.81%   66.79%   -0.03%     
==========================================
  Files        1170     1170              
  Lines       44565    44565              
==========================================
- Hits        29777    29766      -11     
- Misses      14788    14799      +11     
Flag Coverage Δ
API_plugin_unit_test 68.33% <ø> (-0.03%) ⬇️
AWSPluginsCore 68.07% <ø> (ø)
Amplify 47.49% <ø> (+0.01%) ⬆️
Amplify_Foundation_Bridge_unit_test 62.28% <ø> (ø)
Amplify_Foundation_unit_test 67.64% <ø> (ø)
Analytics_plugin_unit_test 83.43% <ø> (ø)
Auth_plugin_unit_test 72.38% <ø> (-0.08%) ⬇️
Connect_unit_test 42.95% <ø> (ø)
DataStore_plugin_unit_test 81.83% <ø> (ø)
EventEnrichment_unit_test 88.98% <ø> (ø)
Firehose_plugin_unit_test 53.15% <ø> (ø)
Geo_plugin_unit_test 73.39% <ø> (ø)
Kinesis_plugin_unit_test 52.17% <ø> (ø)
Logging_plugin_unit_test 64.86% <ø> (ø)
Predictions_plugin_unit_test 34.09% <ø> (ø)
PushNotifications_plugin_unit_test 84.58% <ø> (ø)
RecordCache_unit_test 76.40% <ø> (ø)
Storage_plugin_unit_test 78.67% <ø> (ø)
unit_tests 66.79% <ø> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

2 participants