Skip to content

Commit b9ce7b9

Browse files
authored
refactor(tauri): Webview traits (#1183)
1 parent 555d667 commit b9ce7b9

File tree

20 files changed

+380
-137
lines changed

20 files changed

+380
-137
lines changed

.changes/webview-traits.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": minor
3+
---
4+
5+
The Tauri integration with Webview was refactored to use traits, which allows custom implementations by developers and simplifies changes on the webview implementation.

cli/tauri.js/templates/src-tauri/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
mod cmd;
77

88
fn main() {
9-
tauri::AppBuilder::new()
9+
tauri::AppBuilder::<tauri::flavors::Official>::new()
1010
.invoke_handler(|_webview, arg| async move {
1111
use cmd::Cmd::*;
1212
match serde_json::from_str(&arg) {

tauri/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ features = [ "all-api" ]
2020
[dependencies]
2121
serde_json = "1.0"
2222
serde = { version = "1.0", features = [ "derive" ] }
23-
webview_official = "0.1.1"
23+
webview_official = "0.2.0"
2424
tauri_includedir = "0.6.0"
2525
phf = "0.8.0"
2626
base64 = "0.13.0"

tauri/examples/communication/src-tauri/Cargo.lock

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tauri/examples/communication/src-tauri/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct Reply {
1313
}
1414

1515
fn main() {
16-
tauri::AppBuilder::new()
16+
tauri::AppBuilder::<tauri::flavors::Official>::new()
1717
.setup(|webview, _source| async move {
1818
let mut webview = webview.clone();
1919
tauri::event::listen(String::from("js-event"), move |msg| {

tauri/src/app.rs

+21-19
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
1+
use crate::Webview;
12
use futures::future::BoxFuture;
2-
use webview_official::WebviewMut;
33

44
mod runner;
55

6-
type InvokeHandler =
7-
dyn Fn(WebviewMut, String) -> BoxFuture<'static, Result<(), String>> + Send + Sync;
8-
type Setup = dyn Fn(WebviewMut, String) -> BoxFuture<'static, ()> + Send + Sync;
6+
type InvokeHandler<W> = dyn Fn(W, String) -> BoxFuture<'static, Result<(), String>> + Send + Sync;
7+
type Setup<W> = dyn Fn(W, String) -> BoxFuture<'static, ()> + Send + Sync;
98

109
/// The application runner.
11-
pub struct App {
10+
pub struct App<W: Webview> {
1211
/// The JS message handler.
13-
invoke_handler: Option<Box<InvokeHandler>>,
12+
invoke_handler: Option<Box<InvokeHandler<W>>>,
1413
/// The setup callback, invoked when the webview is ready.
15-
setup: Option<Box<Setup>>,
14+
setup: Option<Box<Setup<W>>>,
1615
/// The HTML of the splashscreen to render.
1716
splashscreen_html: Option<String>,
1817
}
1918

20-
impl App {
19+
impl<W: Webview + 'static> App<W> {
2120
/// Runs the app until it finishes.
2221
pub fn run(self) {
2322
runner::run(self).expect("Failed to build webview");
@@ -28,7 +27,7 @@ impl App {
2827
/// The message is considered consumed if the handler exists and returns an Ok Result.
2928
pub(crate) async fn run_invoke_handler(
3029
&self,
31-
webview: &mut WebviewMut,
30+
webview: &mut W,
3231
arg: &str,
3332
) -> Result<bool, String> {
3433
if let Some(ref invoke_handler) = self.invoke_handler {
@@ -40,7 +39,7 @@ impl App {
4039
}
4140

4241
/// Runs the setup callback if defined.
43-
pub(crate) async fn run_setup(&self, webview: &mut WebviewMut, source: String) {
42+
pub(crate) async fn run_setup(&self, webview: &mut W, source: String) {
4443
if let Some(ref setup) = self.setup {
4544
let fut = setup(webview.clone(), source);
4645
fut.await;
@@ -55,16 +54,16 @@ impl App {
5554

5655
/// The App builder.
5756
#[derive(Default)]
58-
pub struct AppBuilder {
57+
pub struct AppBuilder<W: Webview> {
5958
/// The JS message handler.
60-
invoke_handler: Option<Box<InvokeHandler>>,
59+
invoke_handler: Option<Box<InvokeHandler<W>>>,
6160
/// The setup callback, invoked when the webview is ready.
62-
setup: Option<Box<Setup>>,
61+
setup: Option<Box<Setup<W>>>,
6362
/// The HTML of the splashscreen to render.
6463
splashscreen_html: Option<String>,
6564
}
6665

67-
impl AppBuilder {
66+
impl<W: Webview + 'static> AppBuilder<W> {
6867
/// Creates a new App builder.
6968
pub fn new() -> Self {
7069
Self {
@@ -77,7 +76,7 @@ impl AppBuilder {
7776
/// Defines the JS message handler callback.
7877
pub fn invoke_handler<
7978
T: futures::Future<Output = Result<(), String>> + Send + Sync + 'static,
80-
F: Fn(WebviewMut, String) -> T + Send + Sync + 'static,
79+
F: Fn(W, String) -> T + Send + Sync + 'static,
8180
>(
8281
mut self,
8382
invoke_handler: F,
@@ -91,7 +90,7 @@ impl AppBuilder {
9190
/// Defines the setup callback.
9291
pub fn setup<
9392
T: futures::Future<Output = ()> + Send + Sync + 'static,
94-
F: Fn(WebviewMut, String) -> T + Send + Sync + 'static,
93+
F: Fn(W, String) -> T + Send + Sync + 'static,
9594
>(
9695
mut self,
9796
setup: F,
@@ -109,13 +108,16 @@ impl AppBuilder {
109108
}
110109

111110
/// Adds a plugin to the runtime.
112-
pub fn plugin(self, plugin: impl crate::plugin::Plugin + Send + Sync + Sync + 'static) -> Self {
113-
crate::async_runtime::block_on(crate::plugin::register(plugin));
111+
pub fn plugin(
112+
self,
113+
plugin: impl crate::plugin::Plugin<W> + Send + Sync + Sync + 'static,
114+
) -> Self {
115+
crate::async_runtime::block_on(crate::plugin::register(W::plugin_store(), plugin));
114116
self
115117
}
116118

117119
/// Builds the App.
118-
pub fn build(self) -> App {
120+
pub fn build(self) -> App<W> {
119121
App {
120122
invoke_handler: self.invoke_handler,
121123
setup: self.setup,

tauri/src/app/runner.rs

+21-20
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66
},
77
};
88

9-
use webview_official::{SizeHint, Webview, WebviewBuilder};
9+
use crate::{SizeHint, Webview, WebviewBuilder};
1010

1111
use super::App;
1212
#[cfg(embedded_server)]
@@ -20,7 +20,7 @@ enum Content<T> {
2020
}
2121

2222
/// Main entry point for running the Webview
23-
pub(crate) fn run(application: App) -> crate::Result<()> {
23+
pub(crate) fn run<W: Webview + 'static>(application: App<W>) -> crate::Result<()> {
2424
// setup the content using the config struct depending on the compile target
2525
let main_content = setup_content()?;
2626

@@ -48,8 +48,10 @@ pub(crate) fn run(application: App) -> crate::Result<()> {
4848
// build the webview
4949
let mut webview = build_webview(application, main_content, splashscreen_content)?;
5050

51-
let mut webview_ = webview.as_mut();
52-
crate::async_runtime::spawn(async move { crate::plugin::created(&mut webview_).await });
51+
let mut webview_ = webview.clone();
52+
crate::async_runtime::spawn(async move {
53+
crate::plugin::created(W::plugin_store(), &mut webview_).await
54+
});
5355

5456
// spawn the embedded server on our server url
5557
#[cfg(embedded_server)]
@@ -238,11 +240,11 @@ pub fn init() -> String {
238240
}
239241

240242
// build the webview struct
241-
fn build_webview<'a>(
242-
application: App,
243+
fn build_webview<W: Webview + 'static>(
244+
application: App<W>,
243245
content: Content<String>,
244246
splashscreen_content: Option<Content<String>>,
245-
) -> crate::Result<Webview<'a>> {
247+
) -> crate::Result<W> {
246248
let config = get()?;
247249
let debug = cfg!(debug_assertions);
248250
// get properties from config struct
@@ -254,7 +256,7 @@ fn build_webview<'a>(
254256
SizeHint::FIXED
255257
};
256258
// let fullscreen = config.tauri.window.fullscreen;
257-
let title = config.tauri.window.title.clone().into_boxed_str();
259+
let title = config.tauri.window.title.clone();
258260

259261
let has_splashscreen = splashscreen_content.is_some();
260262
let initialized_splashscreen = Arc::new(AtomicBool::new(false));
@@ -281,18 +283,18 @@ fn build_webview<'a>(
281283
{plugin_init}
282284
"#,
283285
event_init = init(),
284-
plugin_init = crate::async_runtime::block_on(crate::plugin::init_script())
286+
plugin_init = crate::async_runtime::block_on(crate::plugin::init_script(W::plugin_store()))
285287
);
286288

287-
let mut webview = WebviewBuilder::new()
288-
.init(Box::leak(init.into_boxed_str()))
289-
.title(Box::leak(title))
289+
let mut webview = W::Builder::new()
290+
.init(&init)
291+
.title(&title)
290292
.width(width as usize)
291293
.height(height as usize)
292-
.resize(resizable)
294+
.resizable(resizable)
293295
.debug(debug)
294-
.url(Box::leak(url.into_boxed_str()))
295-
.build();
296+
.url(&url)
297+
.finish();
296298
// TODO waiting for webview window API
297299
// webview.set_fullscreen(fullscreen);
298300

@@ -304,7 +306,7 @@ fn build_webview<'a>(
304306
webview.dispatch(move |_webview| _webview.eval(&contents));
305307
}
306308

307-
let w = webview.as_mut();
309+
let w = webview.clone();
308310
let application = Arc::new(application);
309311

310312
webview.bind("__TAURI_INVOKE_HANDLER__", move |_, arg| {
@@ -326,13 +328,12 @@ fn build_webview<'a>(
326328
};
327329
application.run_setup(&mut w, source.to_string()).await;
328330
if source == "window-1" {
329-
crate::plugin::ready(&mut w).await;
331+
crate::plugin::ready(W::plugin_store(), &mut w).await;
330332
}
331333
} else if arg == r#"{"cmd":"closeSplashscreen"}"# {
332334
w.dispatch(move |w| {
333335
w.eval(&format!(r#"window.location.href = "{}""#, content_url));
334-
})
335-
.unwrap();
336+
});
336337
} else {
337338
let mut endpoint_handle = crate::endpoints::handle(&mut w, &arg)
338339
.await
@@ -354,7 +355,7 @@ fn build_webview<'a>(
354355
}
355356
if let Err(ref app_handle_error) = endpoint_handle {
356357
if app_handle_error.contains("unknown variant") {
357-
let error = match crate::plugin::extend_api(&mut w, &arg).await {
358+
let error = match crate::plugin::extend_api(W::plugin_store(), &mut w, &arg).await {
358359
Ok(handled) => {
359360
if handled {
360361
String::from("")

tauri/src/endpoints.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ mod http;
1616
#[cfg(notification)]
1717
mod notification;
1818

19-
use webview_official::WebviewMut;
19+
use crate::Webview;
2020

2121
#[allow(unused_variables)]
22-
pub(crate) async fn handle(webview: &mut WebviewMut, arg: &str) -> crate::Result<()> {
22+
pub(crate) async fn handle<W: Webview + 'static>(webview: &mut W, arg: &str) -> crate::Result<()> {
2323
use cmd::Cmd::*;
2424
match serde_json::from_str(arg) {
2525
Err(e) => Err(e.into()),
@@ -154,7 +154,7 @@ pub(crate) async fn handle(webview: &mut WebviewMut, arg: &str) -> crate::Result
154154
#[cfg(set_title)]
155155
webview.dispatch(move |w| {
156156
w.set_title(&title);
157-
})?;
157+
});
158158
#[cfg(not(set_title))]
159159
throw_allowlist_error(webview, "title");
160160
}
@@ -192,7 +192,7 @@ pub(crate) async fn handle(webview: &mut WebviewMut, arg: &str) -> crate::Result
192192
let js_string = event::listen_fn(event, handler, once)?;
193193
webview.dispatch(move |w| {
194194
w.eval(&js_string);
195-
})?;
195+
});
196196
}
197197
#[cfg(not(event))]
198198
throw_allowlist_error(webview, "event");
@@ -323,15 +323,15 @@ pub(crate) async fn handle(webview: &mut WebviewMut, arg: &str) -> crate::Result
323323
}
324324

325325
#[allow(dead_code)]
326-
fn api_error(webview: &mut WebviewMut, error_fn: String, message: &str) {
326+
fn api_error<W: Webview>(webview: &mut W, error_fn: String, message: &str) {
327327
let reject_code = tauri_api::rpc::format_callback(error_fn, message);
328328
let _ = webview.dispatch(move |w| {
329329
w.eval(&reject_code);
330330
});
331331
}
332332

333333
#[allow(dead_code)]
334-
fn allowlist_error(webview: &mut WebviewMut, error_fn: String, allowlist_key: &str) {
334+
fn allowlist_error<W: Webview>(webview: &mut W, error_fn: String, allowlist_key: &str) {
335335
api_error(
336336
webview,
337337
error_fn,
@@ -343,7 +343,7 @@ fn allowlist_error(webview: &mut WebviewMut, error_fn: String, allowlist_key: &s
343343
}
344344

345345
#[allow(dead_code)]
346-
fn throw_allowlist_error(webview: &mut WebviewMut, allowlist_key: &str) {
346+
fn throw_allowlist_error<W: Webview>(webview: &mut W, allowlist_key: &str) {
347347
let reject_code = format!(
348348
r#"throw new Error("'{}' not on the allowlist")"#,
349349
allowlist_key

tauri/src/endpoints/asset.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
use crate::Webview;
12
use std::path::PathBuf;
2-
use webview_official::WebviewMut;
33

44
#[allow(clippy::option_env_unwrap)]
5-
pub async fn load(
6-
webview: &mut WebviewMut,
5+
pub async fn load<W: Webview + 'static>(
6+
webview: &mut W,
77
asset: String,
88
asset_type: String,
99
callback: String,
@@ -90,7 +90,7 @@ pub async fn load(
9090
} else {
9191
webview_ref.eval(asset_str);
9292
}
93-
})?;
93+
});
9494
Ok("Asset loaded successfully".to_string())
9595
}
9696
},

0 commit comments

Comments
 (0)