Paul Beusterien
Paul Beusterien

Reputation: 29572

Build Swift for iOS and visionOS on both Xcode 14 and 15 without warnings

We'd like to find a way to write iOS-only Swift code blocks in code that supports multiple Apple platforms and runs without warnings on both Xcode 14 and 15.

It's complicated by the fact that #if os(iOS) evaluates to true for visionOS so the test #if os(iOS) && !os(visionOS) is needed to build iOS-only code on Xcode 15. However, this generates a warning on Xcode 14 since visionOS is not recognized.

#if os(iOS) && (swift(<5.9) || !os(visionOS)) also generates warnings on Xcode 14.

We've found that the following runs warning free on both:

    #if swift(>=5.9)
      #if os(iOS) && !os(visionOS)
        code block
      #endif
    #else 
      #if os(iOS)
        code block
      #endif
    #endif

But this is ugly since the code block needs to be duplicated. Is there a better way?

Upvotes: 2

Views: 1067

Answers (2)

rob mayoff
rob mayoff

Reputation: 385840

TLDR: Add a version-specific package manifest that defines a build condition when building for visionOS.

Full details:

I haven't tested this, so I'm not 100% sure it will work. Also, Xcode 15.0 and Xcode 15.1 did not ship with a visionOS SDK but did ship with Swift 5.9, so that also might cause problems. Am I willing to download Xcode 14.3, Xcode 15.0, and Xcode 15.1 to test this solution? No, but I encourage you to do so. 😅 Anyway…

You say you're an SDK vendor, so I assume you're distributing a Swift Package Manager (SwiftPM) package.

SwiftPM supports “Version-specific Manifest Selection”. You can create two package manifests: one named Package.swift and another named [email protected]. A build system that supports Swift 5.9 or later uses the [email protected] manifest, and a build system that doesn't support Swift 5.9 uses Package.swift.

Xcode 15.0 supports Swift 5.9, and earlier Xcodes do not. So Xcode 14 will use Package.swift, and Xcode 15 (and eventually Xcode 16, etc.) will use [email protected].

Create [email protected] as a copy of Package.swift. Update the swift-tools-version line at the top of [email protected] to version 5.9. Then (still in [email protected]) add a swiftSetting to your target as follows:

.target(
    name: "PaulSDK",
    swiftSettings: [
        .define("supportsVisionOS", .when(platforms: [.visionOS])),
    ]
),

Then, in your code, check whether you're building for visionOS by checking the build condition:

#if supportsVisionOS
print("heyo it's visionOS")
#else
print("great sadness")
#endif

Upvotes: 0

HangarRash
HangarRash

Reputation: 15053

Under Xcode 14.3 and Xcode 15, the following will allow you to compile without any warnings:

#if swift(>=5.9) && os(visionOS)
    // visionOS code, if any, under Xcode 15
#elseif os(iOS)
    // iOS code under Xcode 14/15
#endif

Of course you can add other #elseif os(xxx) as needed (for example, macOS).

Under Xcode 14.2 you will get a warning about the unknown visionOS but the code will otherwise build correctly without any code duplication.

Upvotes: 0

Related Questions