Javascript-Rust RPC
It is possible to configure Webview-RPC events for communication between Javascript and Rust. RPC responses are not supported currently.
Serde setup
First, make sure that your crate has serde installed. Add to Cargo.toml
:
serde = { version = "1.0", features = [ "derive" ] }
In the application, import serde:
use serde::{Serialize, Deserialize};
RPC from Javascript to Rust
First, define a struct for the message (or enum, or other deserializable type). Make it deserializable with the serde's Deserialize
-trait. Debug
is optional.
#![allow(unused)] fn main() { extern crate bevy_webview; use bevy_webview::serde::Deserialize; #[derive(Deserialize, Debug)] pub struct LoginRequest { username: String, } }
Configure an event in the application setup code. The first parameter is a message method
, used as a key when sending events.
#![allow(unused)] fn main() { extern crate bevy; extern crate bevy_webview; use bevy::prelude::*; use bevy_webview::prelude::*; use bevy_webview::serde::Deserialize; #[derive(Deserialize)] struct LoginRequest {}; App::new() .add_plugin(WebviewPlugin::with_engine(webview_engine::headless)) // initializations... .add_webview_input_event::<LoginRequest>("login"); }
And define a system to receive events, using a WebviewEventReader<T>
:
#![allow(unused)] fn main() { extern crate bevy; extern crate bevy_webview; use bevy::prelude::*; use bevy_webview::prelude::*; struct LoginRequest { username: String }; fn login_handler(mut login_request_events: WebviewEventReader<LoginRequest>) { for event in login_request_events.iter() { println!("Received a login request, username={:?}", event.username); } } }
Finally, call the RPC method from Javascript. bevy_webview
will try to unmarshal the Javascript-provided JSON into an event struct defined and referenced by add_webview_input_event
key string.
await rpc.call("login", { username: "test" });
Be mindful of not registering too many (hundreds) simultaneous events, as each call to add_webview_input_event
will create two new Bevy-systems (standard Bevy event creates one system).
It is also possible to create a Rust enum
and reference that by Javascript.
RPC from Rust to Javascript
First, define a struct for the message (or enum, or other deserializable type). Make it serializable with the serde's Serialize
-trait. Debug
is optional.
#![allow(unused)] fn main() { extern crate bevy_webview; use bevy_webview::serde::Serialize; #[derive(Serialize, Debug)] pub struct AppTime { seconds_since_startup: f64, } }
Then, configure an outgoing event in the setup code. The first parameter is the event method key, by which Javascript will subscribe into the event.
#![allow(unused)] fn main() { extern crate bevy; extern crate bevy_webview; use bevy::prelude::*; use bevy_webview::prelude::*; use bevy_webview::serde::Serialize; #[derive(Serialize)] struct AppTime {}; App::new() .add_plugin(WebviewPlugin::with_engine(webview_engine::headless)) // initializations... .add_webview_output_event::<AppTime>("app_time"); }
In Javascript, register an event handler by calling rpc.on(method, callback)
. You can have multiple registrations for one method. The parameter for callback will be a Javascript object unmarshalled from JSON by JSON.parse
.
rpc.on("app_time", (app_time) => {
console.log(
"Seconds since startup: " + app_time.seconds_since_startup.toFixed(4)
);
});
Finally, send an event from a Bevy system using a WebviewEventWriter<T>
:
#![allow(unused)] fn main() { extern crate bevy; extern crate bevy_webview; use bevy::prelude::*; use bevy_webview::prelude::*; struct AppTime { seconds_since_startup: f64 }; fn send_time_system(mut app_time: WebviewEventWriter<AppTime>, time: Res<Time>) { app_time.send(AppTime { seconds_since_startup: time.seconds_since_startup(), }); } }
For now, you should avoid redrawing on Javascript by every frame. See performance for more information.