Skip to content

Get uiRuntime directly from react-native-worklets#4276

Open
coado wants to merge 8 commits into
mainfrom
@coado/worklets-integration
Open

Get uiRuntime directly from react-native-worklets#4276
coado wants to merge 8 commits into
mainfrom
@coado/worklets-integration

Conversation

@coado

@coado coado commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Description

RNGH currently obtains the UI runtime through Reanimated’s private _WORKLET_RUNTIME global, which stores a raw jsi::Runtime pointer.

This PR makes the public react-native-worklets Stable API the preferred way to obtain the UI runtime while preserving the existing Reanimated fallback.

Runtime lookup

When compatible Worklets is available:

  1. JavaScript calls getUIRuntimeHolder().
  2. The holder is temporarily exposed to native code for the synchronous installation call.
  3. Android and Apple unwrap it through worklets/Compat/StableApi.h.
  4. RNGH installs _setGestureStateSync on the resulting UI runtime.
  5. The temporary holder is cleared afterward.

RNGH no longer includes or accesses platform-specific Worklets implementation APIs such as worklets/android/WorkletsModule.h or worklets/apple/WorkletsModule.h.

When Worklets is unavailable, too old, or holder retrieval fails, native code falls back to the existing _WORKLET_RUNTIME pointer provided by Reanimated.

The JavaScript initialization handles the providers independently:

  • Worklets available: use the Stable API holder.
  • Reanimated available without Worklets: call native installation and use _WORKLET_RUNTIME.
  • Neither available: skip UI runtime installation.

Optional dependency integration

react-native-worklets remains optional.

Native Worklets integration is enabled only for stable versions >= 0.8.0:

  • CocoaPods resolves the package from the installation root, verifies its version and podspec, adds RNWorklets (>= 0.8.0), and defines RNGH_USE_WORKLETS=1.
  • Android detects the Worklets Gradle project and version, links its prefab target, and defines the same compile-time macro.
  • StableApi.h is included directly when the macro is enabled, so missing or incorrectly exported headers fail compilation instead of silently selecting the fallback.

The shared runtime decorator was also split into:

  • Installing RNGH bindings on a runtime that has already been resolved.
  • Resolving the legacy _WORKLET_RUNTIME pointer when needed.

Test plan

Added Jest coverage and tested on Runtime Decoration example on iOS and Android.

@coado coado changed the title Get uiRuntime directly from react-native-worklets Get uiRuntime directly from react-native-worklets Jun 19, 2026
Comment thread packages/react-native-gesture-handler/android/src/main/jni/CMakeLists.txt Outdated
Comment thread packages/react-native-gesture-handler/android/build.gradle Outdated
Comment thread packages/react-native-gesture-handler/apple/RNGestureHandlerModule.mm Outdated
Comment thread packages/react-native-gesture-handler/src/handlers/gestures/reanimatedWrapper.ts Outdated
Comment thread packages/react-native-gesture-handler/shared/runtime/RNGHRuntimeDecorator.cpp Outdated
Comment thread packages/react-native-gesture-handler/shared/runtime/RNGHRuntimeDecorator.cpp Outdated
Comment thread packages/react-native-gesture-handler/shared/runtime/RNGHRuntimeDecorator.cpp Outdated
Copilot AI review requested due to automatic review settings July 14, 2026 12:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR changes how RNGH finds the UI jsi::Runtime for installing UI-thread bindings, preferring the stable react-native-worklets API when available and falling back to the legacy Reanimated _WORKLET_RUNTIME approach.

Changes:

  • Add a temporary JS global holder (__RNGH_UI_WORKLET_RUNTIME_HOLDER) to pass the Worklets UI runtime holder to native during installation.
  • Update iOS/Android native installation to resolve the UI runtime via Worklets stable API first, then fall back to _WORKLET_RUNTIME.
  • Add conditional platform build integration for RNWorklets (CocoaPods + Android Gradle/CMake) gated on Worklets version/API support.

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/react-native-gesture-handler/src/handlers/gestures/reanimatedWrapper.ts Attempts to provide a Worklets UI runtime holder to native during UI bindings install.
packages/react-native-gesture-handler/src/global.d.ts Declares the new temporary global holder type for TypeScript.
packages/react-native-gesture-handler/shared/runtime/RNGHRuntimeDecorator.h Changes UI bindings install signature and adds tryFindUIRuntime.
packages/react-native-gesture-handler/shared/runtime/RNGHRuntimeDecorator.cpp Splits “find UI runtime” from “install bindings” and preserves legacy lookup.
packages/react-native-gesture-handler/scripts/gesture_handler_utils.rb Adds Worklets package/version detection for CocoaPods.
packages/react-native-gesture-handler/RNGestureHandler.podspec Conditionally depends on RNWorklets (>= 0.8.0) when stable API is detected.
packages/react-native-gesture-handler/apple/RNGestureHandlerModule.mm Uses Worklets stable API (when header available) to locate UI runtime before fallback.
packages/react-native-gesture-handler/android/src/main/jni/RNGestureHandlerModule.h Renames native method to reflect installing UI runtime bindings.
packages/react-native-gesture-handler/android/src/main/jni/RNGestureHandlerModule.cpp Uses Worklets stable API under RNGH_USE_WORKLETS, otherwise falls back to legacy lookup.
packages/react-native-gesture-handler/android/src/main/jni/CMakeLists.txt Conditionally links react-native-worklets when enabled.
packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt Updates the JNI method name used for installing bindings.
packages/react-native-gesture-handler/android/build.gradle Adds version-gated enablement + dependency wiring for react-native-worklets.
apps/basic-example/ios/Podfile.lock Updates example lockfile to include RNWorklets in pods set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/react-native-gesture-handler/src/handlers/gestures/reanimatedWrapper.ts Outdated
Comment thread packages/react-native-gesture-handler/android/src/main/jni/CMakeLists.txt Outdated
@coado coado marked this pull request as ready for review July 14, 2026 15:09
Comment on lines +60 to +75
jsi::Runtime *uiRuntime = nullptr;

#ifdef RNGH_USE_WORKLETS
std::shared_ptr<worklets::WorkletRuntime> uiWorkletRuntime;
const auto runtimeHolder = rnRuntime_->global().getProperty(
*rnRuntime_, "__RNGH_UI_WORKLET_RUNTIME_HOLDER");

if (runtimeHolder.isObject()) {
uiWorkletRuntime = worklets::getWorkletRuntimeFromHolder(
*rnRuntime_, runtimeHolder.asObject(*rnRuntime_));

if (uiWorkletRuntime) {
uiRuntime = &worklets::getJSIRuntimeFromWorkletRuntime(uiWorkletRuntime);
}
}
#endif

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why isn't this a part of RNGHRuntimeDecorator::tryFindUIRuntime?

Comment on lines +117 to +127
std::shared_ptr<worklets::WorkletRuntime> uiWorkletRuntime;
const auto runtimeHolder = _rnRuntime->global().getProperty(*_rnRuntime, "__RNGH_UI_WORKLET_RUNTIME_HOLDER");

if (runtimeHolder.isObject()) {
uiWorkletRuntime = worklets::getWorkletRuntimeFromHolder(*_rnRuntime, runtimeHolder.asObject(*_rnRuntime));

if (uiWorkletRuntime != nullptr) {
uiRuntime = &worklets::getJSIRuntimeFromWorkletRuntime(uiWorkletRuntime);
}
}
#endif

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

And this

Comment on lines +117 to +122
def packageJson = new JsonSlurper().parseText(new File(worklets.projectDir, "../package.json").text)
def version = packageJson.version as String

if (version.contains('-')) {
return false
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this needed?

Other lib checks don't have this, maybe it would be possible to fold it into getExternalLibVersion if necessary?

Comment on lines +77 to +83
if (uiRuntime == nullptr) {
uiRuntime = RNGHRuntimeDecorator::tryFindUIRuntime(*rnRuntime_);
}

if (uiRuntime == nullptr) {
return false;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This might be the one example when nesting these if reads easier

bool RNGestureHandlerModule::installUIRuntimeBindings() {
jsi::Runtime *uiRuntime = nullptr;

#ifdef RNGH_USE_WORKLETS

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

#ifdef checks only if the value is defined, not if it's true - I guess there's no way that this will be defined, but not 1, right?

| undefined;

// Temporary holder used to pass the Worklets UI runtime to native code.
// eslint-disable-next-line no-var

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe we should disable var rule for whole file?

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.

4 participants