feat: add worklet bridge for Reanimated shared value support#250
Open
mfazekas wants to merge 114 commits into
Open
feat: add worklet bridge for Reanimated shared value support#250mfazekas wants to merge 114 commits into
mfazekas wants to merge 114 commits into
Conversation
Add new experimental iOS backend (ios/new/) with synchronous API, move legacy backend files to ios/legacy/, add getEnums() support, retry listener streams on missingData, and restore TestComponentOverlay. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering)
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering)
getEnums() in legacy now throws directing users to the experimental backend instead of creating throwaway Worker+File instances. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering)
…essing Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering)
… binding Each Worker has its own C++ command server with its own m_artboards handle map. Creating separate Workers per file meant artboard handles from one file were invalid on another file's server. Using a shared singleton Worker fixes cross-file artboard property set. Also wires fit/alignment through experimental Fit enum and improves asset type detection with audio/font magic bytes. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Happy <yesreply@happy.engineering>
Passing fit to the Rive() constructor breaks layout mode because the MTKView drawable isn't ready yet. Set rive.fit after setupRiveUIView() instead.
Port Flutter data binding tests for VM access, enums, creation variants, list properties, artboard and image properties. Includes new .riv test assets and react-native-harness upgrade to alpha.25.
…ceByIndex Prevents fatal crash when passing negative numbers to Swift APIs expecting unsigned integers.
CocoaPods doesn't embed SPM-resolved dynamic frameworks automatically. Patches the embed script to include RiveRuntime when USE_RIVE_SPM=1.
Move 19 backend-specific files to src/legacy/java/, add Gradle sourceSets switching via USE_RIVE_NEW_API property, prepare empty experimental dirs.
Uses the new handle-based Rive Android SDK (app.rive.*) with CommandQueue, path-based ViewModelInstance property access, and Kotlin Flows for reactivity. Throws UnsupportedOperationException for SMI inputs, text runs, and events. Also fixes Gradle property resolution to use rootProject.findProperty.
Custom TextureView renderer with Choreographer render loop, CommandQueue polling infrastructure, ViewModel resolution and property validation, and example Compose test activities for manual testing.
Also fix viewModelByIndex/ByName on Android legacy to catch SDK exceptions instead of letting them propagate as JniExceptions.
…fferences Fix colorProperty setter Double→Int overflow on Android legacy (toLong().toInt()). Make enum and replaceViewModel tests tolerant of Android SDK behavioral differences.
Use .viewModelDefault(from: .name(vmName)) for default instance creation instead of artboard-based lookup that only worked for the default artboard's VM. Skip instanceName, color get/set, and non-existent property checks on experimental iOS where the SDK doesn't support them.
…anceName Add async variants for viewModelByName, defaultArtboardViewModel, and ViewModel create methods. Pass instanceName through at creation time on both iOS and Android experimental backends as a workaround for the SDK not exposing ViewModelInstance.name.
…rimental iOS Color.argbValue is now public in rive-ios 6.15.2 — implement getValue via blockingAsync, addListener via valueStream, and fix setter crash by using UInt32(bitPattern:) for negative ARGB values from JS.
- Always use SPM for RiveRuntime (remove CocoaPods fallback) - Add RiveSPMEmbedFix module to auto-embed RiveRuntime.framework - Pin SPM to exactVersion instead of upToNextMajorVersion - Replace USE_RIVE_SPM with USE_RIVE_EXPERIMENTAL_RUNTIME to select legacy vs experimental backend independently of SPM
…erimental iOS test issues - Rename USE_RIVE_EXPERIMENTAL_RUNTIME to USE_RIVE_NEW_API (matches Android) - Remove USE_RIVE_SPM and all SPM embedding hacks from podspec/Podfile - Use standard CocoaPods dependency for RiveRuntime - Emit initial value in experimental addListener (number/string/bool/enum/color) - Guard tests that crash on experimental iOS (list ops, autoPlay, artboard/image loading) - Handle createInstanceByName throwing on experimental backend
…nings (#201) ## Summary - Adds `RiveLog` — a general-purpose logging system that surfaces native logs to JS via a configurable handler - Default handler uses `console.error/warn/log` so logs show in the RN console out of the box - On both platforms, hooks into the Rive SDK's pluggable `RiveLog.Logger` to unify C++ runtime logs (state machine, artboard, command queue diagnostics) through the JS handler - Adds `DeprecationWarning` utility that emits once-per-session warnings when deprecated blocking methods are called ## Test plan - [ ] Build exerciser on iOS + Android - [ ] Call a deprecated method (e.g. `riveFile.viewModelByName(...)`) — verify warning in RN console - [ ] Call same method again — verify no duplicate warning - [ ] `RiveLog.setHandler(() => {})` — verify all logs suppressed - [ ] `RiveLog.resetHandler()` — verify back to default console output - [ ] Verify `onError` prop on RiveView still works independently
… backend RiveUIView creates its MTKView lazily during the first layout pass. Setting rive.fit immediately after creating the view had no effect because the drawable didn't exist yet. Store the desired fit as pendingFit and apply it in layoutSubviews once the MTKView is present.
Add `RiveLog.setLogLevel(level)` to filter log output by severity.
Levels: `debug`, `info`, `warn`, `error`. Default is `warn`.
## Test plan
- `RiveLog.setLogLevel('error')` suppresses warn/info/debug logs
- `RiveLog.setLogLevel('debug')` shows all logs
Bump RiveRuntime from 6.19.0 to 6.19.1. Remove `@_spi(RiveExperimental)` imports — no longer needed with this version.
The experimental factory already has `var backend: String {
"experimental" }`. This adds the matching property to the legacy side so
`RiveFileFactory.backend` works for both backends.
`Int32(value)` traps when ARGB color values exceed `Int32.max` (e.g. `0xFF0000FF` = opaque blue). Uses `Int64` + `truncatingIfNeeded` for safe conversion.
- Pass `fit:` directly in `Rive()` constructor instead of setting it post-creation. Removes the `layoutSubviews`/`pendingFit` workaround since rive-ios 6.19.1 handles this (rive-ios#443) - Warn when `updateReferencedAssets` is called on experimental backend (not supported — concurrency API can't update already-bound artboard assets) - Switch asset registration from parallel `TaskGroup` to sequential to ensure command queue ordering - Add debug logging to `ExperimentalAssetLoader` - Add explicit `type` fields to OutOfBandAssets example - Add `expo-font` plugin for `kanit_regular.ttf` in expo examples ## Test plan - QuickStart + DataBindingArtboards render correctly with `Fit.Layout` on first mount - Out-of-Band Assets example loads initial assets correctly - `updateReferencedAssets` logs a warning instead of silently failing
Add addInstanceAsync, addInstanceAtAsync, removeInstanceAsync, removeInstanceAtAsync, swapAsync. Deprecate sync versions that return before knowing if the operation succeeded.
The library module already depends on the correct version via package.json runtimeVersions. The pin caused version conflicts.
… app Debug activities that import app.rive.* directly, causing the example app to need an explicit rive-android dependency. Easy to recreate when needed for native SDK debugging.
Removes the workaround that stripped the `RiveRuntime.Swift` submodule from modulemaps to avoid ODR conflicts. No longer needed since the upstream XCFramework switched from C++/ObjC++ interop to C/ObjC interop — the generated Swift header no longer emits `swift::` namespace types. Tested building with both Xcode 16.4 and Xcode 26.2 with the unstripped modulemap — no ODR errors. **Note:** This PR depends on a RiveRuntime XCFramework built with C/ObjC interop. If the build fails with ODR errors like `'swift::Optional::init' has different definitions in different modules`, the workaround still needs to be re-added (revert this PR). You can verify by checking `grep -c 'namespace swift' RiveRuntime-Swift.h` — it should be 0.
- Rename `ExperimentalViewConfiguration` → `ViewConfiguration`, `ExperimentalBindData` → `BindData`, `ExperimentalAssetLoader` → `AssetLoader` - Rename `toExperimentalFit` → `toRiveFit`, `toExperimentalAlignment` → `toRiveAlignment` - Remove `RCTLog` debug lines from `RiveReactNativeView` and `HybridRiveFileFactory` - Remove `RCTLogInfo` from `AssetLoader` — error/warn logs are sufficient - Update "Experimental API" comments to "concurrency API"
Navigating away from a Rive screen produced: ``` Draw failed: Artboard instance is null Failed to swap EGL buffers: EGL_BAD_SURFACE ``` The command queue processes commands in order: `close(artboard)` then `draw(artboard)`. The draw finds the artboard already closed. Fix: don't call `.close()` in `dispose()` — just null the handles and stop the render loop. The command queue drains naturally and resources are cleaned up by GC. ## Test plan - Open any Rive example → navigate back → no errors in logcat
…race (#244) - **OOB assets not showing**: `registerAssets` launched fire-and-forget coroutines — file was loaded before assets finished registering. Now `suspend` with `awaitAll()`. - **updateReferencedAssets**: logs warning (same as iOS — not supported in experimental backend). - **NestedViewModel example**: fixed layout so Rive view doesn't get squeezed to zero when log entries appear. ## Test plan - Out-of-Band Assets: image, font, audio all load on Android - NestedViewModel: Rive view stays visible after pressing Replace
Add coverage-ios package, configure RNRive + RiveRuntime pod instrumentation, and document the integration process.
Remove stale `isExperimentalIOS` test skips and fix Android ViewModel name resolution. - **Test skips removed:** Color property (`argbValue` now public in rive-ios 6.19.2), artboard/list/image databinding (crashes fixed in experimental renderer) - **Android fix:** Use `getDefaultViewModelInfo()` (available since rive-android 11.3.2) to resolve ViewModel name for `defaultArtboardViewModel()`, enabling `createInstanceByName` and other name-dependent operations All 105 harness tests pass on both iOS experimental and Android.
The rive-android API is no longer experimental in 11.4.1. Matches the iOS rename done in #240.
Font file needed by the font fallback example. Referenced in app.config.js via expo-font plugin.
Bump RiveRuntime from 6.19.2 to 6.20.0. Fixes Swift/ObjC interop issue in the released version.
Adds coverage-ios dependency and portal resolutions pointing to the local react-native-harness fork (feat/native-ios-coverage branch).
Adds getPropertiesAsync() to ViewModel and ViewModelInstance for runtime introspection. Returns ViewModelPropertyInfo[] with name and type for each property.
Port from #79. Adds RiveWorkletBridge HybridObject that installs Nitro's dispatcher on Reanimated's UI runtime, enabling ViewModel property listeners to drive SharedValues on the UI thread without blocking when JS is busy. Also bumps rive-ios to 6.20.2 and adds bouncing ball exerciser demo.
Suppress eslint no-deprecated warnings for runOnUI, defaultArtboardViewModel, and createDefaultInstance. These are properly fixed in the next stacked PR.
53f140a to
9613d1e
Compare
80b8072 to
f299fe1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Port of #79 to the experimental repo. Adds worklet bridge that installs Nitro's dispatcher on Reanimated's UI runtime, enabling ViewModel property listeners to drive SharedValues on the UI thread.
Stack: