Skip to content

ci: temporary iOS simulator diagnostics (not for merge) - #14

Closed
predatorx7 wants to merge 7 commits into
mainfrom
ci-diag/ios
Closed

predatorx7 wants to merge 7 commits into
mainfrom
ci-diag/ios

Conversation

@predatorx7

@predatorx7 predatorx7 commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Throwaway branch used to diagnose the example-ios hang seen on #13 (the simulator test step printed nothing for 6 hours after the Xcode build). It runs the iOS job twice, headless and with Simulator.app open, each capped at 12 minutes, and dumps the simulator log and crash reports. Will be closed once the real fix lands on #13.

@predatorx7 predatorx7 changed the title Ci diag/ios ci: temporary iOS simulator diagnostics (not for merge) Oct 26, 2026
@predatorx7
predatorx7 marked this pull request as draft October 26, 2026 16:27
predatorx7 and others added 4 commits October 26, 2026 22:17
Tooling-only changes so the repository builds and tests on current
Flutter stable (3.47) with a current JDK. No behavior changes.

- javascript_android: convert android/build.gradle to Kotlin DSL on
  AGP 9.1.0 / Kotlin 2.4.0 / Java 17 / compileSdk 36, matching the
  Flutter 3.47 plugin template. minSdk is now declared as 26, which
  androidx.javascriptengine 1.0.0 already required. Drop the stale
  standalone settings.gradle (AGP 7.3 / Kotlin 1.7).
- javascript_android: bump pigeon ^26 -> ^29 and regenerate. The
  host API methods now use `@asyncCallback` so the generated Kotlin
  keeps the existing callback signatures instead of suspend functions.
  `make gen_schema` formats the generated Dart.
- example: regenerate the platform folders with `flutter create` on
  Flutter 3.47 (Gradle 9.3.1, AGP 9.1.0, Kotlin 2.4.0, SwiftPM), keeping
  lib/, README, pubspec and the path overrides. The previous Gradle 8.12
  wrapper could not run on JDK 25. Keep minSdk 26 and the macOS network
  client entitlement the example needs to load scripts from URLs. Remove
  the empty widget_test.dart which failed to load.
- CI: replace the eight per-package workflows, whose `paths:` filters
  lacked the `packages/` prefix and so never triggered, and which
  referenced javascript_ios/linux/macos/web/windows packages and
  fluttium flows that do not exist, with a single workflow that
  formats, analyzes and tests every package on current stable, builds
  the example for Android, and runs the example integration tests on
  an Android emulator, an iOS simulator and macOS desktop.
- dependabot: point at the real package directories and the two Gradle
  projects.
- javascript_darwin: exclude the vendored flutter_js sources from
  analysis; accept the analyzer excludes Flutter writes into
  analysis_options.yaml.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Define the one result contract for `runJavaScriptReturningResult` and
`runJavaScriptFromFileReturningResult`, document it in
`javascript_platform_interface` (2.1.0), implement it on Darwin
(2.1.0), and pin it with a device integration test that must pass on
Android, iOS and macOS.

Contract: the script's completion value, or the value a returned
Promise resolves to, is returned to Dart as a String verbatim. No JSON
decoding, no type detection. A non-string value resolves to the empty
string on every platform. A rejected promise or a thrown error
completes with a JavaScriptExecutionException carrying the JS message.
Callers who want structured data end their script with JSON.stringify
and jsonDecode it in Dart. The plugin deliberately does not parse the
script to recover a typed last expression.

Darwin fixes, each pinned by a real-JavaScriptCore test:
- NaN, Infinity, 1e21 and 2 ** 63 threw FormatException out of the
  typed converter; they now resolve to ''.
- Promise results were double-encoded (Promise.resolve("hi") gave
  "\"hi\""); the resolved JSValue is now inspected directly.
- undefined, functions, symbols, bigint and circular objects silently
  became null; they now resolve to ''.
- Promise rejection reasons were lost as "{}"; the Error message and
  stack, or String(reason), are now carried by the exception.
- A string result starting with "ERROR:" was reported as a failure and
  non-object throws were not; the vendored runtime now tracks whether an
  exception was actually raised.
- Channel messages reach onMessageReceived as the exact string passed to
  sendMessage, and sendMessage to an unregistered channel throws, which
  is what Android already did.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…gine 1.1.1

Fixes the Android half of #11 and migrates channel messaging to the
proper message-port API.

Results: `runJavaScriptReturningResult` and
`runJavaScriptFromFileReturningResult` now return the engine's string
untouched. The old `parseValue` heuristic, which guessed types from the
string content (a JS string "42" became int 42, '{"a":1}' became a
Map, while an actual JS number 42 arrived as "" because
androidx.javascriptengine coerces every non-string result to ""), is
removed. This is the documented behavior change of this release:
callers jsonDecode themselves. A warning is logged at isolate start if
the WebView lacks JS_FEATURE_PROMISE_RETURN, in which case promises
cannot be awaited by the engine and resolve to "".

Messaging: bump androidx.javascriptengine 1.0.0 -> 1.1.1 and, when
JS_FEATURE_MESSAGE_PORTS is supported, open one MessagePort per isolate
with createMessageChannel; JS obtains it with android.getNamedPort and
posts {channelName, id, message} as a string, replies travel back as
{channelName, id, ok, message | error}. Messages posted before the port
promise resolves are queued. Selection order is message port, then the
console-messaging hack (JS_FEATURE_CONSOLE_MESSAGING), then timer
polling, gated by isFeatureSupported, so older WebViews keep working.
Pigeon gains a JavaScriptAndroidMessagePortHandler proxy API and two
host methods; the public Dart API is unchanged apart from
@VisibleForTesting hooks to force a transport.

removeJavaScriptChannel now also deletes the channel on the JS side so
sendMessage on a removed channel throws, as it does on Darwin.

Tests: 35 Dart unit tests against a fake pigeon host (verbatim results,
transport selection, port/console/polling routing, SetTimeout,
exception mapping) and a device test that forces each of the three
transports in turn. Verified on an API 37 emulator (WebView 153), where
logcat confirms "Message port transport ...: enabled" by default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- javascript_flutter 1.3.0: rewrite the runJavaScriptReturningResult
  dartdoc and the README around the string-in, string-out contract,
  with the JSON.stringify + jsonDecode pattern as the way to get
  structured data back, and a loud behavior-change note with migration
  steps. Depend on javascript_platform_interface ^2.1.0,
  javascript_android ^2.2.0 and javascript_darwin ^2.1.0 so the fixed
  implementations are guaranteed.
- javascript_flutter tests: 15 unit tests pin the public JavaScript API
  against a mock platform (ids, pass-through of results, forwarding,
  dispose semantics, latching of unavailable-platform errors).
- example: README snippet and app updated to the contract; the console
  pretty-prints a result only when it parses as JSON, purely as a
  convenience in the example. Add a widget smoke test and model tests
  so `flutter test` finds tests.
- cspell: add the words the new docs use.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@predatorx7

Copy link
Copy Markdown
Owner Author

Diagnostics done: the example-ios hang was a headless-simulator VM-service discovery issue on the hosted macOS runners; the fix (open Simulator.app, watchdog + retry, explicit shutdown) is in #13, which is green. API 37.x emulator images time out booting on hosted Linux runners, so CI stays on API 36.

@predatorx7 predatorx7 closed this Oct 26, 2026
@predatorx7
predatorx7 deleted the ci-diag/ios branch October 26, 2026 17:54
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.

1 participant