From 275449c2caad0376fdb9f0421f47553abfecec12 Mon Sep 17 00:00:00 2001 From: Jeff Hutchins Date: Sat, 24 Jun 2023 12:31:27 -0600 Subject: [PATCH 1/5] WIP --- core/tauri-runtime-wry/src/lib.rs | 6 + core/tauri-runtime/src/window.rs | 5 + core/tauri/scripts/init.js | 8 -- core/tauri/src/window.rs | 182 +++++++++++++++--------------- 4 files changed, 102 insertions(+), 99 deletions(-) diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 558dabcc4309..79f2285397cc 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -3027,6 +3027,7 @@ fn create_webview( menu_ids, #[cfg(target_os = "android")] on_webview_created, + on_page_load_handler, .. } = pending; let webview_id_map = context.webview_id_map.clone(); @@ -3175,6 +3176,11 @@ fn create_webview( } } + if let Some(on_page_load_handler) = on_page_load_handler { + webview_builder = + webview_builder.with_on_load_handler(move |_, url| on_page_load_handler(todo!(), url)); + } + let webview = webview_builder .with_web_context(web_context) .build() diff --git a/core/tauri-runtime/src/window.rs b/core/tauri-runtime/src/window.rs index fbb7899f9b92..773e61466aa2 100644 --- a/core/tauri-runtime/src/window.rs +++ b/core/tauri-runtime/src/window.rs @@ -25,6 +25,7 @@ type UriSchemeProtocol = dyn Fn(&HttpRequest) -> Result> + Send + Sync + 'static; type WebResourceRequestHandler = dyn Fn(&HttpRequest, &mut HttpResponse) + Send + Sync; +type PageLoadHandler = dyn Fn(&Window, Url) + Send + Sync; /// UI scaling utilities. pub mod dpi; @@ -244,6 +245,8 @@ pub struct PendingWindow> { Option) -> Result<(), jni::errors::Error> + Send>>, pub web_resource_request_handler: Option>, + + pub page_load_handler: Option>, } pub fn is_label_valid(label: &str) -> bool { @@ -286,6 +289,7 @@ impl> PendingWindow { #[cfg(target_os = "android")] on_webview_created: None, web_resource_request_handler: Default::default(), + page_load_handler: None, }) } } @@ -318,6 +322,7 @@ impl> PendingWindow { #[cfg(target_os = "android")] on_webview_created: None, web_resource_request_handler: Default::default(), + page_load_handler: None, }) } } diff --git a/core/tauri/scripts/init.js b/core/tauri/scripts/init.js index 0a242919bb88..9fbc4c08b3d6 100644 --- a/core/tauri/scripts/init.js +++ b/core/tauri/scripts/init.js @@ -18,13 +18,5 @@ __RAW_event_initialization_script__ - if (window.ipc) { - window.__TAURI_INVOKE__('__initialized', { url: window.location.href }) - } else { - window.addEventListener('DOMContentLoaded', function () { - window.__TAURI_INVOKE__('__initialized', { url: window.location.href }) - }) - } - __RAW_plugin_initialization_script__ })() diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 4b3fc28b5d68..83a4df847db9 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -320,6 +320,13 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> { )?; pending.navigation_handler = self.navigation_handler.take(); pending.web_resource_request_handler = self.web_resource_request_handler.take(); + let manager = self.manager.clone(); + pending.page_load_handler = Some(Box::new(move |window, url| { + let payload = PageLoadPayload { + url: url.to_string(), + }; + manager.run_on_page_load(window, payload); + })); let labels = self.manager.labels().into_iter().collect::>(); let pending = self @@ -1670,87 +1677,82 @@ impl Window { } } }; - match payload.cmd.as_str() { - "__initialized" => { - let payload: PageLoadPayload = serde_json::from_value(payload.inner)?; - manager.run_on_page_load(self, payload); - } - _ => { - let message = InvokeMessage::new( - self.clone(), - manager.state(), - payload.cmd.to_string(), - payload.inner, - ); - #[allow(clippy::redundant_clone)] - let resolver = InvokeResolver::new(self.clone(), payload.callback, payload.error); - - let mut invoke = Invoke { message, resolver }; - if !is_local && scope.is_none() { - invoke.resolver.reject(scope_not_found_error_message); + + let message = InvokeMessage::new( + self.clone(), + manager.state(), + payload.cmd.to_string(), + payload.inner, + ); + #[allow(clippy::redundant_clone)] + let resolver = InvokeResolver::new(self.clone(), payload.callback, payload.error); + + let mut invoke = Invoke { message, resolver }; + if !is_local && scope.is_none() { + invoke.resolver.reject(scope_not_found_error_message); + return Ok(()); + } + + if payload.cmd.starts_with("plugin:") { + if !is_local { + let command = invoke.message.command.replace("plugin:", ""); + let plugin_name = command.split('|').next().unwrap().to_string(); + if !scope + .map(|s| s.plugins().contains(&plugin_name)) + .unwrap_or(true) + { + invoke.resolver.reject(IPC_SCOPE_DOES_NOT_ALLOW); return Ok(()); } + } + let command = invoke.message.command.replace("plugin:", ""); + let mut tokens = command.split('|'); + // safe to unwrap: split always has a least one item + let plugin = tokens.next().unwrap(); + invoke.message.command = tokens + .next() + .map(|c| c.to_string()) + .unwrap_or_else(String::new); + + let command = invoke.message.command.clone(); + let resolver = invoke.resolver.clone(); + #[cfg(mobile)] + let message = invoke.message.clone(); + + #[allow(unused_mut)] + let mut handled = manager.extend_api(plugin, invoke); + + #[cfg(target_os = "ios")] + { + if !handled { + handled = true; + let plugin = plugin.to_string(); + let (callback, error) = (resolver.callback, resolver.error); + self.with_webview(move |webview| { + unsafe { + crate::ios::post_ipc_message( + webview.inner() as _, + &plugin.as_str().into(), + &heck::ToLowerCamelCase::to_lower_camel_case(message.command.as_str()) + .as_str() + .into(), + crate::ios::json_to_dictionary(&message.payload) as _, + callback.0, + error.0, + ) + }; + })?; + } + } - if payload.cmd.starts_with("plugin:") { - if !is_local { - let command = invoke.message.command.replace("plugin:", ""); - let plugin_name = command.split('|').next().unwrap().to_string(); - if !scope - .map(|s| s.plugins().contains(&plugin_name)) - .unwrap_or(true) - { - invoke.resolver.reject(IPC_SCOPE_DOES_NOT_ALLOW); - return Ok(()); - } - } - let command = invoke.message.command.replace("plugin:", ""); - let mut tokens = command.split('|'); - // safe to unwrap: split always has a least one item - let plugin = tokens.next().unwrap(); - invoke.message.command = tokens - .next() - .map(|c| c.to_string()) - .unwrap_or_else(String::new); - - let command = invoke.message.command.clone(); - let resolver = invoke.resolver.clone(); - #[cfg(mobile)] - let message = invoke.message.clone(); - - #[allow(unused_mut)] - let mut handled = manager.extend_api(plugin, invoke); - - #[cfg(target_os = "ios")] - { - if !handled { - handled = true; - let plugin = plugin.to_string(); - let (callback, error) = (resolver.callback, resolver.error); - self.with_webview(move |webview| { - unsafe { - crate::ios::post_ipc_message( - webview.inner() as _, - &plugin.as_str().into(), - &heck::ToLowerCamelCase::to_lower_camel_case(message.command.as_str()) - .as_str() - .into(), - crate::ios::json_to_dictionary(&message.payload) as _, - callback.0, - error.0, - ) - }; - })?; - } - } - - #[cfg(target_os = "android")] - { - if !handled { - handled = true; - let resolver_ = resolver.clone(); - let runtime_handle = self.app_handle.runtime_handle.clone(); - let plugin = plugin.to_string(); - self.with_webview(move |webview| { + #[cfg(target_os = "android")] + { + if !handled { + handled = true; + let resolver_ = resolver.clone(); + let runtime_handle = self.app_handle.runtime_handle.clone(); + let plugin = plugin.to_string(); + self.with_webview(move |webview| { webview.jni_handle().exec(move |env, activity, webview| { use jni::{ errors::Error as JniError, @@ -1807,21 +1809,19 @@ impl Window { } }); })?; - } - } - - if !handled { - resolver.reject(format!("Command {command} not found")); - } - } else { - let command = invoke.message.command.clone(); - let resolver = invoke.resolver.clone(); - let handled = manager.run_invoke_handler(invoke); - if !handled { - resolver.reject(format!("Command {command} not found")); - } } } + + if !handled { + resolver.reject(format!("Command {command} not found")); + } + } else { + let command = invoke.message.command.clone(); + let resolver = invoke.resolver.clone(); + let handled = manager.run_invoke_handler(invoke); + if !handled { + resolver.reject(format!("Command {command} not found")); + } } Ok(()) From ddaa8d254c436aaec300f88945caec62a0825868 Mon Sep 17 00:00:00 2001 From: Jeff Hutchins Date: Mon, 26 Jun 2023 11:37:07 -0600 Subject: [PATCH 2/5] Make it work --- core/tauri-runtime-wry/src/lib.rs | 7 ++++--- core/tauri-runtime/src/window.rs | 2 +- core/tauri/src/hooks.rs | 2 +- core/tauri/src/manager.rs | 9 +++++++++ core/tauri/src/window.rs | 7 ------- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 79f2285397cc..f86eb68dfd4a 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -3027,7 +3027,7 @@ fn create_webview( menu_ids, #[cfg(target_os = "android")] on_webview_created, - on_page_load_handler, + page_load_handler, .. } = pending; let webview_id_map = context.webview_id_map.clone(); @@ -3176,9 +3176,10 @@ fn create_webview( } } - if let Some(on_page_load_handler) = on_page_load_handler { + let label_c = label.clone(); + if let Some(on_page_load_handler) = page_load_handler { webview_builder = - webview_builder.with_on_load_handler(move |_, url| on_page_load_handler(todo!(), url)); + webview_builder.with_on_load_handler(move |_, url| on_page_load_handler(&label_c, url)); } let webview = webview_builder diff --git a/core/tauri-runtime/src/window.rs b/core/tauri-runtime/src/window.rs index 773e61466aa2..ea653bd0d4c6 100644 --- a/core/tauri-runtime/src/window.rs +++ b/core/tauri-runtime/src/window.rs @@ -25,7 +25,7 @@ type UriSchemeProtocol = dyn Fn(&HttpRequest) -> Result> + Send + Sync + 'static; type WebResourceRequestHandler = dyn Fn(&HttpRequest, &mut HttpResponse) + Send + Sync; -type PageLoadHandler = dyn Fn(&Window, Url) + Send + Sync; +type PageLoadHandler = dyn Fn(&str, Url) + Send + Sync; /// UI scaling utilities. pub mod dpi; diff --git a/core/tauri/src/hooks.rs b/core/tauri/src/hooks.rs index 4bbe77f0a9d6..56696b1584f4 100644 --- a/core/tauri/src/hooks.rs +++ b/core/tauri/src/hooks.rs @@ -46,7 +46,7 @@ pub(crate) struct IsolationJavascript<'a> { /// The payload for the [`OnPageLoad`] hook. #[derive(Debug, Clone, Deserialize)] pub struct PageLoadPayload { - url: String, + pub(crate) url: String, } impl PageLoadPayload { diff --git a/core/tauri/src/manager.rs b/core/tauri/src/manager.rs index 2db699983845..c601ceaad7d4 100644 --- a/core/tauri/src/manager.rs +++ b/core/tauri/src/manager.rs @@ -1111,6 +1111,15 @@ impl WindowManager { } } + let manager = app_handle.manager; + pending.page_load_handler = Some(Box::new(move |label, url| { + let payload = PageLoadPayload { + url: url.to_string(), + }; + let window = manager.get_window(label).expect("label should exists"); + manager.run_on_page_load(window, payload); + })); + #[cfg(feature = "isolation")] let pattern = self.pattern().clone(); let navigation_handler = pending.navigation_handler.take(); diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 83a4df847db9..52398d4fc181 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -320,13 +320,6 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> { )?; pending.navigation_handler = self.navigation_handler.take(); pending.web_resource_request_handler = self.web_resource_request_handler.take(); - let manager = self.manager.clone(); - pending.page_load_handler = Some(Box::new(move |window, url| { - let payload = PageLoadPayload { - url: url.to_string(), - }; - manager.run_on_page_load(window, payload); - })); let labels = self.manager.labels().into_iter().collect::>(); let pending = self From 86a9469c3594ac8782b30d8b6fe4c6e4e142c329 Mon Sep 17 00:00:00 2001 From: Jeff Hutchins Date: Mon, 26 Jun 2023 12:00:55 -0600 Subject: [PATCH 3/5] Add change file --- .changes/on-load-handler.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changes/on-load-handler.md diff --git a/.changes/on-load-handler.md b/.changes/on-load-handler.md new file mode 100644 index 000000000000..b1a94ce5b319 --- /dev/null +++ b/.changes/on-load-handler.md @@ -0,0 +1,7 @@ +--- +"tauri": 'patch:feat' +"tauri-runtime": 'minor:feat' +"tauri-runtime-wry": 'patch:feat' +--- + +Add `page_load_handler` to `PendingWindow` to provide improved on load experience. From 4f4b0e095191752a7c01689ad3b9e682692f54ec Mon Sep 17 00:00:00 2001 From: Jeff Hutchins Date: Thu, 29 Jun 2023 08:04:38 -0600 Subject: [PATCH 4/5] Use the loaded handler This is later triggering than the javascript injection method was, but is probably more closely aligned with what people expected. I'm not really sure. --- core/tauri-runtime-wry/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index f86eb68dfd4a..6821beb66cbf 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -3178,8 +3178,8 @@ fn create_webview( let label_c = label.clone(); if let Some(on_page_load_handler) = page_load_handler { - webview_builder = - webview_builder.with_on_load_handler(move |_, url| on_page_load_handler(&label_c, url)); + webview_builder = webview_builder + .with_on_page_loaded_handler(move |url| on_page_load_handler(&label_c, url.parse().unwrap())); } let webview = webview_builder From d69b6e842997c79e0388d58ad1addcad3b6a79bf Mon Sep 17 00:00:00 2001 From: Jeff Hutchins Date: Fri, 30 Jun 2023 08:09:49 -0600 Subject: [PATCH 5/5] Clear up unsed imports --- core/tauri/src/window.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 52398d4fc181..8231c2b80aaf 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -32,8 +32,8 @@ use crate::{ sealed::ManagerBase, sealed::RuntimeOrDispatch, utils::config::{WindowConfig, WindowEffectsConfig, WindowUrl}, - EventLoopMessage, Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager, PageLoadPayload, - Runtime, Theme, WindowEvent, + EventLoopMessage, Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager, Runtime, Theme, + WindowEvent, }; #[cfg(desktop)] use crate::{