feat(tauri) add splashscreen API (#400)

* feat(tauri) add splashscreen API

* fix(examples) quasar example building
This commit is contained in:
Lucas Fernandes Nogueira 2020-02-08 12:34:15 -03:00 committed by GitHub
parent a572fb3dc7
commit 3e1ce404f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 34 deletions

View File

@ -18,6 +18,20 @@
* and also whitelist them based upon the developer's settings. * and also whitelist them based upon the developer's settings.
*/ */
// makes the window.external.invoke API available after window.location.href changes
if (navigator.platform != "Win64" && navigator.plaform != "Win32") {
window.external = this
if (navigator.platform == "MacIntel") {
invoke = function (x) {
webkit.messageHandlers.invoke.postMessage(x);
}
} else {
invoke = function (x) {
window.webkit.messageHandlers.external.postMessage(x);
}
}
}
function s4() { function s4() {
return Math.floor((1 + Math.random()) * 0x10000) return Math.floor((1 + Math.random()) * 0x10000)
.toString(16) .toString(16)

View File

@ -13,8 +13,8 @@ use std::io::BufRead;
fn main() { fn main() {
tauri::AppBuilder::new() tauri::AppBuilder::new()
.setup(|_webview| { .setup(|webview, _| {
let handle1 = _webview.handle(); let handle1 = webview.handle();
std::thread::spawn(move || { std::thread::spawn(move || {
let resource_dir = tauri::api::platform::resource_dir().expect("failed to get resource dir"); let resource_dir = tauri::api::platform::resource_dir().expect("failed to get resource dir");
let node_package_path = resource_dir.join("resources/packaged-node.js"); let node_package_path = resource_dir.join("resources/packaged-node.js");
@ -35,7 +35,7 @@ fn main() {
}); });
}); });
let handle2 = _webview.handle(); let handle2 = webview.handle();
tauri::event::listen(String::from("hello"), move |msg| { tauri::event::listen(String::from("hello"), move |msg| {
#[derive(Serialize)] #[derive(Serialize)]
pub struct Reply { pub struct Reply {

View File

@ -6,7 +6,8 @@ mod runner;
pub struct App { pub struct App {
invoke_handler: Option<Box<dyn FnMut(&mut WebView<'_, ()>, &str)>>, invoke_handler: Option<Box<dyn FnMut(&mut WebView<'_, ()>, &str)>>,
setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>)>>, setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>, String)>>,
splashscreen_html: Option<String>,
} }
impl App { impl App {
@ -23,19 +24,24 @@ impl App {
} }
} }
pub(crate) fn run_setup(&mut self, webview: &mut WebView<'_, ()>) { pub(crate) fn run_setup(&mut self, webview: &mut WebView<'_, ()>, source: String) {
match self.setup { match self.setup {
Some(ref mut setup) => { Some(ref mut setup) => {
setup(webview); setup(webview, source);
} }
None => {} None => {}
} }
} }
pub fn splashscreen_html(&self) -> Option<&String> {
self.splashscreen_html.as_ref()
}
} }
pub struct AppBuilder { pub struct AppBuilder {
invoke_handler: Option<Box<dyn FnMut(&mut WebView<'_, ()>, &str)>>, invoke_handler: Option<Box<dyn FnMut(&mut WebView<'_, ()>, &str)>>,
setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>)>>, setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>, String)>>,
splashscreen_html: Option<String>
} }
impl AppBuilder { impl AppBuilder {
@ -43,6 +49,7 @@ impl AppBuilder {
Self { Self {
invoke_handler: None, invoke_handler: None,
setup: None, setup: None,
splashscreen_html: None,
} }
} }
@ -54,15 +61,21 @@ impl AppBuilder {
self self
} }
pub fn setup<F: FnMut(&mut WebView<'_, ()>) + 'static>(mut self, setup: F) -> Self { pub fn setup<F: FnMut(&mut WebView<'_, ()>, String) + 'static>(mut self, setup: F) -> Self {
self.setup = Some(Box::new(setup)); self.setup = Some(Box::new(setup));
self self
} }
pub fn splashscreen_html(mut self, html: &str) -> Self {
self.splashscreen_html = Some(html.to_string());
self
}
pub fn build(self) -> App { pub fn build(self) -> App {
App { App {
invoke_handler: self.invoke_handler, invoke_handler: self.invoke_handler,
setup: self.setup, setup: self.setup,
splashscreen_html: self.splashscreen_html,
} }
} }
} }

View File

@ -35,12 +35,12 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
let config = get()?; let config = get()?;
// setup the content using the config struct depending on the compile target // setup the content using the config struct depending on the compile target
let content = setup_content(config.clone())?; let main_content = setup_content(config.clone())?;
// setup the server url for the embedded-server // setup the server url for the embedded-server
#[cfg(feature = "embedded-server")] #[cfg(feature = "embedded-server")]
let server_url = { let server_url = {
if let Content::Url(ref url) = &content { if let Content::Url(ref url) = &main_content {
String::from(url) String::from(url)
} else { } else {
String::from("") String::from("")
@ -48,8 +48,16 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
}; };
// build the webview // build the webview
let mut webview = build_webview(application, config, content)?; let webview = build_webview(
webview.set_color((255, 255, 255)); application,
config,
main_content,
if application.splashscreen_html().is_some() {
Some(Content::Html(application.splashscreen_html().expect("failed to get splashscreen_html").to_string()))
} else {
None
},
)?;
// on dev-server grab a handler and execute the tauri.js API entry point. // on dev-server grab a handler and execute the tauri.js API entry point.
#[cfg(feature = "dev-server")] #[cfg(feature = "dev-server")]
@ -172,7 +180,12 @@ fn build_webview(
application: &mut App, application: &mut App,
config: Config, config: Config,
content: Content<String>, content: Content<String>,
splashscreen_content: Option<Content<String>>
) -> crate::Result<WebView<'_, ()>> { ) -> crate::Result<WebView<'_, ()>> {
let content_clone = match content {
Content::Html(ref html) => Content::Html(html.clone()),
Content::Url(ref url) => Content::Url(url.clone()),
};
let debug = cfg!(debug_assertions); let debug = cfg!(debug_assertions);
// get properties from config struct // get properties from config struct
let width = config.tauri.window.width; let width = config.tauri.window.width;
@ -180,28 +193,54 @@ fn build_webview(
let resizable = config.tauri.window.resizable; let resizable = config.tauri.window.resizable;
let title = config.tauri.window.title.into_boxed_str(); let title = config.tauri.window.title.into_boxed_str();
Ok( let has_splashscreen = splashscreen_content.is_some();
builder() let mut initialized_splashscreen = false;
.title(Box::leak(title))
.size(width, height)
.resizable(resizable)
.debug(debug)
.user_data(())
.invoke_handler(move |webview, arg| {
if arg == r#"{"cmd":"__initialized"}"# {
application.run_setup(webview);
webview.eval(JS_STRING)?;
} else if let Ok(b) = crate::endpoints::handle(webview, arg) {
if !b {
application.run_invoke_handler(webview, arg);
}
}
Ok(()) let webview = builder()
}) .title(Box::leak(title))
.content(content) .size(width, height)
.build()?, .resizable(resizable)
) .debug(debug)
.user_data(())
.invoke_handler(move |webview, arg| {
if arg == r#"{"cmd":"__initialized"}"# {
let source = if has_splashscreen && !initialized_splashscreen {
initialized_splashscreen = true;
"splashscreen"
} else {
"window-1"
};
application.run_setup(webview, source.to_string());
webview.eval(JS_STRING)?;
} else if arg == r#"{"cmd":"closeSplashscreen"}"# {
let content_href = match content_clone {
Content::Html(ref html) => html,
Content::Url(ref url) => url,
};
webview.eval(&format!("window.location.href = `{}`", content_href))?;
} else if let Ok(b) = crate::endpoints::handle(webview, arg) {
if !b {
application.run_invoke_handler(webview, arg);
}
}
Ok(())
})
.content(if splashscreen_content.is_some() {
splashscreen_content.expect("failed to get splashscreen content")
} else {
content
})
.build()?;
if has_splashscreen {
// trigger the init hook for the splashscreen since we're not injecting the tauri.js entry point
webview.handle().dispatch(|webview| {
webview.eval(r#"window.external.invoke(JSON.stringify({ cmd: "__initialized" }))"#)
}).expect("failed to initialize splashscreen");
}
Ok(webview)
} }
#[cfg(test)] #[cfg(test)]

View File

@ -36,7 +36,7 @@ use threadpool::ThreadPool;
use error_chain::error_chain; use error_chain::error_chain;
pub use app::*; pub use app::*;
use web_view::WebView; use web_view::{WebView, Handle};
pub use tauri_api as api; pub use tauri_api as api;
@ -106,6 +106,14 @@ pub fn call<T: 'static>(
); );
} }
pub fn close_splashscreen<T: 'static>(webview_handle: &Handle<T>) -> crate::Result<()> {
webview_handle.dispatch(|webview| {
// send a signal to the runner so it knows that it should redirect to the main app content
webview.eval(r#"window.external.invoke(JSON.stringify({ cmd: "closeSplashscreen" }))"#)
})?;
Ok(())
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use proptest::prelude::*; use proptest::prelude::*;