feat(🍏): Swift Package Manager support for iOS - #4043
Conversation
b66fe1e to
2105f86
Compare
React Native 0.87 ships preview SwiftPM support, and CocoaPods trunk goes read-only in December 2026. A library that ships its own Package.swift is referenced verbatim by autolinking, so this is additive: SwiftPM ignores the podspec and CocoaPods ignores Package.swift. Autolinking exposes the library through a symlink under the app's build directory and resolves the manifest's relative paths against it, so the two React Native package paths are fixed for every standard app. Skia's binaries stay out of the package. The manifest prefers the react-native-skia-apple-ios copy npm already installs for the CocoaPods build and falls back to the published Swift package, so a checkout that has run `yarn install` builds without network access. Two defines the podspec never needed: CocoaPods forces RCT_NEW_ARCH_ENABLED and RCT_REMOVE_LEGACY_ARCH project-wide, and the SwiftPM path defines neither, yet Skia's Apple sources still gate on both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Covers the React Native 0.87 floor, how autolinking resolves the manifest's relative paths, the two architecture defines CocoaPods supplies but SwiftPM does not, where the binaries come from, and the stale Package.resolved pin that silently keeps the previous binary source when switching between them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2105f86 to
617a4db
Compare
wcandillon
left a comment
There was a problem hiding this comment.
This PR (or it could be an another PR) needs to update the https://github.com/Shopify/react-native-skia/blob/main/.github/workflows/build-skia-graphite.yml to publish artifacts that can be used by SPM? e.g an .xcframework as a .zip file? Is my understanding correct that this would be the very first step? From there we can test the publication of the Package.swift?
|
No change needed there — The binaries repo downloads its That makes the order: land #9 → cut a Graphite release from it. This PR doesn't depend on either step — it links the binaries from the npm package by path, the same as CocoaPods does today. |
Motivation
CocoaPods trunk goes read-only on 2 December 2026, and React Native 0.87 ships preview Swift Package Manager support.
@shopify/react-native-skiais CocoaPods-only today; this makes it consumable as a Swift package.Purely additive: SwiftPM ignores the podspec, CocoaPods ignores
Package.swift. iOS and Ganesh only.pod installinapps/examplestill works.What is here
Package.swiftpath: "."include/ReactNativeSkia.hpublicHeadersPath, deliberately emptyreact-native.config.jspackage.jsonfiles, so consumers receive the manifestWhy the manifest looks the way it does, all documented in
CONTRIBUTING.md:.headerSearchPathcannot escape the target path, so anapple/-rooted target would need../cpp/.....package(path:)against that symlink, not againstpackages/skia.RCT_NEW_ARCH_ENABLEDandRCT_REMOVE_LEGACY_ARCHitself. CocoaPods forces both project-wide; React Native's SwiftPM path sets neither, and Skia's Apple sources gate on them in 21 places. Without them-getTurboModule:is dropped and the JSI bindings never install.SkMathPriv.hcallsstd::countl_zero,std::countr_zeroandstd::popcount; the podspec'sc++17pin is already stale.SkJSONReader.cppis listed explicitly —libskottie.aneeds fourskjson::symbols that no Apple archive defines.RN_SPM_REMOTE_URL) is unsupported: it rewrites the React Native package identity, so one committed manifest cannot serve both modes.Binaries come from the
react-native-skia-apple-iosnpm package, the same one CocoaPods uses, resolved by path so an installed checkout builds offline. When it is missing, which is what an--omit=optionalinstall looks like, the manifest fails with an explanatory message instead of an opaque resolution error. Fetching them from a released Swift package instead is future work, worth doing only once those npm packages are no longer dependencies; see wcandillon/react-native-skia-binaries#9.Other Apple platforms
Not a dead end. Skia's sources are already portable:
RNSkUIKit.hmaps the platform view toUIVieworNSView. Thereact-native-skia-apple-macosand-tvospackages already ship correct manifests.Three blockers, all upstream:
platforms: [.iOS(.v15)]. A package cannot declare macOS if its dependencies do not. The SDK plumbing already mapsappletvos*andmacosx*, so this is a declaration gap, not a redesign.react-native-macosis on 0.81.8 and ships noscripts/spm. tvOS runs onreact-native-tvos. Each needs SwiftPM support first.libskia. That needs suffixed targets or merged xcframeworks — see feat: publish the Skia binaries as a remote Swift package wcandillon/react-native-skia-binaries#9.Then this manifest needs three edits: widen
platforms:, make the linked frameworks conditional (UIKit or AppKit), and point the binaries probe at the matching package. Android and web are unaffected, since SwiftPM is Apple-only.Test plan
CI does not exercise this PR on its own; a follow-up adds an example app and the
build-test-ios-spmjob. With that harness:spm addwith no manifest exits 2 naming the library. Green: it resolves as self-managed.binaryTarget(url:)download and checksum enforcement were proven against a test release on a fork.pod installinapps/examplesucceeds.Re-verified with matching versions after a clean root install:
react-native-skia-apple-ios152.0.0 against milestone-152 headers, Release build, rendered on an iPhone 17 Pro simulator.