diff --git a/flutter_package/example/native/hub/Cargo.toml b/flutter_package/example/native/hub/Cargo.toml index c99cdbba..df1e29c5 100644 --- a/flutter_package/example/native/hub/Cargo.toml +++ b/flutter_package/example/native/hub/Cargo.toml @@ -15,13 +15,13 @@ crate-type = ["lib", "cdylib", "staticlib"] rinf = "7.0.4" prost = "0.13.0" tokio = { version = "1", features = ["rt", "sync", "time", "macros"] } -tokio_with_wasm = { version = "0.7.1", features = [ +tokio_with_wasm = { version = "0.7.2", features = [ "rt", "sync", "time", "macros", ] } -wasm-bindgen = "0.2.93" +wasm-bindgen = "0.2.95" messages = "0.3.1" anyhow = "1.0.89" sample_crate = { path = "../sample_crate" } diff --git a/flutter_package/example/web/index.html b/flutter_package/example/web/index.html index 1aa025dd..29b58086 100644 --- a/flutter_package/example/web/index.html +++ b/flutter_package/example/web/index.html @@ -21,7 +21,7 @@ - + diff --git a/flutter_package/lib/src/interface_web.dart b/flutter_package/lib/src/interface_web.dart index cac787e0..07a2ab79 100644 --- a/flutter_package/lib/src/interface_web.dart +++ b/flutter_package/lib/src/interface_web.dart @@ -2,7 +2,6 @@ import 'load_web.dart'; import 'dart:typed_data'; -import 'dart:js' as js; import 'interface.dart'; import 'dart:async'; import 'dart:convert'; @@ -16,11 +15,11 @@ void setCompiledLibPathReal(String path) { Future prepareInterfaceReal( AssignRustSignal assignRustSignal, ) async { + // Load the JavaScript module. await loadJsFile(); - // Listen to Rust via JavaScript - final jsObject = js.context['rinf'] as js.JsObject; - jsObject['send_rust_signal_extern'] = ( + // Listen to Rust via JavaScript. + rinfBindingsObject['send_rust_signal_extern'] = ( int messageId, Uint8List messageBytes, Uint8List binary, @@ -39,8 +38,7 @@ void startRustLogicReal() { if (wasAlreadyLoaded) { return; } - final jsObject = js.context['rinf'] as js.JsObject; - jsObject.callMethod('start_rust_logic_extern', []); + wasmBindingsObject.callMethod('start_rust_logic_extern', []); } void stopRustLogicReal() { @@ -52,8 +50,7 @@ void sendDartSignalReal( Uint8List messageBytes, Uint8List binary, ) { - final jsObject = js.context['rinf'] as js.JsObject; - jsObject.callMethod('send_dart_signal_extern', [ + wasmBindingsObject.callMethod('send_dart_signal_extern', [ messageId, messageBytes, binary, diff --git a/flutter_package/lib/src/load_web.dart b/flutter_package/lib/src/load_web.dart index 3b7fd41f..ba850643 100644 --- a/flutter_package/lib/src/load_web.dart +++ b/flutter_package/lib/src/load_web.dart @@ -6,22 +6,33 @@ import 'dart:async'; String? jsLibPath; -// When Dart performs hot restart, -// the `rinf` object is already defined -// as a global JavaScript variable. -final wasAlreadyLoaded = js.context.hasProperty('rinf'); - void setJsLibPath(String path) { jsLibPath = path; } +bool wasAlreadyLoaded = false; +js.JsObject rinfBindingsObject = js.context['rinfBindings']; +js.JsObject wasmBindingsObject = js.context['wasmBindings']; + Future loadJsFile() async { + // When Dart performs hot restart, + // the `rinfBindings` JavaScript object is already defined + // as a global JavaScript variable. + wasAlreadyLoaded = js.context.hasProperty('rinfBindings'); + + // Stop loading if it already has been done. if (wasAlreadyLoaded) { return; } + // Create the namespace JavaScript object. + // This namespace object is used by Rust + // to call functions defined in Dart. + js.context['rinfBindings'] = js.JsObject.jsify({}); + + // Prepare to await the module load. final loadCompleter = Completer(); - js.context['completeRinfLoad'] = loadCompleter.complete; + rinfBindingsObject['completeRinfLoad'] = loadCompleter.complete; // Flutter app doesn't always have the top-level path of the domain. // Sometimes, the flutter app might be placed in a lower path. @@ -36,10 +47,10 @@ Future loadJsFile() async { scriptElement.type = 'module'; scriptElement.innerHtml = ''' import init, * as wasmBindings from "$fullUrl"; +globalThis.wasmBindings = wasmBindings; await init(); -window.rinf = { ...wasmBindings }; -completeRinfLoad(); -delete window.completeRinfLoad; +rinfBindings.completeRinfLoad(); +delete rinfBindings.completeRinfLoad; '''; document.head!.append(scriptElement); diff --git a/flutter_package/template/native/hub/Cargo.toml b/flutter_package/template/native/hub/Cargo.toml index 8d06899e..c3f8d114 100644 --- a/flutter_package/template/native/hub/Cargo.toml +++ b/flutter_package/template/native/hub/Cargo.toml @@ -17,5 +17,5 @@ prost = "0.13.0" tokio = { version = "1", features = ["rt", "macros"] } # Uncomment below to target the web. -# tokio_with_wasm = { version = "0.7.1", features = ["rt", "macros"] } -# wasm-bindgen = "0.2.93" +# tokio_with_wasm = { version = "0.7.2", features = ["rt", "macros"] } +# wasm-bindgen = "0.2.95" diff --git a/rust_crate/Cargo.toml b/rust_crate/Cargo.toml index c4df9b1f..b8a95e90 100644 --- a/rust_crate/Cargo.toml +++ b/rust_crate/Cargo.toml @@ -25,8 +25,8 @@ backtrace = { version = "0.3.69", optional = true } [target.'cfg(target_family = "wasm")'.dependencies] js-sys = "0.3.70" -wasm-bindgen = "0.2.93" -wasm-bindgen-futures = "0.4.43" +wasm-bindgen = "0.2.95" +wasm-bindgen-futures = "0.4.45" [lints.clippy] unwrap_used = "deny" diff --git a/rust_crate/src/error.rs b/rust_crate/src/error.rs index 14754371..f69030b8 100644 --- a/rust_crate/src/error.rs +++ b/rust_crate/src/error.rs @@ -6,6 +6,7 @@ pub enum RinfError { NoDartIsolate, CannotDecodeMessage, NoSignalHandler, + NoBindings, } impl fmt::Display for RinfError { @@ -20,6 +21,9 @@ impl fmt::Display for RinfError { Self::NoSignalHandler => { write!(f, "Could not find the handler for Dart signal") } + Self::NoBindings => { + write!(f, "Rinf bindings are not ready") + } } } } diff --git a/rust_crate/src/interface_web.rs b/rust_crate/src/interface_web.rs index 9e849056..173c3141 100644 --- a/rust_crate/src/interface_web.rs +++ b/rust_crate/src/interface_web.rs @@ -22,12 +22,18 @@ where #[wasm_bindgen] extern "C" { - #[wasm_bindgen(js_namespace = rinf, catch)] + // The reason this extern function is marked `catch` + // and returns a `Result` is that the + // `rinfBindings` JavaScript object created by Dart + // does not exist in web workers; it is only available + // in the main JavaScript thread. Loading the function + // fails in web workers. + #[wasm_bindgen(js_namespace = rinfBindings, catch)] pub fn send_rust_signal_extern( resource: i32, message_bytes: Uint8Array, binary: Uint8Array, - ) -> Result<(), JsValue>; // catch the JS exception + ) -> Result<(), JsValue>; } pub fn send_rust_signal_real( @@ -35,15 +41,10 @@ pub fn send_rust_signal_real( message_bytes: Vec, binary: Vec, ) -> Result<(), RinfError> { - match send_rust_signal_extern( + let result = send_rust_signal_extern( message_id, js_sys::Uint8Array::from(message_bytes.as_slice()), js_sys::Uint8Array::from(binary.as_slice()), - ) { - Ok(_) => Ok(()), - Err(e) => { - crate::debug_print!("An error occured during the launch: {e:?}"); - Err(RinfError::NoSignalHandler) - } - } + ); + result.map_err(|_| RinfError::NoBindings) }