Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): use handler instead of javascript for on load, closes #7255 #7305

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changes/on-load-handler.md
Original file line number Diff line number Diff line change
@@ -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.
7 changes: 7 additions & 0 deletions core/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3027,6 +3027,7 @@ fn create_webview<T: UserEvent>(
menu_ids,
#[cfg(target_os = "android")]
on_webview_created,
page_load_handler,
..
} = pending;
let webview_id_map = context.webview_id_map.clone();
Expand Down Expand Up @@ -3175,6 +3176,12 @@ fn create_webview<T: UserEvent>(
}
}

let label_c = label.clone();
if let Some(on_page_load_handler) = page_load_handler {
webview_builder = webview_builder
.with_on_page_loaded_handler(move |url| on_page_load_handler(&label_c, url.parse().unwrap()));
}

jhutchins marked this conversation as resolved.
Show resolved Hide resolved
let webview = webview_builder
.with_web_context(web_context)
.build()
Expand Down
5 changes: 5 additions & 0 deletions core/tauri-runtime/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type UriSchemeProtocol =
dyn Fn(&HttpRequest) -> Result<HttpResponse, Box<dyn std::error::Error>> + Send + Sync + 'static;

type WebResourceRequestHandler = dyn Fn(&HttpRequest, &mut HttpResponse) + Send + Sync;
type PageLoadHandler = dyn Fn(&str, Url) + Send + Sync;

/// UI scaling utilities.
pub mod dpi;
Expand Down Expand Up @@ -244,6 +245,8 @@ pub struct PendingWindow<T: UserEvent, R: Runtime<T>> {
Option<Box<dyn Fn(CreationContext<'_>) -> Result<(), jni::errors::Error> + Send>>,

pub web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,

pub page_load_handler: Option<Box<PageLoadHandler>>,
}

pub fn is_label_valid(label: &str) -> bool {
Expand Down Expand Up @@ -286,6 +289,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
#[cfg(target_os = "android")]
on_webview_created: None,
web_resource_request_handler: Default::default(),
page_load_handler: None,
})
}
}
Expand Down Expand Up @@ -318,6 +322,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
#[cfg(target_os = "android")]
on_webview_created: None,
web_resource_request_handler: Default::default(),
page_load_handler: None,
})
}
}
Expand Down
8 changes: 0 additions & 8 deletions core/tauri/scripts/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -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__
})()
2 changes: 1 addition & 1 deletion core/tauri/src/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions core/tauri/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,15 @@ impl<R: Runtime> WindowManager<R> {
}
}

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();
Expand Down
179 changes: 86 additions & 93 deletions core/tauri/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -1670,87 +1670,82 @@ impl<R: Runtime> Window<R> {
}
}
};
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,
Expand Down Expand Up @@ -1807,21 +1802,19 @@ impl<R: Runtime> Window<R> {
}
});
})?;
}
}

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(())
Expand Down