Skip to content

Instantly share code, notes, and snippets.

@ps73
Last active March 12, 2026 15:09
Show Gist options
  • Select an option

  • Save ps73/570b7e7ecf52a13bd997ee5cda5e993b to your computer and use it in GitHub Desktop.

Select an option

Save ps73/570b7e7ecf52a13bd997ee5cda5e993b to your computer and use it in GitHub Desktop.
Ort / onnxruntime-react-native 1.24.3 bugs on Android

onnxruntime-react-native Android Fix

During development of Zyke App for the Zyke Band we ran in these issues with onnxruntime-react-native.

Problem

onnxruntime-react-native 1.24.3 failed on Android (in our case with Expo 55) with two issues:

  1. Gradle 9 build failureVersionNumber class was removed in Gradle 9, breaking build.gradle line 250 (Expo 55 uses React-Native 0.83.x, so this check is not required)
  2. Runtime crashNativeModules.Onnxruntime was null, causing Cannot read property 'install' of null at startup

Root Causes

Build failure

The library's build.gradle uses VersionNumber.parse() (from org.gradle.util.VersionNumber) which was deprecated in Gradle 7.1 and removed in Gradle 9. The check was only relevant for React Native < 0.71 — dead code for modern RN versions.

Runtime crash (autolinking)

onnxruntime-react-native uses the legacy ReactPackage pattern (OnnxruntimePackage.java) which Expo's autolinking does not pick up. The Gradle dependency was linked, but the Java package was never registered in PackageList — so NativeModules.Onnxruntime was null at runtime.

Reference: microsoft/onnxruntime#19510

Fixes Applied

1. Patch: build.gradle (via patch-package)

Removed the dead VersionNumber block:

-  if (VersionNumber.parse(REACT_NATIVE_VERSION) < VersionNumber.parse("0.71")) {
-    extractLibs "com.facebook.fbjni:fbjni:+:headers"
-    extractLibs "com.facebook.fbjni:fbjni:+"
-  }

2. Patch: binding.ts (via patch-package)

Guarded Module.install() and added a silent stub fallback for background JS contexts where native modules are unavailable:

-if (typeof globalThis.OrtApi === 'undefined') {
+if (typeof globalThis.OrtApi === 'undefined' && Module != null) {
   Module.install();
 }

When Module is null, exports a no-op stub ({ listSupportedBackends: () => [] }) instead of a throwing Proxy.

3. Expo config plugin: plugins/with-onnxruntime.js

Created a custom Expo config plugin that injects OnnxruntimePackage into MainApplication.kt during prebuild — solving the autolinking gap:

import ai.onnxruntime.reactnative.OnnxruntimePackage
// ...
PackageList(this).packages.apply {
    add(OnnxruntimePackage())
}

4. app.config.ts

Replaced ['onnxruntime-react-native'] (library has no plugin) with ['./plugins/with-onnxruntime'].

Files Changed

File Change
patches/onnxruntime-react-native+1.24.3.patch Gradle 9 compat + background JS guard
plugins/with-onnxruntime.js New Expo config plugin for native module registration
app.config.ts Updated plugin reference
diff --git a/node_modules/onnxruntime-react-native/android/build.gradle b/node_modules/onnxruntime-react-native/android/build.gradle
index 41b4359..1b5e7e7 100644
--- a/node_modules/onnxruntime-react-native/android/build.gradle
+++ b/node_modules/onnxruntime-react-native/android/build.gradle
@@ -247,11 +247,6 @@ dependencies {
extractLibs "com.microsoft.onnxruntime:onnxruntime-android:latest.integration@aar"
}
- if (VersionNumber.parse(REACT_NATIVE_VERSION) < VersionNumber.parse("0.71")) {
- extractLibs "com.facebook.fbjni:fbjni:+:headers"
- extractLibs "com.facebook.fbjni:fbjni:+"
- }
-
// By default it will just include onnxruntime full aar package
if (ortExtensionsEnabled) {
implementation "com.microsoft.onnxruntime:onnxruntime-extensions-android:latest.integration@aar"
diff --git a/node_modules/onnxruntime-react-native/lib/binding.ts b/node_modules/onnxruntime-react-native/lib/binding.ts
index f5963a0..f846707 100644
--- a/node_modules/onnxruntime-react-native/lib/binding.ts
+++ b/node_modules/onnxruntime-react-native/lib/binding.ts
@@ -10,17 +10,21 @@ declare global {
var OrtApi: OrtApiType; // eslint-disable-line no-var
}
-if (typeof globalThis.OrtApi === 'undefined') {
+if (typeof globalThis.OrtApi === 'undefined' && Module != null) {
Module.install();
}
export const OrtApi =
globalThis.OrtApi ??
- new Proxy(
- {},
- {
- get: () => {
- throw new Error('OrtApi is not initialized. Please make sure Onnxruntime installation is successful.');
- },
- },
- );
+ (Module == null
+ ? // Native module unavailable (e.g. headless JS context) — return a
+ // silent stub so module-level code in backend.ts / index.ts doesn't throw.
+ ({ listSupportedBackends: () => [] } as unknown as OrtApiType)
+ : new Proxy(
+ {},
+ {
+ get: () => {
+ throw new Error('OrtApi is not initialized. Please make sure Onnxruntime installation is successful.');
+ },
+ },
+ ));
// Store this under plugins/with-onnxruntime.js!
const { withMainApplication, createRunOncePlugin } = require('expo/config-plugins');
const PACKAGE_IMPORT = 'import ai.onnxruntime.reactnative.OnnxruntimePackage';
/**
* Expo config plugin that manually registers OnnxruntimePackage in MainApplication.kt.
*
* onnxruntime-react-native uses the legacy ReactPackage pattern which isn't picked up
* by Expo's autolinking. Without this, NativeModules.Onnxruntime is null at runtime.
*/
function withOnnxruntime(config) {
return withMainApplication(config, (config) => {
let contents = config.modResults.contents;
// Add import if missing
if (!contents.includes(PACKAGE_IMPORT)) {
const lastImportIndex = contents.lastIndexOf('\nimport ');
if (lastImportIndex !== -1) {
const endOfLine = contents.indexOf('\n', lastImportIndex + 1);
contents = contents.slice(0, endOfLine + 1) + PACKAGE_IMPORT + '\n' + contents.slice(endOfLine + 1);
}
}
// Add package registration if missing
if (!contents.includes('OnnxruntimePackage()')) {
// Insert after the comment line inside packages.apply { }
const marker = '// add(MyReactNativePackage())';
const markerIdx = contents.indexOf(marker);
if (markerIdx !== -1) {
const endOfMarkerLine = contents.indexOf('\n', markerIdx);
contents =
contents.slice(0, endOfMarkerLine) +
'\n add(OnnxruntimePackage())' +
contents.slice(endOfMarkerLine);
}
}
config.modResults.contents = contents;
return config;
});
}
module.exports = createRunOncePlugin(withOnnxruntime, 'with-onnxruntime', '1.0.0');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment