diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 61799d039..d82ff0a2f 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -4781,6 +4781,30 @@ You may have it installed on another user account, but it is not available for t webview_builder.with_document_title_changed_handler(document_title_changed_handler) } + if let Some(permission_request_handler) = pending.permission_request_handler { + webview_builder = webview_builder.with_permission_handler(move |kind| { + let kind = match kind { + wry::PermissionKind::Microphone => tauri_runtime::webview::PermissionKind::Microphone, + wry::PermissionKind::Camera => tauri_runtime::webview::PermissionKind::Camera, + wry::PermissionKind::Geolocation => tauri_runtime::webview::PermissionKind::Geolocation, + wry::PermissionKind::Notifications => tauri_runtime::webview::PermissionKind::Notifications, + wry::PermissionKind::ClipboardRead => tauri_runtime::webview::PermissionKind::ClipboardRead, + wry::PermissionKind::DisplayCapture => { + tauri_runtime::webview::PermissionKind::DisplayCapture + } + wry::PermissionKind::Other => tauri_runtime::webview::PermissionKind::Other, + }; + + let response = permission_request_handler(kind); + + match response { + tauri_runtime::webview::PermissionResponse::Allow => wry::PermissionResponse::Allow, + tauri_runtime::webview::PermissionResponse::Deny => wry::PermissionResponse::Deny, + tauri_runtime::webview::PermissionResponse::Default => wry::PermissionResponse::Default, + } + }); + } + let webview_bounds = if let Some(bounds) = webview_attributes.bounds { let bounds: RectWrapper = bounds.into(); let bounds = bounds.0; diff --git a/crates/tauri-runtime/src/webview.rs b/crates/tauri-runtime/src/webview.rs index 80f7edf0e..db5a358fe 100644 --- a/crates/tauri-runtime/src/webview.rs +++ b/crates/tauri-runtime/src/webview.rs @@ -41,6 +41,8 @@ type DocumentTitleChangedHandler = dyn Fn(String) + Send + 'static; type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync; +type PermissionRequestHandler = dyn Fn(PermissionKind) -> PermissionResponse + Send + Sync; + #[cfg(target_os = "ios")] type InputAccessoryViewBuilderFn = dyn Fn(&objc2_ui_kit::UIView) -> Option> + Send @@ -69,6 +71,36 @@ pub enum DownloadEvent<'a> { }, } +/// Permission request response. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PermissionResponse { + /// Permission allowed. + Allow, + /// Permission denied. + Deny, + /// Default behavior. + Default, +} + +/// Permission request kind. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PermissionKind { + /// Microphone access permission. + Microphone, + /// Camera access permission. + Camera, + /// Geolocation access permission. + Geolocation, + /// Notifications permission. + Notifications, + /// Clipboard read permission. + ClipboardRead, + /// Display capture permission (for getDisplayMedia). + DisplayCapture, + /// Other unrecognized permission type. + Other, +} + #[cfg(target_os = "android")] pub struct CreationContext<'a, 'b> { pub env: &'a mut jni::JNIEnv<'b>, @@ -225,6 +257,8 @@ pub struct PendingWebview> { pub on_page_load_handler: Option>, pub download_handler: Option>, + + pub permission_request_handler: Option>, } impl> PendingWebview { @@ -251,6 +285,7 @@ impl> PendingWebview { web_resource_request_handler: None, on_page_load_handler: None, download_handler: None, + permission_request_handler: None, }) } } diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index 8842382bf..4d8829066 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -18,7 +18,9 @@ pub use cookie; use http::HeaderMap; use serde::Serialize; use tauri_macros::default_runtime; -pub use tauri_runtime::webview::{NewWindowFeatures, PageLoadEvent, ScrollBarStyle}; +pub use tauri_runtime::webview::{ + NewWindowFeatures, PageLoadEvent, PermissionKind, PermissionResponse, ScrollBarStyle, +}; // Remove this re-export in v3 pub use tauri_runtime::Cookie; #[cfg(desktop)] @@ -65,6 +67,8 @@ pub(crate) type UriSchemeProtocolHandler = pub(crate) type OnPageLoad = dyn Fn(Webview, PageLoadPayload<'_>) + Send + Sync + 'static; pub(crate) type OnDocumentTitleChanged = dyn Fn(Webview, String) + Send + 'static; pub(crate) type DownloadHandler = dyn Fn(Webview, DownloadEvent<'_>) -> bool + Send + Sync; +pub(crate) type PermissionRequestHandler = + dyn Fn(Webview, PermissionKind) -> PermissionResponse + Send + Sync + 'static; #[derive(Clone, Serialize)] pub(crate) struct CreatedEvent { @@ -278,6 +282,7 @@ unstable_struct!( pub(crate) on_page_load_handler: Option>>, pub(crate) document_title_changed_handler: Option>>, pub(crate) download_handler: Option>>, + pub(crate) permission_request_handler: Option>>, } ); @@ -356,6 +361,7 @@ async fn create_window(app: tauri::AppHandle) { on_page_load_handler: None, document_title_changed_handler: None, download_handler: None, + permission_request_handler: None, } } @@ -435,6 +441,7 @@ async fn create_window(app: tauri::AppHandle) { on_page_load_handler: None, document_title_changed_handler: None, download_handler: None, + permission_request_handler: None, } } @@ -697,6 +704,17 @@ tauri::Builder::default() self } + /// Defines a closure to be executed when a permission is requested. + pub fn on_permission_request< + F: Fn(Webview, PermissionKind) -> PermissionResponse + Send + Sync + 'static, + >( + mut self, + f: F, + ) -> Self { + self.permission_request_handler.replace(Box::new(f)); + self + } + pub(crate) fn into_pending_webview>( mut self, manager: &M, @@ -776,6 +794,18 @@ tauri::Builder::default() } })); + let label_ = pending.label.clone(); + let manager_ = manager.manager_owned(); + if let Some(handler) = self.permission_request_handler { + pending.permission_request_handler = Some(Box::new(move |kind| { + if let Some(w) = manager_.get_webview(&label_) { + handler(w, kind) + } else { + PermissionResponse::Default + } + })); + } + manager .manager() .webview diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 290730067..73f961479 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -441,6 +441,20 @@ tauri::Builder::default() self } + /// Defines a closure to be executed when a permission is requested. + pub fn on_permission_request< + F: Fn(Webview, crate::webview::PermissionKind) -> crate::webview::PermissionResponse + + Send + + Sync + + 'static, + >( + mut self, + f: F, + ) -> Self { + self.webview_builder = self.webview_builder.on_permission_request(f); + self + } + /// Creates a new window. pub fn build(self) -> crate::Result> { let (window, webview) = self.window_builder.with_webview(self.webview_builder)?;