rive-app / rive-app/rive-react-native

[Android] Nested-artboard Property Groups in an ArtboardComponentList never advance — silent no-op (iOS + web OK)

Open
#439 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
783
Forks
81
Avg merge
3d 6h
Merged PRs (30d)
3

Description

Reproduction repository (clone → npm installnpx expo run:android):
https://github.com/lsadsad/rive-android-nested-pg-repro — contains both .riv files, the probe component, and a README with the observed logs. Verified end-to-end on 2026-08-23: fresh install from public npm, 38 s build, both probes reproduce on an API 36 emulator while iOS passes.

Summary

A Property Group keyed on a nested item artboard, instanced through an ArtboardComponentList bound to a view-model list, never advances on Android. The file loads, the view model binds, the list resolves, and property writes land and read back correctly — but the group's animated property stays at its initial value forever. The identical JS code and identical .riv binaries work correctly on iOS and on web (@rive-app/canvas).

The failure is completely silent: no error, no warning, no onError callback — the animation simply never runs. On a production screen this presents as "loads but sits there."

Environment

@rive-app/react-native 0.4.19
react-native-nitro-modules 0.35.10
rive-android 11.7.2 (as pinned by the package's runtimeVersions.android)
RiveRuntime (iOS) 6.21.1 (pinned by runtimeVersions.ios, verified in Podfile.lock)
React Native 0.85.3 (Expo SDK 56.0.18, new architecture)
Android emulator, API 36 (Android 16), arm64 — FAILS
iOS simulator, iPhone 15 Pro — works
Web reference @rive-app/canvas 2.39.1 — works

The .riv structure (two binaries, 861 B and 772 B)

Parent artboard PGNestProbe, state machine PGNestSM, view model with a list property items (3 items). The list drives an ArtboardComponentList; each item is a nested item artboard whose view model has:

  • progress (number) — animated 0 → 100 over 2000 ms by a Property Group keyed on the nested item artboard
  • phase (number) — gate input (main binary only)

Two variants isolate conditionality:

  1. Gated (pg_nest_probe.riv, md5 d96f10b1): item state machine has ItemIdle --[phase >= 1]--> ItemRun. The host writes phase := 1 per item, staggered 700 ms apart, and polls progress per item.
  2. Autoplay discriminator (pg_nest_probe_pregate.riv, md5 002f3738): built before the gate existed — no phase property, no ItemIdle state, no condition anywhere. Each item artboard runs entry → ItemRun and should simply play.

Reproduction (minimal shape)

const { riveFile } = useRiveFile(require('./pg_nest_probe.riv'));
const { instance } = useViewModelInstance(riveFile, { async: true });
const { length, getInstanceAt } = useRiveList('items', instance);

// capture the 3 item instances once length resolves ...
const { value: p0 } = useRiveNumber('progress', items[0]);           // per-item read
const { value: ph0, setValue: setPh0 } = useRiveNumber('phase', items[0]); // per-item write

// render
<RiveView file={riveFile} dataBind={instance}
  artboardName="PGNestProbe" stateMachineName="PGNestSM" autoPlay />
// then: setPh0(1) (staggered per item), poll p0/p1/p2 every ~250 ms

The full probe component (single file, includes the verdict harness that produced the logs below) is App.tsx in the repro repository above.

Expected

progress ramps 0 → 100 per item; with the staggered gate writes the three items diverge (per-instance state). This is exactly what happens on iOS and web.

Actual

iOS — works (same day, same code, same binaries)
[PGNestNitro] list 'items' length=3; captured 3 instances
[PGNestNitro] phase[0] := 1
[PGNestNitro] t=254ms  [10.83, 0, 0]
[PGNestNitro] phase[1] := 1
[PGNestNitro] t=786ms  [37.50, 2.50, 0]
[PGNestNitro] phase[2] := 1
[PGNestNitro] t=1554ms [75.83, 40.83, 5.83]
[PGNestNitro] divergence read: [79.17, 43.33, 8.33]   ← three distinct values, staggered as written
[PGNestNitro] t=3654ms [100, 100, 100]
Android — gated binary: writes land, nothing advances
[PGNestNitro] list 'items' length=3; captured 3 instances
[PGNestNitro] phase[0] := 1
[PGNestNitro] t=274ms  [0,0,0]
[PGNestNitro] phase[1] := 1
[PGNestNitro] phase[2] := 1
[PGNestNitro] t=1605ms [0,0,0]
...
[PGNestNitro] t=4787ms [0,0,0]        ← 4.6 s, zero movement
phase reads back [1,1,1]              ← the writes DID land

progress reads are real zeros (values resolve; they are not undefined/null), and phase reads back 1/1/1 — so binding, list traversal, per-item addressing, writes, and reads all work. Only the advance is missing.

Android — autoplay discriminator: eliminates conditions entirely
[Pregate] vm: loading=false instance=ready err=null
[Pregate] list 'items' length=3; captured 3
[Pregate] t=243ms  [0,0,0]
...
[Pregate] t=3053ms [0,0,0]
VERDICT: progress never moved (spread 0.00) on an AUTOPLAYING build with
no condition anywhere.

With no gate, no condition, and no host writes at all, the nested group still never advances on Android. This rules out "the transition condition doesn't resolve against a list-item instance" — the group itself does not advance.

Ruled out

  • Stale install / stale native runtime — single canonical install verified before each run; fresh expo run:android build.
  • Asset drift — md5-verified binaries, served via Metro on both platforms.
  • Probe/verdict artifact — the harness treats unresolved reads as INCONCLUSIVE, never as zeros; the Android zeros are resolved readings. The same harness produced PASS on iOS the same day.
  • JS-layer difference — identical component code on both platforms; the divergence is below the JS bridge.

Notes

  • Everything around the advance works on Android: RiveFile load, useViewModelInstance, useRiveList + getInstanceAt, per-item useRiveNumber reads and writes (with listeners firing for phase).
  • The failure mode is the dangerous kind: silent. If a runtime can't advance nested Property Groups in an ArtboardComponentList, an error or console warning at bind time would save integrators days.
  • Everything needed to reproduce is in https://github.com/lsadsad/rive-android-nested-pg-repro; happy to provide additional logs or run variants on request.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Clone the linked reproduction repository, run npm install and npx expo run:android, then start with App.tsx and compare the gated and autoplay probes. Trace the Android path for nested item artboards in an ArtboardComponentList and property-group advancement; done means progress advances per item on Android without breaking the existing iOS and web behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, react-native, typescript
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.