Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5b89deb
Add script to init a MacOS test app
kraenhansen Oct 27, 2025
b4c7469
Update Podspec to detect React Native package name
kraenhansen Oct 27, 2025
e67510a
Add changeset
kraenhansen Oct 27, 2025
4f1711e
Add job in the check workflow to initialize and build the MacOS test app
kraenhansen Oct 27, 2025
1f23c01
Fall-back on non-universal libraries when getting path for weak-node-…
kraenhansen Oct 27, 2025
afb5f61
Enable Hermes and Fabric
kraenhansen Oct 28, 2025
17ff79e
No need to Setup Android SDK
kraenhansen Oct 28, 2025
e1b3cea
Debugging with Copilot
kraenhansen Oct 28, 2025
4b9faf2
Pass --mode when building from CLI
kraenhansen Oct 28, 2025
44609d5
Don't pod install when initializing
kraenhansen Oct 28, 2025
d589923
Moved patching of JSI headers to a separate function
kraenhansen Oct 28, 2025
0f98a0e
Patch react_native_post_install to pass react native path
kraenhansen Oct 28, 2025
ab26a44
Install CMake 3.22
kraenhansen Oct 28, 2025
df8f1a0
Fix bootstrap issue
kraenhansen Oct 28, 2025
f52a402
Trying a higher CMake version
kraenhansen Oct 28, 2025
18c9857
Set up files in private packages
kraenhansen Oct 28, 2025
723f7b9
Patch macos app with scripts and source files
kraenhansen Oct 28, 2025
f660946
Remove platform restriction from host package's podspec
kraenhansen Oct 28, 2025
c23325b
Commit update from bootstrapping
kraenhansen Oct 28, 2025
838e783
Reconstruct missing symbolic links if needed
kraenhansen Oct 28, 2025
070e61f
Remove debug info from workflow
kraenhansen Oct 28, 2025
eaaef56
Moved "ios" into a shared "apple" directory
kraenhansen Oct 28, 2025
46e731b
Simplify Apple host module provider
kraenhansen Oct 28, 2025
012d85f
Restore weak-node-api symlinks
kraenhansen Oct 28, 2025
4cf9011
Re-arm the init script
kraenhansen Oct 28, 2025
77ed18d
Build universal Darwin libraries
kraenhansen Oct 28, 2025
5080c23
Add missing x86_64-apple-darwin Rust target to macOS CI job (#298)
Copilot Oct 28, 2025
395409a
Move linked deps into install command to make --install-links effective
kraenhansen Oct 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silly-mice-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-native-node-api": patch
---

Detects "pod install" from React Native MacOS apps and vendors Hermes accordingly
34 changes: 34 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,40 @@ jobs:
# TODO: Enable release mode when it works
# run: npm run test:ios -- --mode Release
working-directory: apps/test-app
test-macos:
# Disabling this on main for now, as initializing the template takes a long time and
# we don't have macOS-specific code yet
if: contains(github.event.pull_request.labels.*.name, 'MacOS 💻')
name: Test app (macOS)
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/jod
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'jod' to 'iron'. The Node.js LTS codename should be 'iron'.

Copilot uses AI. Check for mistakes.
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: "17"
distribution: "temurin"
# Install CMake 3 since 4.x may have compatibility issues with Hermes build system
- name: Install compatible CMake version
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: "3.31.2"
- run: rustup target add x86_64-apple-darwin
- run: npm ci
- run: npm run bootstrap
env:
CMAKE_RN_TRIPLETS: arm64;x86_64-apple-darwin
FERRIC_TARGETS: aarch64-apple-darwin,x86_64-apple-darwin
- run: npm run init-macos-test-app
- run: pod install --project-directory=macos
working-directory: apps/macos-test-app
- name: Build MacOS test app
run: npx react-native build-macos --mode Release
working-directory: apps/macos-test-app
# TODO: Run the app eventually
test-android:
if: github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'Android 🤖')
name: Test app (Android)
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ node_modules/
dist/

*.tsbuildinfo

# Treading the MacOS app as ephemeral
apps/macos-test-app
29 changes: 16 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"test": "npm test --workspace react-native-node-api --workspace cmake-rn --workspace gyp-to-cmake --workspace node-addon-examples",
"bootstrap": "node --run build && npm run bootstrap --workspaces --if-present",
"prerelease": "node --run build && npm run prerelease --workspaces --if-present",
"release": "changeset publish"
"release": "changeset publish",
"init-macos-test-app": "node scripts/init-macos-test-app.ts"
},
"author": {
"name": "Callstack",
Expand Down Expand Up @@ -64,6 +65,7 @@
"globals": "^16.0.0",
"prettier": "^3.6.2",
"react-native": "0.81.4",
"read-pkg": "^9.0.1",
"tsx": "^4.20.5",
"typescript": "^5.8.0",
"typescript-eslint": "^8.38.0"
Expand Down
8 changes: 7 additions & 1 deletion packages/ferric-example/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "@react-native-node-api/ferric-example",
"version": "0.1.1",
"private": true,
"type": "commonjs",
"version": "0.1.1",
"homepage": "https://github.com/callstackincubator/react-native-node-api",
"repository": {
"type": "git",
Expand All @@ -11,6 +11,12 @@
},
"main": "ferric_example.js",
"types": "ferric_example.d.ts",
"files": [
"ferric_example.js",
"ferric_example.d.ts",
"ferric_example.apple.node",
"ferric_example.android.node"
],
"scripts": {
"build": "ferric build",
"bootstrap": "node --run build"
Expand Down
58 changes: 45 additions & 13 deletions packages/ferric/src/cargo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,46 @@ import {
isThirdTierTarget,
} from "./targets.js";

const APPLE_XCFRAMEWORK_CHILDS_PER_TARGET: Record<AppleTargetName, string> = {
"aarch64-apple-darwin": "macos-arm64_x86_64", // Universal
"x86_64-apple-darwin": "macos-arm64_x86_64", // Universal
/**
* A per apple target mapping to a list of xcframework slices in order of priority
*/
const APPLE_XCFRAMEWORK_SLICES_PER_TARGET: Record<AppleTargetName, string[]> = {
"aarch64-apple-darwin": [
"macos-arm64_x86_64", // Universal
"macos-arm64",
],
"x86_64-apple-darwin": [
"macos-arm64_x86_64", // Universal
"macos-x86_64",
],

"aarch64-apple-ios": "ios-arm64",
"aarch64-apple-ios-sim": "ios-arm64_x86_64-simulator", // Universal
"x86_64-apple-ios": "ios-arm64_x86_64-simulator", // Universal
"aarch64-apple-ios": ["ios-arm64"],
"aarch64-apple-ios-sim": [
"ios-arm64_x86_64-simulator", // Universal
"ios-arm64-simulator",
],
"x86_64-apple-ios": [
"ios-arm64_x86_64-simulator", // Universal
"ios-x86_64-simulator",
],

"aarch64-apple-visionos": "xros-arm64",
"aarch64-apple-visionos-sim": "xros-arm64_x86_64-simulator", // Universal
"aarch64-apple-visionos": ["xros-arm64"],
"aarch64-apple-visionos-sim": [
"xros-arm64_x86_64-simulator", // Universal
"xros-arm64-simulator",
],
// The x86_64 target for vision simulator isn't supported
// see https://doc.rust-lang.org/rustc/platform-support.html

"aarch64-apple-tvos": "tvos-arm64",
"aarch64-apple-tvos-sim": "tvos-arm64_x86_64-simulator",
"x86_64-apple-tvos": "tvos-arm64_x86_64-simulator",
"aarch64-apple-tvos": ["tvos-arm64"],
"aarch64-apple-tvos-sim": [
"tvos-arm64_x86_64-simulator", // Universal
"tvos-arm64-simulator",
],
"x86_64-apple-tvos": [
"tvos-arm64_x86_64-simulator", // Universal
"tvos-x86_64-simulator",
],

// "aarch64-apple-ios-macabi": "", // Catalyst
// "x86_64-apple-ios-macabi": "ios-x86_64-simulator",
Expand Down Expand Up @@ -145,11 +169,19 @@ export function getTargetAndroidPlatform(target: AndroidTargetName) {
}

export function getWeakNodeApiFrameworkPath(target: AppleTargetName) {
return joinPathAndAssertExistence(
const xcframeworkPath = joinPathAndAssertExistence(
weakNodeApiPath,
"weak-node-api.xcframework",
APPLE_XCFRAMEWORK_CHILDS_PER_TARGET[target],
);
const result = APPLE_XCFRAMEWORK_SLICES_PER_TARGET[target].find((slice) => {
const candidatePath = path.join(xcframeworkPath, slice);
return fs.existsSync(candidatePath);
});
assert(
result,
`No matching slice found in weak-node-api.xcframework for target ${target}`,
);
return joinPathAndAssertExistence(xcframeworkPath, result);
}

export function getWeakNodeApiAndroidLibraryPath(target: AndroidTargetName) {
Expand Down
21 changes: 21 additions & 0 deletions packages/host/apple/NodeApiHostModuleProvider.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#import "CxxNodeApiHostModule.hpp"
#import "WeakNodeApiInjector.hpp"

#import <ReactCommon/CxxTurboModuleUtils.h>
@interface NodeApiHost : NSObject

@end

@implementation NodeApiHost
+ (void)load {
callstack::nodeapihost::injectIntoWeakNodeApi();

facebook::react::registerCxxModuleToGlobalModuleMap(
callstack::nodeapihost::CxxNodeApiHostModule::kModuleName,
[](std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<callstack::nodeapihost::CxxNodeApiHostModule>(
jsInvoker);
});
}

@end
44 changes: 0 additions & 44 deletions packages/host/ios/NodeApiHostModuleProvider.mm

This file was deleted.

3 changes: 1 addition & 2 deletions packages/host/react-native-node-api.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ Pod::Spec.new do |s|
s.license = package["license"]
s.authors = package["author"]

s.platforms = { :ios => min_ios_version_supported }
s.source = { :git => "https://github.com/callstackincubator/react-native-node-api.git", :tag => "#{s.version}" }

s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{hpp,cpp,c,h}", "weak-node-api/include/*.h", "weak-node-api/*.hpp"
s.source_files = "apple/**/*.{h,m,mm}", "cpp/**/*.{hpp,cpp,c,h}", "weak-node-api/include/*.h", "weak-node-api/*.hpp"
s.public_header_files = "weak-node-api/include/*.h"

s.vendored_frameworks = "auto-linked/apple/*.xcframework", "weak-node-api/weak-node-api.xcframework"
Expand Down
12 changes: 11 additions & 1 deletion packages/host/scripts/patch-hermes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@
raise "React Native Node-API cannot reliably patch JSI when React Native Core is prebuilt."
end

def get_react_native_package
if caller.any? { |frame| frame.include?("node_modules/react-native-macos/") }
return "react-native-macos"
elsif caller.any? { |frame| frame.include?("node_modules/react-native/") }
return "react-native"
else
raise "Unable to determine React Native package from call stack."
end
end

if ENV['REACT_NATIVE_OVERRIDE_HERMES_DIR'].nil?
VENDORED_HERMES_DIR ||= `npx react-native-node-api vendor-hermes --silent '#{Pod::Config.instance.installation_root}'`.strip
VENDORED_HERMES_DIR ||= `npx react-native-node-api vendor-hermes --react-native-package '#{get_react_native_package()}' --silent '#{Pod::Config.instance.installation_root}'`.strip
# Signal the patched Hermes to React Native
ENV['BUILD_FROM_SOURCE'] = 'true'
ENV['REACT_NATIVE_OVERRIDE_HERMES_DIR'] = VENDORED_HERMES_DIR
Expand Down
Loading
Loading