feat!: experimental Rive runtime backend (iOS + Android)#134
feat!: experimental Rive runtime backend (iOS + Android)#134
Conversation
95816cf to
4fe9e12
Compare
8485f9f to
9b4acd8
Compare
There was a problem hiding this comment.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
ktlint
🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:try-catch-finally-spacing reported by reviewdog 🐶
Expected a newline after '{'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after '{'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline before '}'
🚫 [ktlint] standard:try-catch-finally-spacing reported by reviewdog 🐶
Expected a newline before '}'
🚫 [ktlint] standard:try-catch-finally-spacing reported by reviewdog 🐶
Expected a newline after '{'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after '{'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline before '}'
🚫 [ktlint] standard:try-catch-finally-spacing reported by reviewdog 🐶
Expected a newline before '}'
🚫 [ktlint] standard:no-unused-imports reported by reviewdog 🐶
Unused import
🚫 [ktlint] standard:string-template reported by reviewdog 🐶
Redundant curly braces
🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline
🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }
🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
Expected a newline
🚫 [ktlint] standard:multiline-if-else reported by reviewdog 🐶
Missing { ... }
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:string-template reported by reviewdog 🐶
Redundant curly braces
🚫 [ktlint] standard:max-line-length reported by reviewdog 🐶
Exceeded max line length (140)
🚫 [ktlint] standard:string-template reported by reviewdog 🐶
Redundant curly braces
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Missing newline before ")"
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after '{'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after ';'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline before '}'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after '{'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after ';'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline before '}'
🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
A single line if-statement should be kept simple. The 'THEN' may not be wrapped in a block.
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after '{'
🚫 [ktlint] standard:string-template reported by reviewdog 🐶
Redundant curly braces
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after ';'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline before '}'
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:max-line-length reported by reviewdog 🐶
Exceeded max line length (140)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Missing newline before ")"
🚫 [ktlint] standard:function-naming reported by reviewdog 🐶
Function name should start with a lowercase letter (except factory methods) and use camel case
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:max-line-length reported by reviewdog 🐶
Exceeded max line length (140)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Missing newline before ")"
dd06b3a to
a5855c9
Compare
There was a problem hiding this comment.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
ktlint
🚫 [ktlint] standard:if-else-wrapping reported by reviewdog 🐶
A single line if-statement should be kept simple. The 'THEN' may not be wrapped in a block.
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after '{'
🚫 [ktlint] standard:string-template reported by reviewdog 🐶
Redundant curly braces
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline after ';'
🚫 [ktlint] standard:statement-wrapping reported by reviewdog 🐶
Missing newline before '}'
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:max-line-length reported by reviewdog 🐶
Exceeded max line length (140)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Missing newline before ")"
🚫 [ktlint] standard:function-naming reported by reviewdog 🐶
Function name should start with a lowercase letter (except factory methods) and use camel case
🚫 [ktlint] standard:chain-method-continuation reported by reviewdog 🐶
Expected newline before '.'
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Argument should be on a separate line (unless all arguments can fit a single line)
🚫 [ktlint] standard:max-line-length reported by reviewdog 🐶
Exceeded max line length (140)
🚫 [ktlint] standard:argument-list-wrapping reported by reviewdog 🐶
Missing newline before ")"
8134a07 to
ec12673
Compare
91e2fb6 to
cfb2ff6
Compare
cfb2ff6 to
44681b5
Compare
f1b851e to
aa2fdf0
Compare
35c6fea to
4f1ab3f
Compare
4e0c53a to
be6d334
Compare
164180e to
7116ac7
Compare
dcdde5e to
0a3d09c
Compare
…roid-auto-databind
…ndroid When auto-binding, cppDefaultVMCreateDefaultVMI returns handle 1L (null sentinel) if the artboard has no default ViewModel. Guard against passing this sentinel to bindViewModelInstance.
5c7cd87 to
e9ee276
Compare
…E, check WebP explicitly
…ReactNativeView
…allable methods Nitro calls hybrid methods on the JS thread, not the main thread. MainActor.assumeIsolated crashes at runtime when not on main.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 74 out of 153 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try { | ||
| vmi = source.createInstanceByName(instanceName); | ||
| } catch { | ||
| // experimental backend throws for non-existent names | ||
| } |
There was a problem hiding this comment.
The catch block around source.createInstanceByName() swallows all exceptions with no logging. This can hide unexpected backend errors (not just “instance not found”) and make debugging very difficult. Consider logging the caught error (like the RiveFile path above) or narrowing the catch to only the expected “not found” failure mode.
| /** | ||
| * Get all enums defined in this Rive file. | ||
| * Useful for debugging and building dynamic UIs. | ||
| * @experimental Uses the experimental Rive API on iOS | ||
| */ | ||
| getEnums(): Promise<RiveEnumDefinition[]>; |
There was a problem hiding this comment.
The getEnums() doc comment says it uses the experimental iOS API, but the method is also implemented on Android (including legacy) and is stubbed to throw on iOS legacy. Consider updating the doc to accurately describe backend/platform support (e.g., supported on experimental iOS + Android; throws on iOS legacy).
| // Null when constructed via DefaultForArtboard — the Rive Android SDK does not expose | ||
| // the ViewModel name from a ViewModelInstance, so name-dependent operations are unavailable. | ||
| // Track: https://github.com/rive-app/rive-android/issues/XXX | ||
| private val viewModelName: String?, | ||
| private val parentFile: HybridRiveFile, | ||
| private val vmSource: ViewModelSource | ||
| ) : HybridViewModelSpec() { | ||
| companion object { | ||
| private const val TAG = "HybridViewModel" | ||
| private const val NO_NAME_ERROR = | ||
| "This operation requires the ViewModel name, which is unavailable for ViewModels " + | ||
| "obtained via defaultArtboardViewModel(). The Rive Android SDK does not yet expose " + | ||
| "the ViewModel name from a ViewModelInstance. Use a named ViewModel instead, or " + | ||
| "track the upstream fix: https://github.com/rive-app/rive-android/issues/XXX" |
There was a problem hiding this comment.
NO_NAME_ERROR (and the preceding comment) contains a placeholder upstream link (.../issues/XXX). Since this string is thrown to JS as an exception, it should reference the real upstream issue/PR (e.g. rive-android#443) or omit the link to avoid sending users to a dead URL.
| val vmSource = ViewModelSource.DefaultForArtboard(artboard) | ||
| // Name is null because the Rive Android SDK does not expose the ViewModel name | ||
| // from a ViewModelInstance — name-dependent operations will throw UnsupportedOperationException. | ||
| // Track upstream: https://github.com/rive-app/rive-android/issues/XXX |
There was a problem hiding this comment.
This comment references a placeholder upstream URL (.../issues/XXX). Since it documents a known limitation, it should point to the real tracking issue/PR so future maintainers/users can follow progress.
| // Track upstream: https://github.com/rive-app/rive-android/issues/XXX |
| /** | ||
| * Reproduces issue #159 — Rive graphics stutter when JS/UI thread is under heavy load. | ||
| * | ||
| * Loads vehicles.riv from URL (endless animation). | ||
| * Two buttons: block JS thread or block UI thread for ~60s. | ||
| * If the vehicles stop animating, rendering depends on that thread. | ||
| */ | ||
|
|
||
| const VEHICLES_URL = require('../../../assets/rive/rewards.riv'); | ||
|
|
There was a problem hiding this comment.
The file/constant naming and comment are inconsistent: the header says this loads vehicles.riv from a URL, but VEHICLES_URL is a local require() of rewards.riv. Consider either switching to the intended remote vehicles URL or updating the comment/constant name so the reproducer matches what it actually loads.
Adds a new native backend using Rive's experimental runtime APIs on both iOS and Android. The new backend is async-native — all ViewModel operations go through a CommandQueue, eliminating the need for
blockingAsync/runBlockingwrappers on the non-deprecated API surface.The experimental backend is now the default. Legacy backend files are moved to
ios/legacy/andandroid/src/legacy/(identical to main exceptgetEnums()stub andbackendproperty). New implementations live inios/new/andandroid/src/new/. CI runs tests on both backends.Release-please configured for beta prereleases (
0.5.0-beta, published as@next).Opting into the legacy backend
Without the flag, the experimental backend is used.
What works
viewModelAsync)RiveUIViewon iOS, custom implementation on Android)play()/pause()(iOS: togglesisPaused; Android: fully implemented)getEnums()for introspectiongetPropertyCountAsync/getInstanceCountAsyncKnown limitations
Android
defaultArtboardViewModeldoesn't expose the ViewModel name — pending rive-android#443. This causesmodelName/propertyCount/instanceCountto throw andviewModelAsyncpath validation to be skipped on those instances.replaceViewModelis a no-op (not yet implemented)iOS
reset()only pauses — doesn't actually reset the state machineBoth platforms