You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
React Native's native library loading mechanism is incompatible with third-party SDKs that use wrapped C++ symbols (with __wrap__ prefix). This blocks integration of Meta Horizon Platform SDK and potentially other SDKs with similar symbol requirements.
The Core Issue
React Native loads libc++_shared.so with standard symbols during static initialization (via ReactNativeJNISoLoader.staticInit()), preventing later-loaded native libraries from finding wrapped symbols they depend on.
Result: One shared libc++_shared.so for all native modules, loaded before third-party code runs, symbol table fixed at load time, no mechanism to provide alternative symbols.
Attempted Solutions (All Failed)
1. Static STL Linking ❌
Tried patching React Native to use ANDROID_STL=c++_static
Result: APK still contains libc++_shared.so because third-party modules (reanimated, screens, gesture-handler, etc.) are prebuilt AARs with c++_shared
2. pickFirst Packaging ❌
Used pickFirst '**/libc++_shared.so'
Result: Build succeeds but runtime crash persists (only selects which file to package, doesn't solve symbol mismatch)
3. Build Flavor Separation ❌
Separated Play and Horizon builds using source sets
Result: Successfully separates code/dependencies at build time, but React Native still loads standard libc++ first at runtime
Questions for React Native Team
Is there a way to support custom symbol resolution for specific native libraries?
Can library loading order be controlled for special cases?
Is this a known limitation that should be documented?
Should SDK vendors be contacted to avoid wrapped symbols for RN compatibility?
Steps to reproduce
1. Create React Native Project
# Using Expo
npx create-expo-app@latest HorizonTest
cd HorizonTest
# Or bare React Native
npx react-native init HorizonTest
cd HorizonTest
importcom.meta.horizon.billingclient.api.HorizonBillingClientimportcom.meta.horizon.billingclient.api.BillingClientStateListenerimportcom.meta.horizon.billingclient.api.BillingResultval billingClient =HorizonBillingClient.newBuilder(context)
.setListener { billingResult, purchases ->// Handle purchases
}
.build()
// This call will trigger the crash
billingClient.startConnection(object:BillingClientStateListener {
overridefunonBillingSetupFinished(billingResult:BillingResult) {
// Won't reach here
}
overridefunonBillingServiceDisconnected() {
// Won't reach here
}
})
5. Build and Run on Meta Quest Device
# Build APKcd android && ./gradlew assembleDebug
# Install on Quest
adb install app/build/outputs/apk/debug/app-debug.apk
# Run app
adb shell am start -n com.your.package/.MainActivity
6. Observe Crash
App will crash immediately when startConnection() is called.
React Native Version
0.81.4
Affected Platforms
Runtime - Android
Output of npx @react-native-community/cli info
System:
OS: macOS 15.6.1
CPU: (10) arm64 Apple M4
Memory: 167.38 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 20.19.0
path: /opt/homebrew/bin/node
Yarn:
version: 3.6.1
path: /opt/homebrew/bin/yarn
npm:
version: 10.8.2
path: /opt/homebrew/bin/npm
Watchman:
version: 2025.03.10.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.0
- iOS 26.0
- macOS 26.0
- tvOS 26.0
- visionOS 26.0
- watchOS 26.0
Android SDK: Not Found
IDEs:
Android Studio: 2024.2 AI-242.23339.11.2421.12483815
Xcode:
version: 26.0.1/17A400
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.12
path: /usr/bin/javac
Ruby:
version: 2.7.2
path: /Users/crossplatformkorea/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 19.1.0
wanted: 19.1.0
react-native:
installed: 0.81.4
wanted: 0.81.4
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
Stacktrace or Logs
[useIAP] initConnection failed: [Error: Call to function 'ExpoIap.initConnection' has been rejected.
→ Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__wrap__ZTVSt12length_error" referenced by "/data/app/~~H2QqsKUEITvWPnjTyKH8MA==/dev.hyo.martie-jmdTuEYhK2gA-IVo9mG0Pw==/base.apk!/lib/arm64-v8a/libpsdk_jni.so"...]
FATAL EXCEPTION: main
Process: dev.hyo.martie, PID: 398
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__wrap__ZTVSt12length_error" referenced by "/data/app/~~XXX/dev.hyo.martie-YYY/base.apk!/lib/arm64-v8a/libpsdk_jni.so"...
at java.lang.Runtime.loadLibrary0(Runtime.java:1071)
at java.lang.Runtime.loadLibrary0(Runtime.java:1000)
at java.lang.System.loadLibrary(System.java:1893)
at com.meta.horizon.platform.PlatformSDK.<clinit>(PlatformSDK.java)
at com.meta.horizon.billingclient.api.HorizonBillingClient.startConnection(HorizonBillingClient.java)
Description
React Native's native library loading mechanism is incompatible with third-party SDKs that use wrapped C++ symbols (with
__wrap__prefix). This blocks integration of Meta Horizon Platform SDK and potentially other SDKs with similar symbol requirements.The Core Issue
React Native loads
libc++_shared.sowith standard symbols during static initialization (viaReactNativeJNISoLoader.staticInit()), preventing later-loaded native libraries from finding wrapped symbols they depend on.Environment
com.meta.horizon.platform.ovr:android-platform-sdk:72)Platform Comparison
Root Cause Analysis
Symbol Mismatch:
libc++_shared.socontains standard symbols:_ZTVSt12length_error__wrap__ZTVSt12length_errorReact Native's Loading Sequence:
Static Initialization -
CatalystInstanceImpl.java:54:SoLoader Call -
ReactNativeJNISoLoader.kt#L19-L27:Hard-coded STL Configuration:
ReactAndroid/build.gradle.kts:567:"-DANDROID_STL=c++_shared"ReactAndroid/hermes-engine/build.gradle.kts:276:"-DANDROID_STL=c++_shared"Result: One shared
libc++_shared.sofor all native modules, loaded before third-party code runs, symbol table fixed at load time, no mechanism to provide alternative symbols.Attempted Solutions (All Failed)
1. Static STL Linking ❌
ANDROID_STL=c++_staticlibc++_shared.sobecause third-party modules (reanimated, screens, gesture-handler, etc.) are prebuilt AARs withc++_shared2. pickFirst Packaging ❌
pickFirst '**/libc++_shared.so'3. Build Flavor Separation ❌
Questions for React Native Team
Steps to reproduce
1. Create React Native Project
2. Add Horizon Platform SDK Dependency
android/build.gradle:
android/app/build.gradle:
3. Add Oculus App ID to AndroidManifest.xml
4. Initialize and Connect to HorizonBillingClient
Kotlin/Java code:
5. Build and Run on Meta Quest Device
6. Observe Crash
App will crash immediately when
startConnection()is called.React Native Version
0.81.4
Affected Platforms
Runtime - Android
Output of
npx @react-native-community/cli infoStacktrace or Logs
MANDATORY Reproducer
hyochan/expo-iap#105
Screenshots and Videos
Expo App (Failed 😞)
expo.mp4
Android App (Success ✅)
android.mp4
Flutter App (Success ✅)
flutter.mp4