Skip to content

Update Android/iOS Managed Players to include onStartedFlow callback#896

Open
KetanReddy wants to merge 3 commits into
mainfrom
feature/mobile-managed-player-alignment
Open

Update Android/iOS Managed Players to include onStartedFlow callback#896
KetanReddy wants to merge 3 commits into
mainfrom
feature/mobile-managed-player-alignment

Conversation

@KetanReddy

Copy link
Copy Markdown
Member

Change Type (required)

Indicate the type of change your pull request is:

  • patch
  • minor
  • major
  • N/A

Does your PR have any documentation updates?

  • Updated docs
  • No Update needed
  • Unable to update docs

Release Notes

Brings the React Managed Player's onStartedFlow callback (added in #881) to iOS and Android. Consumers can now be notified when the managed player starts a flow, and receive the flow that was used to start it — without having to track it themselves. For performance, the callback hands back the in-memory flow String that was passed in, rather than reading it back out of Player (which would force a deserialization across the JS bridge).

@KetanReddy KetanReddy requested review from a team as code owners June 29, 2026 20:10
@KetanReddy KetanReddy added the minor Increment the minor version when merged label Jun 29, 2026
@intuit-svc

intuit-svc commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

Comparison against baseline from main. ⚠️ = regression (>10% slower), ✅ = improvement (>5% faster)

core/player ⚠️

Benchmark Current Baseline Change
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.bar 862.66K ops/s 811.76K ops/s +6.3% ✅
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets.1.name 525.81K ops/s 538.45K ops/s -2.3%
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets.01.name 539.59K ops/s 516.53K ops/s +4.5%
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets['01'].name 488.49K ops/s 428.46K ops/s +14.0% ✅
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets[01].name 515.71K ops/s 482.20K ops/s +6.9% ✅
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets[name = "frodo"].type 292.38K ops/s 292.80K ops/s -0.1%
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets["name" = "sprinkles"].type 210.82K ops/s 215.71K ops/s -2.3%
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets["isDog" = false].type 298.30K ops/s 289.19K ops/s +3.2%
core/player/src/binding/__tests__/parser.bench.ts > parser benchmarks > Resolving binding: foo.pets["isDog" = true].type 224.97K ops/s 298.58K ops/s -24.7% ⚠️
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.bar 402.43K ops/s 595.33K ops/s -32.4% ⚠️
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets.1.name 331.20K ops/s 388.29K ops/s -14.7% ⚠️
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets.01.name 327.75K ops/s 332.46K ops/s -1.4%
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets['01'].name 315.66K ops/s 327.84K ops/s -3.7%
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets[01].name 351.19K ops/s 346.15K ops/s +1.5%
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets[name = "frodo"].type 204.57K ops/s 236.93K ops/s -13.7% ⚠️
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets["name" = "sprinkles"].type 164.69K ops/s 188.82K ops/s -12.8% ⚠️
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets["isDog" = false].type 206.68K ops/s 211.70K ops/s -2.4%
core/player/src/binding/__tests__/parser.bench.ts > binding creation benchmarks > Resolving binding: foo.pets["isDog" = true].type 153.12K ops/s 219.91K ops/s -30.4% ⚠️
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = 1 + 3 (sync) 461.85K ops/s 422.46K ops/s +9.3% ✅
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = 1 + 3 (async) 358.92K ops/s 352.50K ops/s +1.8%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: conditional(true, true, false) (sync) 471.62K ops/s 485.17K ops/s -2.8%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: conditional(true, true, false) (async) 415.82K ops/s 429.57K ops/s -3.2%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = conditional({{bar}} > 0, true, false) (sync) 210.62K ops/s 181.50K ops/s +16.0% ✅
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = conditional({{bar}} > 0, true, false) (async) 165.38K ops/s 175.71K ops/s -5.9%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = conditional(conditional(true = false, false, true), conditional(false = false, true, false), conditional(true = true, false, true)) (sync) 153.07K ops/s 169.34K ops/s -9.6%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = conditional(conditional(true = false, false, true), conditional(false = false, true, false), conditional(true = true, false, true)) (async) 152.52K ops/s 107.08K ops/s +42.4% ✅
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = await(asyncTestFunction(1)) (sync) N/A N/A N/A
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = await(asyncTestFunction(1)) (async) 294.32K ops/s 272.46K ops/s +8.0% ✅
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = asyncTestFunction(1) (sync) 342.20K ops/s 258.18K ops/s +32.5% ✅
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = asyncTestFunction(1) (async) 289.87K ops/s 292.69K ops/s -1.0%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: asyncTestFunction(1) (sync) 866.96K ops/s 830.12K ops/s +4.4%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: asyncTestFunction(1) (async) 686.66K ops/s 662.45K ops/s +3.7%
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = conditional(!{{bar}} == false, await(asyncTestFunction(1)), false) (sync) 184.47K ops/s 171.20K ops/s +7.7% ✅
core/player/src/expressions/__tests__/performance.bench.ts > Expression Parsing/Execution Benchmark > Parsing: {{foo}} = conditional(!{{bar}} == false, await(asyncTestFunction(1)), false) (async) 172.57K ops/s 141.15K ops/s +22.3% ✅
core/player/src/view/resolver/__tests__/index.bench.ts > resolver benchmarks > initial resolve 593.94 ops/s 572.91 ops/s +3.7%
core/player/src/view/resolver/__tests__/index.bench.ts > resolver benchmarks > Resolving from cache 14.48K ops/s 15.52K ops/s -6.7%
core/player/src/view/resolver/__tests__/index.bench.ts > resolver benchmarks > data changes 2.66K ops/s 2.60K ops/s +2.4%
core/player/src/view/resolver/__tests__/index.bench.ts > resolver benchmarks > data changes slow 586.12 ops/s 538.53 ops/s +8.8% ✅

plugins/async-node/core

Benchmark Current Baseline Change
plugins/async-node/core/src/__tests__/index.bench.ts > async node benchmarks > Resolve Async Node 1 times 14.16K ops/s 11.66K ops/s +21.5% ✅
plugins/async-node/core/src/__tests__/index.bench.ts > async node benchmarks > Resolve Async Node 5 times 14.39K ops/s 11.19K ops/s +28.6% ✅
plugins/async-node/core/src/__tests__/index.bench.ts > async node benchmarks > Resolve Async Node 10 times 9.10K ops/s 7.94K ops/s +14.7% ✅
plugins/async-node/core/src/__tests__/index.bench.ts > async node benchmarks > Resolve Async Node 50 times 3.11K ops/s 3.15K ops/s -1.5%
plugins/async-node/core/src/__tests__/index.bench.ts > async node benchmarks > Resolve Async Node 100 times 1.75K ops/s 1.65K ops/s +5.7% ✅
plugins/async-node/core/src/__tests__/transform.bench.ts > async transform benchmarks > Resolve Async Node 1 times 7.16K ops/s 6.80K ops/s +5.4% ✅
plugins/async-node/core/src/__tests__/transform.bench.ts > async transform benchmarks > Resolve Async Node 5 times 7.04K ops/s 7.48K ops/s -5.8%
plugins/async-node/core/src/__tests__/transform.bench.ts > async transform benchmarks > Resolve Async Node 10 times 7.29K ops/s 7.09K ops/s +2.8%
plugins/async-node/core/src/__tests__/transform.bench.ts > async transform benchmarks > Resolve Async Node 50 times 2.76K ops/s 2.77K ops/s -0.5%
plugins/async-node/core/src/__tests__/transform.bench.ts > async transform benchmarks > Resolve Async Node 100 times 1.59K ops/s 1.52K ops/s +4.1%

react/player

Benchmark Current Baseline Change
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Render asset nested in 1 ReactAssets 589.97 ops/s 607.99 ops/s -3.0%
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Bubble errors nested in 1 ReactAssets 1.15K ops/s 1.04K ops/s +10.3% ✅
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Render asset nested in 5 ReactAssets 645.19 ops/s 619.23 ops/s +4.2%
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Bubble errors nested in 5 ReactAssets 1.09K ops/s 1.03K ops/s +6.0% ✅
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Render asset nested in 10 ReactAssets 637.73 ops/s 627.20 ops/s +1.7%
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Bubble errors nested in 10 ReactAssets 897.68 ops/s 841.28 ops/s +6.7% ✅
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Render asset nested in 50 ReactAssets 517.75 ops/s 481.86 ops/s +7.4% ✅
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Bubble errors nested in 50 ReactAssets 278.22 ops/s 271.63 ops/s +2.4%
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Render asset nested in 100 ReactAssets 390.42 ops/s 422.93 ops/s -7.7%
react/player/src/asset/__tests__/index.bench.tsx > ReactAsset benchmarks > Bubble errors nested in 100 ReactAssets 118.53 ops/s 129.15 ops/s -8.2%

@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (0597f2d) to head (82f8b9e).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@     Coverage Diff     @@
##   main   #896   +/-   ##
===========================
===========================

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

}

@Test
fun `startedFlows emits the flow used to start the player`() = runBlocking {

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.

hmm this test technically doesn't have any checks in it and relies on awaiting for something to happen so the code finishes executing. Can you check if this has a reasonable timeout so we don't wait the default 5 or 10min (forget how long it is) in case it doesn't pass?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added an explicit timeout, suspendUntilCondition has a default one of 5s.

private fun start(flow: String) {
// Notify that a flow has started, passing back the in-memory flow that was used to start
// Player (avoids deserializing the flow back across the JS bridge)
_startedFlows.tryEmit(flow)

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.

the flow technically hasn't started at this point, it's just about to, not sure if that distinction matters

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Technically the callback on the React side just waits for Player to be in a running state and I think this is the closest I could get it without having to actually introspect into Core Player's state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor Increment the minor version when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants