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
11 changes: 11 additions & 0 deletions .changes/permission-handler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"tauri": patch
"tauri-runtime": patch
"tauri-runtime-wry": patch
---

Expand the `PermissionKind` and `PermissionResponse` enums to match the updated `wry` API.
This includes support for permission types such as `DisplayCapture`, `Midi`, `Sensors`, `MediaKeySystemAccess`, `LocalFonts`, `WindowManagement`, `PointerLock`, `AutomaticDownloads`, `FileSystemAccess`, and `Autoplay`.
Added `PermissionResponse::Prompt` to explicitly trigger system dialogs.
Added Android support for geolocation, microphone, camera, protected media, and MIDI requests via JNI.
Updated Linux DisplayCapture support for WebKitGTK versions older than 2.42.
21 changes: 10 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/tauri-runtime-wry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ edition.workspace = true
rust-version.workspace = true

[dependencies]
wry = { version = "0.55.0", default-features = false, features = [
wry = { git = "https://github.com/F0RLE/wry", rev = "88472aedf318287eddd832cc3e2217cde426f766", default-features = false, features = [
"protocol",
"os-webview",
"linux-body",
Expand Down
43 changes: 43 additions & 0 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4907,6 +4907,49 @@ 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::Midi => tauri_runtime::webview::PermissionKind::Midi,
wry::PermissionKind::Sensors => tauri_runtime::webview::PermissionKind::Sensors,
wry::PermissionKind::MediaKeySystemAccess => {
tauri_runtime::webview::PermissionKind::MediaKeySystemAccess
}
wry::PermissionKind::LocalFonts => tauri_runtime::webview::PermissionKind::LocalFonts,
wry::PermissionKind::WindowManagement => {
tauri_runtime::webview::PermissionKind::WindowManagement
}
wry::PermissionKind::PointerLock => tauri_runtime::webview::PermissionKind::PointerLock,
wry::PermissionKind::AutomaticDownloads => {
tauri_runtime::webview::PermissionKind::AutomaticDownloads
}
wry::PermissionKind::FileSystemAccess => {
tauri_runtime::webview::PermissionKind::FileSystemAccess
}
wry::PermissionKind::Autoplay => tauri_runtime::webview::PermissionKind::Autoplay,
wry::PermissionKind::Other => tauri_runtime::webview::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,
tauri_runtime::webview::PermissionResponse::Prompt => wry::PermissionResponse::Prompt,
}
});
}

let webview_bounds = if let Some(bounds) = webview_attributes.bounds {
let bounds: RectWrapper = bounds.into();
let bounds = bounds.0;
Expand Down
99 changes: 99 additions & 0 deletions crates/tauri-runtime/src/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(any(target_os = "macos", target_os = "ios"))]
type OnWebContentProcessTerminateHandler = dyn Fn() + Send;

Expand Down Expand Up @@ -72,6 +74,100 @@ pub enum DownloadEvent<'a> {
},
}

/// Permission request response.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum PermissionResponse {
/// Permission allowed.
Allow,
/// Permission denied.
Deny,
/// Use default behavior (show system prompt).
#[default]
Default,
/// Explicitly prompt the user (system dialog).
Prompt,
}

impl std::fmt::Display for PermissionResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Allow => write!(f, "allow"),
Self::Deny => write!(f, "deny"),
Self::Default => write!(f, "default"),
Self::Prompt => write!(f, "prompt"),
}
}
}

/// Permission request kind.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
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,
/// Midi access permission.
Midi,
/// Sensors (accelerometer, gyroscope, etc.) access permission.
Sensors,
/// Media key system access permission.
MediaKeySystemAccess,
/// Local fonts access permission.
LocalFonts,
/// Window management permission.
WindowManagement,
/// Pointer lock permission.
PointerLock,
/// Automatic downloads permission (multiple downloads without user interaction).
AutomaticDownloads,
/// File system access permission (read/write via File System Access API).
///
/// ## Platform-specific
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_FILE_READ_WRITE`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
FileSystemAccess,
/// Media autoplay permission.
///
/// ## Platform-specific
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_AUTOPLAY`.
/// - **macOS / Linux / Android / iOS**: Not yet supported by platform backends.
Autoplay,
/// Other unrecognized permission type.
Other,
}

impl std::fmt::Display for PermissionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Microphone => write!(f, "microphone"),
Self::Camera => write!(f, "camera"),
Self::Geolocation => write!(f, "geolocation"),
Self::Notifications => write!(f, "notifications"),
Self::ClipboardRead => write!(f, "clipboard-read"),
Self::DisplayCapture => write!(f, "display-capture"),
Self::Midi => write!(f, "midi"),
Self::Sensors => write!(f, "sensors"),
Self::MediaKeySystemAccess => write!(f, "media-key-system-access"),
Self::LocalFonts => write!(f, "local-fonts"),
Self::WindowManagement => write!(f, "window-management"),
Self::PointerLock => write!(f, "pointer-lock"),
Self::AutomaticDownloads => write!(f, "automatic-downloads"),
Self::FileSystemAccess => write!(f, "file-system-access"),
Self::Autoplay => write!(f, "autoplay"),
Self::Other => write!(f, "other"),
}
}
}

#[cfg(target_os = "android")]
pub struct CreationContext<'a, 'b> {
pub env: &'a mut jni::JNIEnv<'b>,
Expand Down Expand Up @@ -229,6 +325,8 @@ pub struct PendingWebview<T: UserEvent, R: Runtime<T>> {

pub download_handler: Option<Arc<DownloadHandler>>,

pub permission_request_handler: Option<Box<PermissionRequestHandler>>,

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub on_web_content_process_terminate_handler: Option<Box<OnWebContentProcessTerminateHandler>>,
}
Expand Down Expand Up @@ -257,6 +355,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWebview<T, R> {
web_resource_request_handler: None,
on_page_load_handler: None,
download_handler: None,
permission_request_handler: None,
#[cfg(any(target_os = "macos", target_os = "ios"))]
on_web_content_process_terminate_handler: None,
})
Expand Down
23 changes: 23 additions & 0 deletions crates/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,9 @@ pub struct Builder<R: Runtime> {
/// Page load hook.
on_page_load: Option<Arc<OnPageLoad<R>>>,

/// Permission request hook.
on_permission_request: Option<Arc<crate::webview::PermissionRequestHandler<R>>>,

/// Web content process termination hook.
#[cfg(any(target_os = "macos", target_os = "ios"))]
on_web_content_process_terminate: Option<Arc<OnWebContentProcessTerminate<R>>>,
Expand Down Expand Up @@ -1576,6 +1579,7 @@ impl<R: Runtime> Builder<R> {
.into_string(),
channel_interceptor: None,
on_page_load: None,
on_permission_request: None,
#[cfg(any(target_os = "macos", target_os = "ios"))]
on_web_content_process_terminate: None,
plugins: PluginStore::default(),
Expand Down Expand Up @@ -1758,6 +1762,24 @@ tauri::Builder::default()
self
}

/// Defines a closure to be executed when a permission is requested.
///
/// The handler receives the [`crate::webview::PermissionKind`] and should return
/// the desired [`crate::webview::PermissionResponse`].
#[must_use]
pub fn on_permission_request<F>(mut self, on_permission_request: F) -> Self
where
F: Fn(Webview<R>, crate::webview::PermissionKind) -> crate::webview::PermissionResponse
+ Send
+ Sync
+ 'static,
{
self
.on_permission_request
.replace(Arc::new(on_permission_request));
self
}

/// Defines the web content process termination hook.
///
/// ## Platform-specific
Expand Down Expand Up @@ -2223,6 +2245,7 @@ tauri::Builder::default()
self.plugins,
self.invoke_handler,
self.on_page_load,
self.on_permission_request,
#[cfg(any(target_os = "macos", target_os = "ios"))]
self.on_web_content_process_terminate,
self.uri_scheme_protocols,
Expand Down
2 changes: 2 additions & 0 deletions crates/tauri/src/manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ impl<R: Runtime> AppManager<R> {
plugins: PluginStore<R>,
invoke_handler: Box<InvokeHandler<R>>,
on_page_load: Option<Arc<OnPageLoad<R>>>,
on_permission_request: Option<Arc<crate::webview::PermissionRequestHandler<R>>>,
#[cfg(any(target_os = "macos", target_os = "ios"))] on_web_content_process_terminate: Option<
Arc<OnWebContentProcessTerminate<R>>,
>,
Expand Down Expand Up @@ -290,6 +291,7 @@ impl<R: Runtime> AppManager<R> {
webviews: Mutex::default(),
invoke_handler,
on_page_load,
on_permission_request,
#[cfg(any(target_os = "macos", target_os = "ios"))]
on_web_content_process_terminate,
uri_scheme_protocols: Mutex::new(uri_scheme_protocols),
Expand Down
Loading