Skip to content

fix(android): create transport HybridObject on JS thread (fix ClassNotFound)#8

Merged
lopadova merged 2 commits into
mainfrom
fix/jni-classloader-transport-create
May 28, 2026
Merged

fix(android): create transport HybridObject on JS thread (fix ClassNotFound)#8
lopadova merged 2 commits into
mainfrom
fix/jni-classloader-transport-create

Conversation

@lopadova
Copy link
Copy Markdown
Contributor

Summary

Fixes java.lang.ClassNotFoundException: com.margelo.nitro.ecr17.HybridEcr17Transport thrown on every command when running the example app on a device.

Root cause: createHybridObject does a JNI FindClass, which resolves against the current thread's class loader. The previous JNI fix attaches Nitro worker threads via ThreadScope, but an attached worker thread gets the system class loader (visible in the error's DexPathList[... /system/lib64 ...]), which can't see app/library classes.

Fix: run ensureInit() (the createHybridObject) inside configure(), which executes on the JS thread where the app class loader is present. fbjni caches the resolved jclass globally, so later method calls from worker threads work (they only need a JNIEnv, supplied by the existing ThreadScope guards).

Verification

  • android-build dispatched (compiles the native change).
  • Runtime: re-install the new APK artifact and run connect + commands — should no longer throw ClassNotFound.

Test plan

  • android-build green
  • On device: connect + commands run without ClassNotFound / JNI errors

🤖 Generated with Claude Code

…oader)

Runtime ClassNotFoundException for com.margelo.nitro.ecr17.HybridEcr17Transport
on every command: createHybridObject's JNI FindClass resolves against the
current thread's class loader, and the Nitro worker thread (attached via
ThreadScope) has the SYSTEM class loader, which can't see app classes.

Fix: run ensureInit() (the createHybridObject) in configure(), which executes on
the JS thread where the app class loader is available. fbjni caches the resolved
jclass globally, so subsequent method calls from worker threads succeed (they
only need a JNIEnv, provided by the ThreadScope guards).

Found by running the example app on a device.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

- LESSON: fix now-stale notes (client include is HybridEcr17Client.hpp;
  createHybridObject downcast is dynamic_pointer_cast on the JS thread).
- AGENTS: add a consolidated "Nitro Android native integration (JNI)" rule
  group (impl-header naming, dynamic_pointer_cast, react-native.config.js,
  ThreadScope, createHybridObject on the JS thread) — all reproducible only by
  running the app.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lopadova lopadova merged commit ceaa3f7 into main May 28, 2026
2 checks passed
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.

2 participants