Skip to content
Open
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
35 changes: 35 additions & 0 deletions packages/desktop/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub struct Config {
pub(crate) background_color: Option<(u8, u8, u8, u8)>,
pub(crate) last_window_close_behavior: WindowCloseBehaviour,
pub(crate) custom_event_handler: Option<CustomEventHandler>,
pub(crate) disable_file_drop_handler: bool,
pub(crate) navigation_handler: Option<Box<dyn Fn(String) -> bool + 'static>>,
}

impl LaunchConfig for Config {}
Expand Down Expand Up @@ -108,6 +110,8 @@ impl Config {
background_color: None,
last_window_close_behavior: WindowCloseBehaviour::LastWindowExitsApp,
custom_event_handler: None,
disable_file_drop_handler: false,
navigation_handler: None,
}
}

Expand Down Expand Up @@ -276,6 +280,37 @@ impl Config {
}
self
}

/// Set a custom navigation handler to control which URLs the WebView is allowed to navigate to.
///
/// The handler receives the target URL as a `String` and must return `true` to allow navigation
/// or `false` to block it.
///
/// When not set, the default behavior applies: internal `dioxus://` URLs are allowed, and
/// external `http://` or `https://` URLs are opened in the system browser via
/// [`webbrowser::open`](https://docs.rs/webbrowser) and blocked in the WebView.
///
/// This is useful for applications that embed web content (e.g. via `<iframe>`) and need
/// fine-grained control over navigation, or that want to suppress the automatic
/// system-browser-open behavior.
///
/// # Example
///
/// ```rust
/// # use dioxus_desktop::Config;
/// let cfg = Config::new()
/// .with_navigation_handler(|url| {
/// // Allow dioxus internal URLs and a specific external domain
/// url.starts_with("dioxus://") || url.starts_with("https://trusted.example.com")
/// });
/// ```
pub fn with_navigation_handler(
mut self,
handler: impl Fn(String) -> bool + 'static,
) -> Self {
self.navigation_handler = Some(Box::new(handler));
self
}
}

impl Default for Config {
Expand Down
11 changes: 8 additions & 3 deletions packages/desktop/src/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ impl WebviewInstance {
webview = webview.with_browser_accelerator_keys(false);
}

let navigation_handler = cfg.navigation_handler.take();
webview = webview
.with_bounds(wry::Rect {
position: wry::dpi::Position::Logical(wry::dpi::LogicalPosition::new(0.0, 0.0)),
Expand All @@ -332,9 +333,13 @@ impl WebviewInstance {
.with_transparent(cfg.window.window.transparent)
.with_url("dioxus://index.html/")
.with_ipc_handler(ipc_handler)
.with_navigation_handler(|var| {
// We don't want to allow any navigation
// We only want to serve the index file and assets
.with_navigation_handler(move |var| {
// If the app supplied a custom handler, delegate entirely to it.
if let Some(handler) = &navigation_handler {
return handler(var);
}
// Default behaviour: allow internal dioxus URLs; open external http(s) URLs
// in the system browser and block them inside the WebView.
if var.starts_with("dioxus://") || var.starts_with("http://dioxus.") {
true
} else {
Expand Down