Skip to content

Commit d55ade0

Browse files
authored
[js/rn] Migrate to JSI implementation (#25764)
### Description <!-- Describe your changes. --> close #16031 ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> Make React Native fully zero copy.
1 parent e824331 commit d55ade0

File tree

89 files changed

+2859
-3898
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+2859
-3898
lines changed

.github/workflows/react_native.yml

Lines changed: 23 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,11 @@ jobs:
5353
cp tools/ci_build/github/js/react_native_e2e_full_aar_build_settings.json ${{ runner.temp }}/.build_settings/build_settings.json
5454
5555
python3 -m pip install --user -r ${{ github.workspace }}/tools/ci_build/requirements/pybind/requirements.txt
56-
57-
python3 ${{ github.workspace }}/tools/ci_build/github/android/build_aar_package.py --build_dir ${{ runner.temp }} --config Release --android_sdk_path $ANDROID_SDK_ROOT --android_ndk_path $ANDROID_NDK_ROOT ${{ runner.temp }}/.build_settings/build_settings.json
56+
57+
python3 ${{ github.workspace }}/tools/ci_build/github/android/build_aar_package.py --build_dir ${{ runner.temp }} --config Release --android_sdk_path $ANDROID_SDK_ROOT --android_ndk_path $ANDROID_NDK_ROOT ${{ runner.temp }}/.build_settings/build_settings.json
5858
5959
# Copy the built artifacts to give folder for publishing
60-
BASE_PATH=${{ runner.temp }}/aar_out/Release/com/microsoft/onnxruntime/onnxruntime-android/${OnnxRuntimeVersion}
61-
cp ${BASE_PATH}/*.jar ${{ runner.temp }}/artifacts
62-
cp ${BASE_PATH}/*.aar ${{ runner.temp }}/artifacts
63-
cp ${BASE_PATH}/*.pom ${{ runner.temp }}/artifacts
60+
cp -r ${{ runner.temp }}/aar_out/Release/com ${{ runner.temp }}/artifacts
6461
6562
- name: Upload Android AAR Artifact
6663
uses: actions/upload-artifact@v5
@@ -109,10 +106,8 @@ jobs:
109106

110107
- name: Copy AAR to React Native and E2E directories
111108
run: |
112-
mkdir -p ${{ github.workspace }}/js/react_native/android/libs
113-
cp ${{ runner.temp }}/android-full-aar/*.aar ${{ github.workspace }}/js/react_native/android/libs
114109
mkdir -p ${{ github.workspace }}/js/react_native/e2e/android/app/libs
115-
cp ${{ runner.temp }}/android-full-aar/*.aar ${{ github.workspace }}/js/react_native/e2e/android/app/libs
110+
cp -r ${{ runner.temp }}/android-full-aar/com ${{ github.workspace }}/js/react_native/e2e/android/app/libs
116111
117112
- name: Install dependencies and bootstrap
118113
run: |
@@ -141,10 +136,6 @@ jobs:
141136
with:
142137
ndk-version: 28.0.13004108
143138

144-
- name: Run React Native Android Instrumented Tests
145-
run: ./gradlew connectedDebugAndroidTest --stacktrace
146-
working-directory: ${{ github.workspace }}/js/react_native/android
147-
148139
- name: Run React Native Detox Android e2e Tests
149140
run: |
150141
JEST_JUNIT_OUTPUT_FILE=${{ github.workspace }}/js/react_native/e2e/android-test-results.xml \
@@ -169,6 +160,15 @@ jobs:
169160
echo "Emulator PID file was expected to exist but does not."
170161
fi
171162
163+
- name: Upload Android Test Results
164+
if: always()
165+
uses: actions/upload-artifact@v5
166+
with:
167+
name: android-test-results
168+
path: |
169+
${{ github.workspace }}/js/react_native/e2e/android-test-results.xml
170+
${{ github.workspace }}/js/react_native/e2e/artifacts
171+
172172
react_native_ci_ios_build:
173173
name: React Native CI iOS Build
174174
runs-on: macos-14
@@ -211,62 +211,6 @@ jobs:
211211
name: ios_pod
212212
path: ${{ runner.temp }}/ios_pod
213213

214-
react_native_ci_ios_unit_tests:
215-
name: React Native CI iOS Unit Tests
216-
needs: react_native_ci_ios_build
217-
runs-on: macos-14
218-
timeout-minutes: 90
219-
steps:
220-
- name: Checkout repository
221-
uses: actions/checkout@v5
222-
223-
- name: Download iOS pod artifact
224-
uses: actions/download-artifact@v6
225-
with:
226-
name: ios_pod
227-
path: ${{ runner.temp }}/ios_pod
228-
229-
- name: Use Xcode 15.3.0
230-
run: sudo xcode-select --switch /Applications/Xcode_15.3.0.app/Contents/Developer
231-
232-
- name: Use Node.js 22.x
233-
uses: actions/setup-node@v6
234-
with:
235-
node-version: '22.x'
236-
237-
- uses: microsoft/onnxruntime-github-actions/[email protected]
238-
with:
239-
vcpkg-version: '2025.06.13'
240-
vcpkg-hash: 735923258c5187966698f98ce0f1393b8adc6f84d44fd8829dda7db52828639331764ecf41f50c8e881e497b569f463dbd02dcb027ee9d9ede0711102de256cc
241-
cmake-version: '3.31.8'
242-
cmake-hash: 99cc9c63ae49f21253efb5921de2ba84ce136018abf08632c92c060ba91d552e0f6acc214e9ba8123dee0cf6d1cf089ca389e321879fd9d719a60d975bcffcc8
243-
add-cmake-to-path: 'true'
244-
disable-terrapin: 'true'
245-
246-
- name: Install dependencies and bootstrap
247-
run: |
248-
npm ci
249-
working-directory: ${{ github.workspace }}/js
250-
- run: npm ci
251-
working-directory: ${{ github.workspace }}/js/common
252-
- run: |
253-
set -e -x
254-
npm ci
255-
npm run bootstrap-no-pods
256-
working-directory: ${{ github.workspace }}/js/react_native
257-
258-
- name: Pod install
259-
run: |
260-
set -e -x
261-
ls ${{ runner.temp }}/ios_pod/onnxruntime-c
262-
ORT_C_LOCAL_POD_PATH=${{ runner.temp }}/ios_pod/onnxruntime-c pod install --verbose
263-
working-directory: ${{ github.workspace }}/js/react_native/ios
264-
265-
- name: Run React Native iOS Instrumented Tests
266-
run: |
267-
/usr/bin/xcodebuild -sdk iphonesimulator -configuration Debug -workspace ${{ github.workspace }}/js/react_native/ios/OnnxruntimeModule.xcworkspace -scheme OnnxruntimeModuleTest -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.4' test CODE_SIGNING_ALLOWED=NO
268-
working-directory: ${{ github.workspace }}/js/react_native/ios
269-
270214
react_native_ci_ios_e2e_tests:
271215
name: React Native CI iOS E2E Tests
272216
needs: react_native_ci_ios_build
@@ -314,7 +258,7 @@ jobs:
314258
npm ci
315259
npm run bootstrap-no-pods
316260
working-directory: ${{ github.workspace }}/js/react_native
317-
261+
318262
- name: Pod install for e2e tests
319263
run: |
320264
set -e -x
@@ -331,3 +275,12 @@ jobs:
331275
--loglevel verbose \
332276
--take-screenshots failing
333277
working-directory: ${{ github.workspace }}/js/react_native/e2e
278+
279+
- name: Upload iOS Test Results
280+
if: always()
281+
uses: actions/upload-artifact@v5
282+
with:
283+
name: ios-test-results
284+
path: |
285+
${{ github.workspace }}/js/react_native/e2e/ios-test-results.xml
286+
${{ github.workspace }}/js/react_native/e2e/artifacts
Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,99 @@
1-
project(OnnxruntimeJSIHelper)
1+
project(OnnxruntimeJSI)
22
cmake_minimum_required(VERSION 3.9.0)
33

4-
set (PACKAGE_NAME "onnxruntime-react-native")
5-
set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
4+
set(PACKAGE_NAME "onnxruntime-react-native")
5+
set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
66
set(CMAKE_VERBOSE_MAKEFILE ON)
77
set(CMAKE_CXX_STANDARD 17)
88

9-
file(TO_CMAKE_PATH "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi/jsi/jsi.cpp" libPath)
9+
option(ORT_EXTENSIONS_ENABLED "Enable Ort Extensions" NO)
10+
option(USE_NNAPI "Use NNAPI" YES)
11+
option(USE_QNN "Use QNN" NO)
12+
13+
file(GLOB libfbjni_link_DIRS "${BUILD_DIR}/fbjni-*.aar/jni/${ANDROID_ABI}")
14+
file(GLOB libfbjni_include_DIRS "${BUILD_DIR}/fbjni-*-headers.jar/")
15+
16+
file(GLOB onnxruntime_include_DIRS
17+
"${BUILD_DIR}/onnxruntime-android-*.aar/headers")
18+
file(GLOB onnxruntime_link_DIRS
19+
"${BUILD_DIR}/onnxruntime-android-*.aar/jni/${ANDROID_ABI}/")
20+
21+
if(ORT_EXTENSIONS_ENABLED)
22+
add_definitions(-DORT_ENABLE_EXTENSIONS)
23+
endif()
24+
25+
if(USE_QNN)
26+
add_definitions(-DUSE_QNN)
27+
endif()
28+
29+
if(USE_NNAPI)
30+
add_definitions(-DUSE_NNAPI)
31+
endif()
32+
33+
file(TO_CMAKE_PATH
34+
"${NODE_MODULES_DIR}/react-native/ReactCommon/jsi/jsi/jsi.cpp" libPath)
35+
36+
find_package(fbjni REQUIRED CONFIG)
37+
find_package(ReactAndroid REQUIRED CONFIG)
38+
39+
find_library(
40+
onnxruntime-lib onnxruntime
41+
PATHS ${onnxruntime_link_DIRS}
42+
NO_CMAKE_FIND_ROOT_PATH)
43+
44+
set(RN_INCLUDES
45+
"${NODE_MODULES_DIR}/react-native/React"
46+
"${NODE_MODULES_DIR}/react-native/React/Base"
47+
"${NODE_MODULES_DIR}/react-native/ReactCommon"
48+
"${NODE_MODULES_DIR}/react-native/ReactCommon/jsi"
49+
"${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker")
50+
51+
if(${REACT_NATIVE_VERSION} VERSION_GREATER_EQUAL "0.76")
52+
set(RN_LIBS
53+
ReactAndroid::reactnative
54+
ReactAndroid::jsi)
55+
else()
56+
list(
57+
APPEND
58+
RN_INCLUDES
59+
"${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni"
60+
)
61+
set(RN_LIBS
62+
ReactAndroid::jsi
63+
ReactAndroid::react_nativemodule_core
64+
ReactAndroid::turbomodulejsijni)
65+
endif()
1066

1167
include_directories(
12-
"${NODE_MODULES_DIR}/react-native/React"
13-
"${NODE_MODULES_DIR}/react-native/React/Base"
14-
"${NODE_MODULES_DIR}/react-native/ReactCommon/jsi"
15-
)
68+
../cpp
69+
${RN_INCLUDES}
70+
${onnxruntime_include_DIRS}
71+
${libfbjni_include_DIRS})
1672

17-
add_library(onnxruntimejsihelper
18-
SHARED
19-
${libPath}
20-
src/main/cpp/cpp-adapter.cpp
21-
)
73+
add_library(
74+
onnxruntimejsi SHARED
75+
${libPath}
76+
src/main/cpp/cpp-adapter.cpp
77+
../cpp/JsiMain.cpp
78+
../cpp/InferenceSessionHostObject.cpp
79+
../cpp/JsiUtils.cpp
80+
../cpp/SessionUtils.cpp
81+
../cpp/TensorUtils.cpp)
2282

2383
# Configure C++ 17
2484
set_target_properties(
25-
onnxruntimejsihelper PROPERTIES
26-
CXX_STANDARD 17
27-
CXX_EXTENSIONS OFF
28-
POSITION_INDEPENDENT_CODE ON
29-
)
85+
onnxruntimejsi
86+
PROPERTIES CXX_STANDARD 17
87+
CXX_EXTENSIONS OFF
88+
POSITION_INDEPENDENT_CODE ON)
3089

3190
find_library(log-lib log)
3291

3392
target_link_libraries(
34-
onnxruntimejsihelper
35-
${log-lib} # <-- Logcat logger
36-
android # <-- Android JNI core
93+
onnxruntimejsi
94+
${onnxruntime-lib}
95+
fbjni::fbjni
96+
${RN_LIBS}
97+
${log-lib} # <-- Logcat logger
98+
android # <-- Android JNI core
3799
)

js/react_native/android/build.gradle

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,22 @@ static def findNodeModules(baseDir) {
4848

4949
def nodeModules = findNodeModules(projectDir);
5050

51-
def checkIfOrtExtensionsEnabled() {
51+
def readPackageJsonField(field) {
5252
// locate user's project dir
5353
def reactnativeRootDir = project.rootDir.parentFile
5454
// get package.json file in root directory
5555
def packageJsonFile = new File(reactnativeRootDir, 'package.json')
56-
// read field 'onnxruntimeExtensionsEnabled'
5756
if (packageJsonFile.exists()) {
5857
def packageJsonContents = packageJsonFile.getText()
5958
def packageJson = new groovy.json.JsonSlurper().parseText(packageJsonContents)
60-
return packageJson.onnxruntimeExtensionsEnabled == "true"
59+
return packageJson.get(field)
6160
} else {
62-
logger.warn("Could not find package.json file in the expected directory: ${reactnativeRootDir}. ONNX Runtime Extensions will not be enabled.")
61+
logger.warn("Could not find package.json file in the expected directory: ${reactnativeRootDir}. ${field} will not be enabled.")
6362
}
64-
return false
6563
}
6664

67-
boolean ortExtensionsEnabled = checkIfOrtExtensionsEnabled()
65+
boolean ortExtensionsEnabled = readPackageJsonField('onnxruntimeExtensionsEnabled') == "true"
66+
boolean useQnn = readPackageJsonField('onnxruntimeUseQnn') == "true"
6867

6968
def REACT_NATIVE_VERSION = ['node', '--print', "JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim()
7069
def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.split("\\.")[1].toInteger()
@@ -85,9 +84,18 @@ android {
8584
cppFlags "-O2 -frtti -fexceptions -Wall -Wno-unused-variable -fstack-protector-all"
8685
if (REACT_NATIVE_MINOR_VERSION >= 71) {
8786
// fabricjni required c++_shared
88-
arguments "-DANDROID_STL=c++_shared", "-DNODE_MODULES_DIR=${nodeModules}", "-DORT_EXTENSIONS_ENABLED=${ortExtensionsEnabled}"
87+
arguments "-DANDROID_STL=c++_shared",
88+
"-DNODE_MODULES_DIR=${nodeModules}",
89+
"-DORT_EXTENSIONS_ENABLED=${ortExtensionsEnabled}",
90+
"-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}",
91+
"-DUSE_QNN=${useQnn}",
92+
"-DUSE_NNAPI=${!useQnn}"
8993
} else {
90-
arguments "-DNODE_MODULES_DIR=${nodeModules}", "-DORT_EXTENSIONS_ENABLED=${ortExtensionsEnabled}"
94+
arguments "-DNODE_MODULES_DIR=${nodeModules}",
95+
"-DORT_EXTENSIONS_ENABLED=${ortExtensionsEnabled}",
96+
"-DREACT_NATIVE_VERSION=${REACT_NATIVE_VERSION}",
97+
"-DUSE_QNN=${useQnn}",
98+
"-DUSE_NNAPI=${!useQnn}"
9199
}
92100
abiFilters (*reactNativeArchitectures())
93101
}
@@ -119,6 +127,9 @@ android {
119127
"META-INF",
120128
"META-INF/**",
121129
"**/libjsi.so",
130+
"**/libfbjni.so",
131+
"**/libreact_nativemodule_core.so",
132+
"**/libturbomodulejsijni.so"
122133
]
123134
}
124135

@@ -147,6 +158,10 @@ android {
147158
}
148159
}
149160
}
161+
162+
configurations {
163+
extractLibs
164+
}
150165
}
151166

152167
repositories {
@@ -217,27 +232,54 @@ repositories {
217232
"Ensure you have you installed React Native as a dependency in your project and try again."
218233
)
219234
}
220-
221-
flatDir {
222-
dir 'libs'
223-
}
224235
}
225236

226237
dependencies {
227238
//noinspection GradleDynamicVersion
228239
implementation "com.facebook.react:react-android:"+ REACT_NATIVE_VERSION
229240
api "org.mockito:mockito-core:2.28.2"
230241

231-
androidTestImplementation "androidx.test:runner:1.5.2"
232-
androidTestImplementation "androidx.test:rules:1.5.0"
233242
implementation "junit:junit:4.12"
234243

235-
androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito-inline-extended:2.28.1"
244+
if (useQnn) {
245+
extractLibs "com.microsoft.onnxruntime:onnxruntime-android-qnn:latest.integration@aar"
246+
} else {
247+
extractLibs "com.microsoft.onnxruntime:onnxruntime-android:latest.integration@aar"
248+
}
236249

237-
implementation "com.microsoft.onnxruntime:onnxruntime-android:latest.integration@aar"
250+
if (VersionNumber.parse(REACT_NATIVE_VERSION) < VersionNumber.parse("0.71")) {
251+
extractLibs "com.facebook.fbjni:fbjni:+:headers"
252+
extractLibs "com.facebook.fbjni:fbjni:+"
253+
}
238254

239255
// By default it will just include onnxruntime full aar package
240256
if (ortExtensionsEnabled) {
241257
implementation "com.microsoft.onnxruntime:onnxruntime-extensions-android:latest.integration@aar"
242258
}
243-
}
259+
}
260+
261+
task extractLibs {
262+
doLast {
263+
configurations.extractLibs.files.each {
264+
def file = it.absoluteFile
265+
copy {
266+
from zipTree(file)
267+
into "$buildDir/$file.name"
268+
include "**/*.h", "**/*.so"
269+
}
270+
}
271+
}
272+
}
273+
274+
def nativeBuildDependsOn(dependsOnTask, variant) {
275+
def buildTasks = tasks.findAll({ task ->
276+
!task.name.contains("Clean") && (task.name.contains("externalNative") || task.name.contains("CMake")) })
277+
if (variant != null) {
278+
buildTasks = buildTasks.findAll({ task -> task.name.contains(variant) })
279+
}
280+
buildTasks.forEach { task -> task.dependsOn(dependsOnTask) }
281+
}
282+
283+
afterEvaluate {
284+
nativeBuildDependsOn(extractLibs, null)
285+
}

0 commit comments

Comments
 (0)