Skip to content

feat: Add macOS support to Swift Package Manager build system#2815

Draft
Saadnajmi wants to merge 8 commits intomicrosoft:mainfrom
Saadnajmi:feature/spm-macos-support
Draft

feat: Add macOS support to Swift Package Manager build system#2815
Saadnajmi wants to merge 8 commits intomicrosoft:mainfrom
Saadnajmi:feature/spm-macos-support

Conversation

@Saadnajmi
Copy link
Collaborator

@Saadnajmi Saadnajmi commented Jan 17, 2026

Summary

Extends the Swift Package Manager (SPM) build system to support macOS, building on the existing iOS/visionOS SPM infrastructure. This enables building React Native as an xcframework with a macOS slice.

Changes

Package.swift

  • Added .macOS(.v14) to platforms
  • Created React-RCTUIKit as its own SPM module — RCTUIKit needs conditional UIKit (iOS/visionOS) vs AppKit (macOS) linking, which requires it to be a separate target
  • Added "RCTUIKit" to React-Core excludedPaths to avoid overlapping sources, and added .reactRCTUIKit as a dependency
  • Added conditional linker settings for React-graphics-Apple and React-RCTUIKit:
    .linkedFramework("UIKit", .when(platforms: [.iOS, .visionOS]))
    .linkedFramework("AppKit", .when(platforms: [.macOS]))
  • Removed macOS platform paths from exclude lists in reactFabric and reactFabricComponents so macOS-specific C++ files (HostPlatformViewProps, HostPlatformViewEventEmitter, etc.) get compiled

scripts/ios-prebuild/hermes.js

  • Ported findMatchingHermesVersion() from Ruby (hermes-utils.rb) to JavaScript — maps react-native-macos version to upstream RN version via peerDependencies['react-native'] in package.json, so Hermes artifacts can be downloaded from Maven
  • Ported hermesCommitAtMergeBase() from Ruby — finds the Hermes commit at the merge base with facebook/react-native for main branch builds where no prebuilt artifacts exist (version 1000.0.0)
  • Added allowBuildFromSource flag to hermesSourceType() so the nightly fallback behavior isn't broken — only allows BUILD_FROM_HERMES_COMMIT when on main branch with no explicit HERMES_VERSION
  • Added ensureMacOSSliceInXCFramework() — after downloading the Hermes tarball from Maven, rebuilds the xcframework to include the macOS slice. The tarball already contains a standalone macOS framework at destroot/Library/Frameworks/macosx/ but it's not included in the xcframework at destroot/Library/Frameworks/universal/. SPM's BinaryTarget requires an xcframework, so we use xcodebuild -create-xcframework to reassemble it with all existing slices plus macOS. This avoids needing any upstream changes to Meta's Hermes publishing pipeline.

scripts/ios-prebuild/setup.js

  • Added link('React/RCTUIKit', 'React') for RCTUIKit header linking
  • Added macOS view platform header links with both prefixed and unprefixed paths:
    link('ReactCommon/react/renderer/components/view/platform/macos',
         'ReactCommon/react/renderer/components/view');
    link('ReactCommon/react/renderer/components/view/platform/macos',
         'react/renderer/components/view');
    Both are needed because includes use <react/renderer/components/view/MouseEvent.h> which resolves via the non-prefixed search path.

scripts/ios-prebuild/cli.js & types.js

  • Added 'macos' to the Platform type and platforms array
  • Added 'macOS' to the Destination type and platformToDestination map

How to test locally

cd packages/react-native

# Run setup (downloads deps, runs codegen, links headers, rebuilds Hermes xcframework with macOS slice)
node scripts/ios-prebuild.js -s -f Debug

# Build for macOS
node scripts/ios-prebuild.js -b -f Debug -p macos

# Or build all platforms and compose xcframework
node scripts/ios-prebuild.js -f Debug

Dependencies

Test plan

  • node scripts/ios-prebuild.js -s -f Debug completes successfully
  • node scripts/ios-prebuild.js -b -f Debug -p macos enters compilation phase
  • macOS-specific C++ files (HostPlatformViewProps.cpp, HostPlatformViewEventEmitter.cpp) are compiled
  • Hermes xcframework rebuilt with macOS slice after tarball extraction
  • Full macOS build completes (blocked on porting fixes in fix(macos): fix compilation errors for macOS target #2868)
  • swift package describe --type json outputs valid build graph with macOS targets

🤖 Generated with Claude Code

@Saadnajmi Saadnajmi requested a review from a team as a code owner January 17, 2026 03:48
@Saadnajmi Saadnajmi changed the title feat: Add macOS support to Swift Package Manager build system (claude code generated) feat: Add macOS support to Swift Package Manager build system Jan 17, 2026
@Saadnajmi Saadnajmi marked this pull request as draft January 17, 2026 03:56
[pull] main from microsoft:main
@Saadnajmi Saadnajmi force-pushed the feature/spm-macos-support branch from a22ab6e to 30d348a Compare March 23, 2026 03:19
@changeset-bot
Copy link

changeset-bot bot commented Mar 23, 2026

⚠️ No Changeset found

Latest commit: b7c5a29

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@Saadnajmi Saadnajmi changed the title (claude code generated) feat: Add macOS support to Swift Package Manager build system feat: Add macOS support to Swift Package Manager build system Mar 23, 2026
Saadnajmi and others added 4 commits March 23, 2026 09:29
- RCTLinkingManager.mm: combine iOS and macOS implementations into a
  single file using #if TARGET_OS_OSX guards, remove macos/ overlay
  directory, and clean up podspec
- RCTCursor.m: replace Foundation + conditional AppKit imports with
  RCTUIKit umbrella header
- RCTViewComponentView.mm: remove duplicate cursor property check
  introduced during merge

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add .macOS(.v14) platform to Package.swift
- Create React-RCTUIKit as its own SPM module with conditional UIKit/AppKit linking
- Port findMatchingHermesVersion and hermesCommitAtMergeBase from Ruby to JS
- Add macOS platform and destination to prebuild CLI
- Link RCTUIKit and macOS view platform headers in setup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add "macosx" to the create_universal_framework call so the published
Hermes xcframework includes a native macOS slice. The macOS framework
is already built by build-mac-framework.sh and placed in
destroot/Library/Frameworks/macosx/ — it just wasn't included in the
xcodebuild -create-xcframework step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rball

When downloading prebuilt Hermes from Maven, the tarball contains a
standalone macOS framework at destroot/Library/Frameworks/macosx/ but
the xcframework at destroot/Library/Frameworks/universal/ does not
include it. After extraction, rebuild the xcframework using
xcodebuild -create-xcframework to include the macOS slice.

This is a workaround until the upstream build-ios-framework.sh change
(commit 2) is adopted by Meta's CI pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Saadnajmi Saadnajmi force-pushed the feature/spm-macos-support branch 4 times, most recently from 5f31f61 to fa8de90 Compare March 23, 2026 15:30
Add a new reusable workflow (microsoft-build-spm.yml) that tests SPM
builds for ios, macos, and visionos on every PR. Wire it into the PR
gate job in microsoft-pr.yml.

Also add visionos/visionos-simulator as supported platforms in the
ios-prebuild CLI so CI and local builds can target visionOS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Saadnajmi Saadnajmi force-pushed the feature/spm-macos-support branch from fa8de90 to 21908c3 Compare March 23, 2026 15:53
Saadnajmi and others added 2 commits March 23, 2026 10:58
The cleanup commit accidentally removed the core dark mode fix from
HostPlatformColor.mm. This re-adds it using performAsCurrentDrawingAppearance
instead of manual NSAppearance save/restore for cleaner, exception-safe code.

- ColorFromUIColor: resolve dynamic colors against effective appearance
- hashFromUIColor: hash both light and dark variants for proper invalidation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant