Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 22 additions & 0 deletions packages/android-jsi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ void installBindings() {

Each V8 isolate (the main UI thread and any NativeScript Worker threads) lazily owns its own `std::shared_ptr<facebook::jsi::Runtime>` keyed by `v8::Isolate::GetCurrent()`, resolving V8 symbols exported by `libNativeScript.so`.

## Scheduling work on the JS thread

`tns::GetJSICallInvoker()` returns a `tns::JSICallInvoker` (the equivalent of React Native's `CallInvoker`) for the calling thread's runtime, backed by that thread's `ALooper`. Grab it on the JS thread, then call `invokeAsync` from any thread to run work back on it, for example to settle a promise from a background queue:

```cpp
#include "JSIRuntime.h"

auto invoker = tns::GetJSICallInvoker();
std::thread([invoker, resolve] {
double result = expensiveWork();
invoker->invokeAsync([resolve, result](facebook::jsi::Runtime& rt) {
resolve->call(rt, result);
});
}).detach();
```

Each task runs as a top-level JS entry followed by a microtask checkpoint, so `await`ing code continues immediately. Errors thrown by a task are reported through NativeScript's uncaught error handling.

## JSI version

The bundled `facebook::jsi` headers match React Native 0.88.0, which is what Nitro Modules v1 (`nitro-core`) and other current JSI libraries compile against. Install Nitro with `margelo::nitro::install(*runtime, dispatcher)`, where the dispatcher forwards `runAsync` to `JSICallInvoker::invokeAsync` and `isOnDispatcher` to `isOnJSThread`.

## JavaScript / TypeScript Usage

```ts
Expand Down
20 changes: 20 additions & 0 deletions packages/android-jsi/platforms/android/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@ add_library(
v8runtime/JSIV8ValueConverter.cpp
v8runtime/HostProxy.cpp
v8runtime/JSIRuntime.cpp
v8runtime/V8ExportShims.cpp
)

# Inline V8 header code reads object layouts, so these must match the V8 build
# inside libNativeScript.so (NativeScript/android test-app/runtime/CMakeLists.txt).
target_compile_definitions(nativescript-jsi PUBLIC V8_31BIT_SMIS_ON_64BIT_ARCH)
if(ANDROID_ABI MATCHES "arm64-v8a$" OR ANDROID_ABI MATCHES "x86_64$")
target_compile_definitions(nativescript-jsi PUBLIC V8_COMPRESS_POINTERS)
endif()

target_include_directories(
nativescript-jsi
PUBLIC
Expand All @@ -49,6 +57,7 @@ target_compile_options(
)

find_library(android-log-lib log)
find_library(android-lib android)

# V8 symbols are exported by libNativeScript.so which is already loaded in the
# Android process by the NativeScript runtime. Allow unresolved shared-library
Expand All @@ -62,9 +71,18 @@ if(DEFINED NATIVESCRIPT_SO_PATH AND EXISTS "${NATIVESCRIPT_SO_PATH}")
target_link_libraries(
nativescript-jsi
${android-log-lib}
${android-lib}
NativeScriptRuntime
)
else()
# Android's dynamic linker binds a library's undefined symbols only against
# its own DT_NEEDED tree, never against libraries the process loaded earlier.
# Linking against an empty stub whose soname is libNativeScript.so records
# that dependency, so the V8 symbols bind to the runtime already in memory.
add_library(nativescript-runtime-stub SHARED v8runtime/NativeScriptRuntimeStub.cpp)
set_target_properties(nativescript-runtime-stub PROPERTIES NO_SONAME ON)
target_link_options(nativescript-runtime-stub PRIVATE "-Wl,-soname,libNativeScript.so")

string(REGEX REPLACE "(^| )-Wl,--no-undefined( |$)" " " CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
target_link_options(
nativescript-jsi
Expand All @@ -75,5 +93,7 @@ else()
target_link_libraries(
nativescript-jsi
${android-log-lib}
${android-lib}
nativescript-runtime-stub
)
endif()
Loading
Loading