Skip to content

feat(web): migrate web bindings to dart:js_interop for WebAssembly (dart2wasm) support#132

Open
sunweiyang wants to merge 1 commit into
AgoraIO-Extensions:mainfrom
workplacearcade:js-interop-wasm-support
Open

feat(web): migrate web bindings to dart:js_interop for WebAssembly (dart2wasm) support#132
sunweiyang wants to merge 1 commit into
AgoraIO-Extensions:mainfrom
workplacearcade:js-interop-wasm-support

Conversation

@sunweiyang

Copy link
Copy Markdown

Problem

flutter build web --wasm builds that include this package compile successfully but break at runtime: the platform implementation is selected via

export 'iris_method_channel_internal_expect.dart'
    if (dart.library.io) 'iris_method_channel_internal_actual_io.dart'
    if (dart.library.js) 'iris_method_channel_internal_actual_web.dart';

and under dart2wasm both dart.library.io and dart.library.js are false (wasm exposes dart.library.js_interop instead), so the stub implementation is exported and createAgoraRtcEngine() in agora_rtc_engine throws UnimplementedError: Unimplemented createPlatformBindingsProvider before any API call runs. Because this is a silent wrong-import selection rather than a compile error, apps only discover it in production wasm builds.

Changes

  • Conditional imports in iris_method_channel_internal.dart and utils.dart: dart.library.jsdart.library.js_interop, which is true under both dart2js and dart2wasm, so a single web implementation serves both compilers (including the JS fallback that --wasm builds ship for non-wasmGC browsers).
  • lib/src/platform/web/bindings/iris_api_common_bindings_js.dart: migrated from legacy package:js @JS()/@anonymous classes to dart:js_interop extension types (legacy package:js/dart:js are unavailable under dart2wasm):
    • array-typed members are now JSArray — under dart2wasm Dart Lists are not JS arrays, so implicit passthrough no longer exists; callers convert with .toJS/.toDart.
    • callIrisApi is now typed JSPromise<CallIrisApiResult> (what IrisCore.callIrisApi actually returns) instead of int + a dartify() Promise cast, which does not work under dart2wasm.
    • IrisCEventHandler is now a JSFunction typedef; iris_method_channel_internal_web.dart uses .toJS instead of allowInterop.
  • pubspec.yaml: SDK floor raised to >=3.3.0 (required for dart:js_interop extension types). The language-version bump also requires the ffigen-generated ffi.Struct subclasses to be final (Dart 3 class modifiers) — io-only files, no behavior change.

Breaking-change note

The exported web bindings surface (iris_method_channel_bindings_web.dart) changes shape (JS types instead of Dart lists/functions). Its consumer in agora_rtc_engine needs the matching one-file update to its web binding delegate — I will submit that companion PR to Agora-Flutter-SDK referencing this one. test/platform/fake still uses legacy interop and is untouched in this PR; happy to migrate it as well if you'd like.

Testing

  • dart analyze lib clean (errors/warnings).
  • End-to-end smoke test in a production Flutter app (agora_rtc_engine 6.6.3 + iris-web-rtc 0.8.1, headless Chrome with fake media devices): under both the wasm and dart2js runtimes, createAgoraRtcEngineinitializeregisterEventHandlerenableAudiojoinChannel all succeed, and the JS→Dart event path delivers typed events (including the buffer marshalling in both directions). dart2js behavior is unchanged.

Under dart2wasm the 'dart.library.js' conditional-import predicate is
false, so the platform selection fell through to the stub and
createAgoraRtcEngine() threw UnimplementedError on flutter build
web --wasm. Switch the conditionals to 'dart.library.js_interop'
(true under both dart2js and dart2wasm) and migrate the web bindings
off legacy package:js/dart:js:

- iris_api_common_bindings_js.dart: @JS/@anonymous classes ->
  dart:js_interop extension types; array members are JSArray;
  callIrisApi is typed as JSPromise<CallIrisApiResult> (what
  IrisCore.callIrisApi actually returns); IrisCEventHandler is now a
  JSFunction typedef.
- iris_method_channel_internal_web.dart: allowInterop -> .toJS.
- SDK floor raised to 3.3 (extension types); generated ffi Struct
  subclasses marked 'final' to satisfy Dart 3 class modifiers.

Note: consumers of iris_method_channel_bindings_web.dart must convert
Dart lists/typed-data with .toJS (see Agora-Flutter-SDK companion
change). Tests under test/platform/fake still use legacy interop and
are unchanged.

Generated with AI assistance (Claude Code).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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