move custom_scheme_url to runtime

This commit is contained in:
Lucas Nogueira
2025-11-06 09:07:37 -03:00
parent 8801df6b5c
commit 6b87f8f333
8 changed files with 46 additions and 29 deletions

View File

@@ -2080,6 +2080,14 @@ impl<T: UserEvent> Runtime<T> for CefRuntime<T> {
fn set_device_event_filter(&mut self, _filter: DeviceEventFilter) {}
fn custom_scheme_url(scheme: &str, https: bool) -> String {
// CEF always uses http/https format regardless of platform
format!(
"{}://{scheme}.localhost",
if https { "https" } else { "http" }
)
}
#[cfg(any(
target_os = "macos",
windows,

View File

@@ -3027,6 +3027,21 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
.set_device_event_filter(DeviceEventFilterWrapper::from(filter).0);
}
/// Returns the URL for a custom scheme.
///
/// On Windows and Android, custom schemes use `http://<scheme>.localhost` or `https://<scheme>.localhost`.
/// On other platforms, custom schemes use `<scheme>://localhost`.
fn custom_scheme_url(scheme: &str, _https: bool) -> String {
if cfg!(any(windows, target_os = "android")) {
format!(
"{}://{scheme}.localhost",
if _https { "https" } else { "http" }
)
} else {
format!("{scheme}://localhost")
}
}
#[cfg(desktop)]
fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) {
use tao::platform::run_return::EventLoopExtRunReturn;

View File

@@ -490,6 +490,9 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
/// [`tao`]: https://crates.io/crates/tao
fn set_device_event_filter(&mut self, filter: DeviceEventFilter);
/// Returns the URL for a custom scheme.
fn custom_scheme_url(scheme: &str, _https: bool) -> String;
/// Runs an iteration of the runtime event loop and returns control flow to the caller.
#[cfg(desktop)]
fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, callback: F);

View File

@@ -28,7 +28,6 @@ use crate::{
plugin::PluginStore,
resources::ResourceTable,
utils::{config::Config, PackageInfo},
webview::custom_scheme_url,
Assets, Context, DebugAppIcon, EventName, Pattern, Runtime, StateManager, Webview, Window,
};
@@ -357,7 +356,7 @@ impl<R: Runtime> AppManager<R> {
pub(crate) fn get_url(&self, https: bool) -> Cow<'_, Url> {
match self.base_path() {
Some(url) => Cow::Borrowed(url),
_ => Cow::Owned(Url::parse(&custom_scheme_url("tauri", https)).unwrap()),
_ => Cow::Owned(Url::parse(&R::custom_scheme_url("tauri", https)).unwrap()),
}
}
@@ -438,7 +437,7 @@ impl<R: Runtime> AppManager<R> {
let default_src = csp_map
.entry("default-src".into())
.or_insert_with(Default::default);
default_src.push(crate::webview::custom_scheme_url(schema, _use_https_schema));
default_src.push(R::custom_scheme_url(schema, _use_https_schema));
}
csp_header.replace(Csp::DirectiveMap(csp_map).to_string());

View File

@@ -136,9 +136,7 @@ impl<R: Runtime> WebviewManager<R> {
let ipc_init = IpcJavascript {
isolation_origin: &match &*app_manager.pattern {
#[cfg(feature = "isolation")]
crate::Pattern::Isolation { schema, .. } => {
crate::webview::custom_scheme_url(schema, use_https_scheme)
}
crate::Pattern::Isolation { schema, .. } => R::custom_scheme_url(schema, use_https_scheme),
_ => "".to_owned(),
},
}
@@ -195,7 +193,7 @@ impl<R: Runtime> WebviewManager<R> {
if let crate::Pattern::Isolation { schema, .. } = &*app_manager.pattern {
all_initialization_scripts.push(main_frame_script(
IsolationJavascript {
isolation_src: crate::webview::custom_scheme_url(schema, use_https_scheme).as_str(),
isolation_src: R::custom_scheme_url(schema, use_https_scheme).as_str(),
style: tauri_utils::pattern::isolation::IFRAME_STYLE,
}
.render_default(&Default::default())?
@@ -217,6 +215,7 @@ impl<R: Runtime> WebviewManager<R> {
let mut registered_scheme_protocols = Vec::new();
let mut custom_uri_schemes = Vec::new();
for (uri_scheme, protocol) in &*self.uri_scheme_protocols.lock().unwrap() {
registered_scheme_protocols.push(uri_scheme.clone());
let protocol = protocol.clone();
@@ -229,17 +228,17 @@ impl<R: Runtime> WebviewManager<R> {
};
(protocol.protocol)(context, request, UriSchemeResponder(responder))
});
custom_uri_schemes.push(uri_scheme.clone());
}
let window_url = Url::parse(&pending.url).unwrap();
let window_origin = if window_url.scheme() == "data" {
"null".into()
} else if (cfg!(windows) || cfg!(target_os = "android") || cfg!(feature = "cef"))
&& window_url.scheme() != "http"
&& window_url.scheme() != "https"
{
let https = if use_https_scheme { "https" } else { "http" };
format!("{https}://{}.localhost", window_url.scheme())
} else if custom_uri_schemes.contains(&window_url.scheme().to_string()) {
// when we're referencing a custom scheme, make sure it's using the actual window origin
// this will convert tauri://localhost to http://tauri.localhost (or any other scheme format) to match the runtime given URL
R::custom_scheme_url(window_url.scheme(), use_https_scheme)
} else if let Some(host) = window_url.host() {
format!(
"{}://{}{}",
@@ -556,7 +555,7 @@ impl<R: Runtime> WebviewManager<R> {
#[cfg(feature = "isolation")]
let isolation_frame_url = if let crate::Pattern::Isolation { schema, .. } = &*pattern {
Some(
Url::parse(&crate::webview::custom_scheme_url(
Url::parse(&R::custom_scheme_url(
schema,
pending.webview_attributes.use_https_scheme,
))

View File

@@ -14,7 +14,7 @@ use std::sync::Arc;
use crate::{
manager::{set_csp, webview::PROCESS_IPC_MESSAGE_FN, AppManager},
webview::{UriSchemeProtocolHandler, custom_scheme_url},
webview::UriSchemeProtocolHandler,
Runtime,
};
@@ -26,7 +26,7 @@ pub fn get<R: Runtime>(
window_origin: String,
use_https_scheme: bool,
) -> UriSchemeProtocolHandler {
let frame_src = custom_scheme_url(schema, use_https_scheme);
let frame_src = R::custom_scheme_url(schema, use_https_scheme);
let assets = assets as Arc<dyn Assets<R>>;

View File

@@ -1264,6 +1264,10 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {}
fn custom_scheme_url(scheme: &str, _https: bool) -> String {
format!("{scheme}://localhost")
}
#[cfg(any(
target_os = "macos",
windows,

View File

@@ -1703,7 +1703,7 @@ tauri::Builder::default()
// if from `tauri://` custom protocol
({
let protocol_url = Url::parse(&custom_scheme_url("tauri", uses_https)).unwrap();
let protocol_url = Url::parse(&R::custom_scheme_url("tauri", uses_https)).unwrap();
current_url.scheme() == protocol_url.scheme()
&& current_url.domain() == protocol_url.domain()
}) ||
@@ -1727,7 +1727,7 @@ tauri::Builder::default()
// so we check using the first part of the domain
#[cfg(any(windows, target_os = "android"))]
let local = {
let protocol_url = Url::parse(&custom_scheme_url("tauri", uses_https)).unwrap();
let protocol_url = Url::parse(&R::custom_scheme_url("tauri", uses_https)).unwrap();
let maybe_protocol = current_url
.domain()
.and_then(|d| d .split_once('.'))
@@ -2326,17 +2326,6 @@ impl<T: ScopeObject> ResolvedScope<T> {
}
}
pub(crate) fn custom_scheme_url(scheme: &str, https: bool) -> String {
if cfg!(any(windows, target_os = "android", feature = "cef")) {
format!(
"{}://{scheme}.localhost",
if https { "https" } else { "http" }
)
} else {
format!("{scheme}://localhost")
}
}
#[cfg(test)]
mod tests {
#[test]