From 093856a2a53a6fc1aaa759e048c7e1fe31bb09fa Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Mon, 6 Oct 2025 15:41:24 -0300 Subject: [PATCH 01/13] feat(android): add flag to opt out of automatic back navigation (#1622) needed by https://github.com/tauri-apps/tauri/pull/14133 see https://github.com/tauri-apps/tauri/pull/14133#issuecomment-3361224695 --- .changes/android-go-back-opt-out.md | 5 +++++ src/android/kotlin/WryActivity.kt | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changes/android-go-back-opt-out.md diff --git a/.changes/android-go-back-opt-out.md b/.changes/android-go-back-opt-out.md new file mode 100644 index 000000000..9f8fce64a --- /dev/null +++ b/.changes/android-go-back-opt-out.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Add flag to opt out of automatic back navigation handling on Android via `WryActivity#handleBackNavigation`. diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index 58b355d85..44e5f27f0 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -14,6 +14,7 @@ import androidx.appcompat.app.AppCompatActivity abstract class WryActivity : AppCompatActivity() { private lateinit var mWebView: RustWebView + open val handleBackNavigation: Boolean = true open fun onWebViewCreate(webView: WebView) { } @@ -102,7 +103,7 @@ abstract class WryActivity : AppCompatActivity() { } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { - if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { + if (handleBackNavigation && keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { mWebView.goBack() return true } From 7dbc91879920cbc33f460ad0b4b22fc9b0a66601 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:43:16 -0300 Subject: [PATCH 02/13] apply version updates (#1611) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changes/android-go-back-opt-out.md | 5 ----- .changes/remove-webkitgtk-request-workaround.md | 8 -------- CHANGELOG.md | 8 ++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 5 files changed, 10 insertions(+), 15 deletions(-) delete mode 100644 .changes/android-go-back-opt-out.md delete mode 100644 .changes/remove-webkitgtk-request-workaround.md diff --git a/.changes/android-go-back-opt-out.md b/.changes/android-go-back-opt-out.md deleted file mode 100644 index 9f8fce64a..000000000 --- a/.changes/android-go-back-opt-out.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"wry": patch ---- - -Add flag to opt out of automatic back navigation handling on Android via `WryActivity#handleBackNavigation`. diff --git a/.changes/remove-webkitgtk-request-workaround.md b/.changes/remove-webkitgtk-request-workaround.md deleted file mode 100644 index ac32d3375..000000000 --- a/.changes/remove-webkitgtk-request-workaround.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -wry: patch ---- - -On Linux, removed a workaround which forced inital requests for multiple webviews to be handled sequentially. -The workaround was intended to fix a concurrency bug with loading multiple URIs at the same time on WebKitGTK. -But it prevented parallelization and could cause a deadlock in certain situations. -It is no longer needed with newer WebKitGTK versions. diff --git a/CHANGELOG.md b/CHANGELOG.md index d36485e9e..59db06845 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## \[0.53.4] + +- [`093856a`](https://github.com/tauri-apps/wry/commit/093856a2a53a6fc1aaa759e048c7e1fe31bb09fa) ([#1622](https://github.com/tauri-apps/wry/pull/1622) by [@lucasfernog](https://github.com/tauri-apps/wry/../../lucasfernog)) Add flag to opt out of automatic back navigation handling on Android via `WryActivity#handleBackNavigation`. +- [`0f51d67`](https://github.com/tauri-apps/wry/commit/0f51d67485d84fd9c72391379a67567eea3cbbfe) ([#1605](https://github.com/tauri-apps/wry/pull/1605) by [@dgerhardt](https://github.com/tauri-apps/wry/../../dgerhardt)) On Linux, removed a workaround which forced inital requests for multiple webviews to be handled sequentially. + The workaround was intended to fix a concurrency bug with loading multiple URIs at the same time on WebKitGTK. + But it prevented parallelization and could cause a deadlock in certain situations. + It is no longer needed with newer WebKitGTK versions. + ## \[0.53.3] - [`6aa5854`](https://github.com/tauri-apps/wry/commit/6aa5854b0371a4828638cd722e18d9b1ab235a8b) ([#1609](https://github.com/tauri-apps/wry/pull/1609) by [@lucasfernog](https://github.com/tauri-apps/wry/../../lucasfernog)) Enhance error handling of the `webview_version` function on macOS. diff --git a/Cargo.lock b/Cargo.lock index 2a8661377..ec5edb8f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4128,7 +4128,7 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wry" -version = "0.53.3" +version = "0.53.4" dependencies = [ "base64", "block2 0.6.0", diff --git a/Cargo.toml b/Cargo.toml index 9cef321d7..6fd7992b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ workspace = {} [package] name = "wry" -version = "0.53.3" +version = "0.53.4" authors = ["Tauri Programme within The Commons Conservancy"] edition = "2021" license = "Apache-2.0 OR MIT" From 9604b0e9fa8a7ff046344a2df2f65b37cb7b46b4 Mon Sep 17 00:00:00 2001 From: Fabian-Lars Date: Wed, 15 Oct 2025 11:03:44 +0200 Subject: [PATCH 03/13] chore: remove rustc/rustdoc args for docsrs cfg to fix docs.rs builds (#1626) --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6fd7992b6..79bd917b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,6 @@ targets = [ "x86_64-pc-windows-msvc", "x86_64-apple-darwin", ] -rustc-args = ["--cfg", "docsrs"] -rustdoc-args = ["--cfg", "docsrs"] [features] default = ["drag-drop", "protocol", "os-webview", "x11"] From 84b0ec2e35236e0b43150e37b55c7b6d2e5cf7e9 Mon Sep 17 00:00:00 2001 From: Jeff Tsang <36611384+JeffTsang@users.noreply.github.com> Date: Wed, 15 Oct 2025 17:04:40 +0800 Subject: [PATCH 04/13] feat(ios/macos): Add handler for web content process termination (#1624) * Add handler for web content process termination * Move handler to platform specific attributes * chore: code format --------- Co-authored-by: Jason Tsai --- .changes/web-content-process-termination.md | 5 +++++ src/lib.rs | 11 +++++++++++ .../class/wry_navigation_delegate.rs | 19 +++++++++++++++++++ src/wkwebview/mod.rs | 1 + src/wkwebview/navigation.rs | 11 +++++++++++ 5 files changed, 47 insertions(+) create mode 100644 .changes/web-content-process-termination.md diff --git a/.changes/web-content-process-termination.md b/.changes/web-content-process-termination.md new file mode 100644 index 000000000..4e298a07a --- /dev/null +++ b/.changes/web-content-process-termination.md @@ -0,0 +1,5 @@ +--- +"wry": minor +--- + +Add handler for web content process termination. diff --git a/src/lib.rs b/src/lib.rs index 77a54ccd8..2b2706ec7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1462,6 +1462,7 @@ pub(crate) struct PlatformSpecificWebViewAttributes { data_store_identifier: Option<[u8; 16]>, traffic_light_inset: Option, allow_link_preview: bool, + on_web_content_process_terminate_handler: Option>, #[cfg(target_os = "ios")] input_accessory_view_builder: Option>, #[cfg(target_os = "ios")] @@ -1478,6 +1479,7 @@ impl Default for PlatformSpecificWebViewAttributes { traffic_light_inset: None, // platform default for this is true allow_link_preview: true, + on_web_content_process_terminate_handler: None, #[cfg(target_os = "ios")] input_accessory_view_builder: None, #[cfg(target_os = "ios")] @@ -1509,6 +1511,8 @@ pub trait WebViewBuilderExtDarwin { /// /// See https://developer.apple.com/documentation/webkit/wkwebview/allowslinkpreview fn with_allow_link_preview(self, allow_link_preview: bool) -> Self; + /// Set a handler closure to respond to web content process termination. Available on macOS and iOS only. + fn with_on_web_content_process_terminate_handler(self, handler: impl Fn() + 'static) -> Self; } #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -1527,6 +1531,13 @@ impl WebViewBuilderExtDarwin for WebViewBuilder<'_> { self.platform_specific.allow_link_preview = allow_link_preview; self } + + fn with_on_web_content_process_terminate_handler(mut self, handler: impl Fn() + 'static) -> Self { + self + .platform_specific + .on_web_content_process_terminate_handler = Some(Box::new(handler)); + self + } } #[cfg(target_os = "macos")] diff --git a/src/wkwebview/class/wry_navigation_delegate.rs b/src/wkwebview/class/wry_navigation_delegate.rs index 5919949b6..3325fafc8 100644 --- a/src/wkwebview/class/wry_navigation_delegate.rs +++ b/src/wkwebview/class/wry_navigation_delegate.rs @@ -22,6 +22,7 @@ use crate::{ download::{navigation_download_action, navigation_download_response}, navigation::{ did_commit_navigation, did_finish_navigation, navigation_policy, navigation_policy_response, + web_content_process_did_terminate, }, }, PageLoadEvent, WryWebView, @@ -35,6 +36,7 @@ pub struct WryNavigationDelegateIvars { pub navigation_policy_function: Box bool>, pub download_delegate: Option>, pub on_page_load_handler: Option>, + pub on_web_content_process_terminate_handler: Option>, } define_class!( @@ -96,6 +98,11 @@ define_class!( ) { navigation_download_response(self, webview, response, download); } + + #[unsafe(method(webViewWebContentProcessDidTerminate:))] + fn web_content_process_did_terminate(&self, webview: &WKWebView) { + web_content_process_did_terminate(self, webview); + } } ); @@ -108,6 +115,7 @@ impl WryNavigationDelegate { navigation_handler: Option bool>>, download_delegate: Option>, on_page_load_handler: Option>, + on_web_content_process_terminate_handler: Option>, mtm: MainThreadMarker, ) -> Retained { let navigation_policy_function = Box::new(move |url: String| -> bool { @@ -125,6 +133,16 @@ impl WryNavigationDelegate { None }; + let on_web_content_process_terminate_handler = + if let Some(handler) = on_web_content_process_terminate_handler { + let custom_handler = Box::new(move || { + handler(); + }) as Box; + Some(custom_handler) + } else { + None + }; + let delegate = mtm .alloc::() .set_ivars(WryNavigationDelegateIvars { @@ -133,6 +151,7 @@ impl WryNavigationDelegate { has_download_handler, download_delegate, on_page_load_handler, + on_web_content_process_terminate_handler, }); unsafe { msg_send![super(delegate), init] } diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 0bbf6711a..7ca2e14a0 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -542,6 +542,7 @@ impl InnerWebView { attributes.navigation_handler, download_delegate.clone(), attributes.on_page_load_handler, + pl_attrs.on_web_content_process_terminate_handler, mtm, ); diff --git a/src/wkwebview/navigation.rs b/src/wkwebview/navigation.rs index 358353697..9dfeebb1a 100644 --- a/src/wkwebview/navigation.rs +++ b/src/wkwebview/navigation.rs @@ -102,3 +102,14 @@ pub(crate) fn navigation_policy_response( (*handler).call((WKNavigationResponsePolicy::Allow,)); } } + +pub(crate) fn web_content_process_did_terminate( + this: &WryNavigationDelegate, + _webview: &WKWebView, +) { + if let Some(on_web_content_process_terminate) = + &this.ivars().on_web_content_process_terminate_handler + { + on_web_content_process_terminate(); + } +} From 37b81221e0b96f4c0d6a8c2d8c58e96c5d949189 Mon Sep 17 00:00:00 2001 From: Fabian-Lars Date: Wed, 22 Oct 2025 11:37:27 +0200 Subject: [PATCH 05/13] chore: manually trigger release for 0.35.5 to fix docsrs (#1628) --- CHANGELOG.md | 4 ++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59db06845..11ed2c6c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## \[0.53.5] + +- [#1622](https://github.com/tauri-apps/wry/pull/1626) Fixed an issue that caused docs.rs builds to fail. No user facing changes. + ## \[0.53.4] - [`093856a`](https://github.com/tauri-apps/wry/commit/093856a2a53a6fc1aaa759e048c7e1fe31bb09fa) ([#1622](https://github.com/tauri-apps/wry/pull/1622) by [@lucasfernog](https://github.com/tauri-apps/wry/../../lucasfernog)) Add flag to opt out of automatic back navigation handling on Android via `WryActivity#handleBackNavigation`. diff --git a/Cargo.lock b/Cargo.lock index ec5edb8f9..c250fb04b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4128,7 +4128,7 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wry" -version = "0.53.4" +version = "0.53.5" dependencies = [ "base64", "block2 0.6.0", diff --git a/Cargo.toml b/Cargo.toml index 79bd917b6..5b6cd126c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ workspace = {} [package] name = "wry" -version = "0.53.4" +version = "0.53.5" authors = ["Tauri Programme within The Commons Conservancy"] edition = "2021" license = "Apache-2.0 OR MIT" From 2bfe45f48a166f4c172a460de23f925ec9e534b1 Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 22 Oct 2025 11:39:51 +0200 Subject: [PATCH 06/13] temporarily remove changefiles --- .changes/web-content-process-termination.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changes/web-content-process-termination.md diff --git a/.changes/web-content-process-termination.md b/.changes/web-content-process-termination.md deleted file mode 100644 index 4e298a07a..000000000 --- a/.changes/web-content-process-termination.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"wry": minor ---- - -Add handler for web content process termination. From 27ba73f07720b80a21b6b876f1229cad8871aa33 Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 22 Oct 2025 11:40:11 +0200 Subject: [PATCH 07/13] Revert "temporarily remove changefiles" This reverts commit 2bfe45f48a166f4c172a460de23f925ec9e534b1. --- .changes/web-content-process-termination.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/web-content-process-termination.md diff --git a/.changes/web-content-process-termination.md b/.changes/web-content-process-termination.md new file mode 100644 index 000000000..4e298a07a --- /dev/null +++ b/.changes/web-content-process-termination.md @@ -0,0 +1,5 @@ +--- +"wry": minor +--- + +Add handler for web content process termination. From a0403b9e2f1ff9d73be7dce1184f058afcaa1d82 Mon Sep 17 00:00:00 2001 From: lon <114724657+longregen@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:47:18 +0100 Subject: [PATCH 08/13] docs: simpler dependencies with Nix on README (#1629) The previous `shell.nix` version is quite opinionated. Users of `nix` would be expected to know how to build their own `mkShell`, based on this simple `nix-shell` command. --- README.md | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/README.md b/README.md index 4b80c2be6..a0284e7e2 100644 --- a/README.md +++ b/README.md @@ -189,24 +189,8 @@ sudo dnf install gtk3-devel webkit2gtk4.1-devel ###### Nix & NixOS -```nix -# shell.nix - -let - # Unstable Channel | Rolling Release - pkgs = import (fetchTarball("channel:nixpkgs-unstable")) { }; - packages = with pkgs; [ - pkg-config - webkitgtk_4_1 - ]; - in - pkgs.mkShell { - buildInputs = packages; - } -``` - ```sh -nix-shell shell.nix +nix-shell -p pkg-config webkitgtk_4_1 ``` ###### GUIX From 5fdd1a9840e24ce77ea4a57ce3746c3dbee28c9c Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Mon, 10 Nov 2025 07:30:59 -0300 Subject: [PATCH 09/13] refactor(android): use OnBackPressedCallback (#1625) * refactor(android): use OnBackPressedCallback see https://developer.android.com/reference/android/app/Activity#onBackPressed() * fix * fmt --- .changes/OnBackPressedCallback.md | 5 +++++ src/android/kotlin/WryActivity.kt | 25 +++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 .changes/OnBackPressedCallback.md diff --git a/.changes/OnBackPressedCallback.md b/.changes/OnBackPressedCallback.md new file mode 100644 index 000000000..4b396213c --- /dev/null +++ b/.changes/OnBackPressedCallback.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Use OnBackPressedCallback instead of the deprecated onKeyDown for back navigation on Android. diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index 44e5f27f0..73291e44f 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -10,6 +10,7 @@ import android.os.Build import android.os.Bundle import android.webkit.WebView import android.view.KeyEvent +import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity abstract class WryActivity : AppCompatActivity() { @@ -20,6 +21,22 @@ abstract class WryActivity : AppCompatActivity() { fun setWebView(webView: RustWebView) { mWebView = webView + + if (handleBackNavigation) { + val callback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (this@WryActivity.mWebView.canGoBack()) { + this@WryActivity.mWebView.goBack() + } else { + this.isEnabled = false + this@WryActivity.onBackPressed() + this.isEnabled = true + } + } + } + onBackPressedDispatcher.addCallback(this, callback) + } + onWebViewCreate(webView) } @@ -102,14 +119,6 @@ abstract class WryActivity : AppCompatActivity() { memory() } - override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { - if (handleBackNavigation && keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { - mWebView.goBack() - return true - } - return super.onKeyDown(keyCode, event) - } - fun getAppClass(name: String): Class<*> { return Class.forName(name) } From a32d8359bbe1c8441f62c62d9839959c90073002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Vennberg?= Date: Mon, 29 Sep 2025 12:59:44 +0200 Subject: [PATCH 10/13] update patch to work on newest wry --- examples/simple.rs | 19 ++++++++- src/lib.rs | 35 ++++++++++++++++ .../class/wry_web_view_ui_delegate.rs | 26 +++++++++++- src/wkwebview/display_capture.rs | 41 +++++++++++++++++++ src/wkwebview/mod.rs | 17 ++++++-- 5 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 src/wkwebview/display_capture.rs diff --git a/examples/simple.rs b/examples/simple.rs index 6b3657338..832eb9fae 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -14,7 +14,7 @@ fn main() -> wry::Result<()> { let window = WindowBuilder::new().build(&event_loop).unwrap(); let builder = WebViewBuilder::new() - .with_url("http://tauri.app") + .with_url("https://webrtc.github.io/samples/src/content/getusermedia/getdisplaymedia/") .with_new_window_req_handler(|url, features| { println!("new window req: {url} {features:?}"); wry::NewWindowResponse::Allow @@ -39,11 +39,18 @@ fn main() -> wry::Result<()> { #[cfg(any( target_os = "windows", - target_os = "macos", target_os = "ios", target_os = "android" ))] let _webview = builder.build(&window)?; + #[cfg(target_os = "macos")] + let _webview = { + use wry::WebViewBuilderExtMacos; + builder.with_display_capture_decision_handler(|_capture_type| { + wry::WKDisplayCapturePermissionDecision::ScreenPrompt + }).build(&window)? + }; + #[cfg(not(any( target_os = "windows", target_os = "macos", @@ -57,6 +64,14 @@ fn main() -> wry::Result<()> { builder.build_gtk(vbox)? }; + #[cfg(target_os = "macos")] + { + use wry::WebViewExtMacOS; + _webview.set_display_capture_decision_handler(|_capture_type| { + wry::WKDisplayCapturePermissionDecision::ScreenPrompt + }); + } + event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/src/lib.rs b/src/lib.rs index 2b2706ec7..cb831f806 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -379,6 +379,8 @@ use webkitgtk::*; use objc2::rc::Retained; #[cfg(target_os = "macos")] use objc2_app_kit::NSWindow; +#[cfg(target_os = "macos")] +use objc2_web_kit::WKMediaCaptureType; #[cfg(any(target_os = "macos", target_os = "ios"))] use objc2_web_kit::WKUserContentController; #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -387,6 +389,8 @@ pub(crate) mod wkwebview; use wkwebview::*; #[cfg(any(target_os = "macos", target_os = "ios"))] pub use wkwebview::{PrintMargin, PrintOptions, WryWebView}; +#[cfg(target_os = "macos")] +pub use wkwebview::WKDisplayCapturePermissionDecision; #[cfg(target_os = "windows")] pub(crate) mod webview2; @@ -1469,6 +1473,12 @@ pub(crate) struct PlatformSpecificWebViewAttributes { limit_navigations_to_app_bound_domains: bool, #[cfg(target_os = "macos")] webview_configuration: Option>, + #[cfg(target_os = "macos")] + /// A closure that make the permission decision for display capture (e.g. getDisplayMedia()) requests. + /// + /// Only available on macOS 13+. + pub display_capture_decision_handler: + Option WKDisplayCapturePermissionDecision>>, } #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -1486,6 +1496,8 @@ impl Default for PlatformSpecificWebViewAttributes { limit_navigations_to_app_bound_domains: false, #[cfg(target_os = "macos")] webview_configuration: None, + #[cfg(target_os = "macos")] + display_capture_decision_handler: None, } } } @@ -1547,6 +1559,10 @@ pub trait WebViewBuilderExtMacos { self, configuration: Retained, ) -> Self; + + fn with_display_capture_decision_handler(self, handler: F) -> Self + where + F: Fn(WKMediaCaptureType) -> WKDisplayCapturePermissionDecision + 'static; } #[cfg(target_os = "macos")] @@ -1561,6 +1577,14 @@ impl WebViewBuilderExtMacos for WebViewBuilder<'_> { .replace(configuration); self } + + fn with_display_capture_decision_handler(mut self, handler: F) -> Self + where + F: Fn(WKMediaCaptureType) -> WKDisplayCapturePermissionDecision + 'static, + { + self.platform_specific.display_capture_decision_handler = Some(Box::new(handler)); + self + } } #[cfg(target_os = "ios")] @@ -2373,6 +2397,10 @@ pub trait WebViewExtMacOS { /// Warning: Do not use this if your chosen window library does not support traffic light insets. /// Warning: Only use this in **decorated** windows with a **hidden titlebar**! fn set_traffic_light_inset>(&self, position: P) -> Result<()>; + /// Set display capture decision handler to decide if incoming display capture request is allowed and its target. + fn set_display_capture_decision_handler(&self, handler: F) + where + F: Fn(WKMediaCaptureType) -> WKDisplayCapturePermissionDecision + 'static; } #[cfg(target_os = "macos")] @@ -2400,6 +2428,13 @@ impl WebViewExtMacOS for WebView { fn set_traffic_light_inset>(&self, position: P) -> Result<()> { self.webview.set_traffic_light_inset(position.into()) } + + fn set_display_capture_decision_handler(&self, handler: F) + where + F: Fn(WKMediaCaptureType) -> WKDisplayCapturePermissionDecision + 'static, + { + self.webview.set_display_capture_decision_handler(handler); + } } /// Additional methods on `WebView` that are specific to iOS. diff --git a/src/wkwebview/class/wry_web_view_ui_delegate.rs b/src/wkwebview/class/wry_web_view_ui_delegate.rs index 223fcadcc..76fa8bec6 100644 --- a/src/wkwebview/class/wry_web_view_ui_delegate.rs +++ b/src/wkwebview/class/wry_web_view_ui_delegate.rs @@ -21,7 +21,7 @@ use objc2_web_kit::{ WKFrameInfo, WKMediaCaptureType, WKPermissionDecision, WKSecurityOrigin, WKUIDelegate, }; -use crate::{NewWindowFeatures, NewWindowResponse, WryWebView}; +use crate::{NewWindowFeatures, NewWindowResponse, WKDisplayCapturePermissionDecision, WryWebView}; #[cfg(target_os = "macos")] struct NewWindow { @@ -86,6 +86,8 @@ pub struct WryWebViewUIDelegateIvars { Option NewWindowResponse + Send + Sync>>, #[cfg(target_os = "macos")] new_windows: Rc>>, + #[cfg(target_os = "macos")] + pub(crate) display_capture_decision_handler: RefCell WKDisplayCapturePermissionDecision + 'static>>>, } define_class!( @@ -263,6 +265,27 @@ define_class!( } } } + + impl WryWebViewUIDelegate { + // This might fail to compile on macOS 12 and below. + #[unsafe(method(_webView:requestDisplayCapturePermissionForOrigin:initiatedByFrame:withSystemAudio:decisionHandler:))] + fn request_display_capture_permission( + &self, + _webview: &WryWebView, + _origin: &WKSecurityOrigin, + _frame: &WKFrameInfo, + capture_type: WKMediaCaptureType, + decision_handler: &Block, + ) { + let function = &self.ivars().display_capture_decision_handler; + if let Some(function) = &*function.borrow() { + let decision = (*function)(capture_type); + (*decision_handler).call((decision,)); + } else { + (*decision_handler).call((WKDisplayCapturePermissionDecision::Deny,)); + } + } + } ); impl WryWebViewUIDelegate { @@ -282,6 +305,7 @@ impl WryWebViewUIDelegate { new_window_req_handler, #[cfg(target_os = "macos")] new_windows: Rc::new(RefCell::new(vec![])), + display_capture_decision_handler: RefCell::new(None), }); unsafe { msg_send![super(delegate), init] } } diff --git a/src/wkwebview/display_capture.rs b/src/wkwebview/display_capture.rs new file mode 100644 index 000000000..78d4c768b --- /dev/null +++ b/src/wkwebview/display_capture.rs @@ -0,0 +1,41 @@ +use crate::wkwebview::class::wry_web_view_ui_delegate::WryWebViewUIDelegate; +use crate::wkwebview::util::operating_system_version; +use crate::WryWebView; +use objc2::{msg_send, DefinedClass, Encode, Encoding}; +use objc2_web_kit::WKMediaCaptureType; + +#[repr(isize)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum WKDisplayCapturePermissionDecision { + Deny = 0, + ScreenPrompt, + WindowPrompt, +} + +unsafe impl Encode for WKDisplayCapturePermissionDecision { + const ENCODING: Encoding = isize::ENCODING; +} + +impl From for WKDisplayCapturePermissionDecision { + fn from(value: isize) -> Self { + match value { + 0 => WKDisplayCapturePermissionDecision::Deny, + 1 => WKDisplayCapturePermissionDecision::ScreenPrompt, + 2 => WKDisplayCapturePermissionDecision::WindowPrompt, + _ => panic!("Invalid WKDisplayCapturePermissionDecision value"), + } + } +} + +pub(crate) fn set_decision_handler( + webview: &WryWebView, + handler: Option WKDisplayCapturePermissionDecision + 'static>>, +) { + #[cfg(target_os = "macos")] + if operating_system_version().0 >= 13 { + if let Some(handler) = handler { + let ui_delegate: &WryWebViewUIDelegate = unsafe { msg_send![webview, UIDelegate] }; + ui_delegate.ivars().display_capture_decision_handler.replace(Some(handler)); + } + } +} diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 7ca2e14a0..77c1fbe8a 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +#[cfg(target_os = "macos")] +mod display_capture; mod download; #[cfg(target_os = "macos")] mod drag_drop; @@ -68,11 +70,10 @@ use crate::wkwebview::util::operating_system_version; #[cfg(target_os = "macos")] use objc2_web_kit::WKWebView; +#[cfg(target_os = "macos")] +pub use display_capture::{WKDisplayCapturePermissionDecision}; -use objc2_web_kit::{ - WKAudiovisualMediaTypes, WKInactiveSchedulingPolicy, WKURLSchemeHandler, WKUserContentController, - WKUserScript, WKUserScriptInjectionTime, WKWebViewConfiguration, WKWebsiteDataStore, -}; +use objc2_web_kit::{WKAudiovisualMediaTypes, WKInactiveSchedulingPolicy, WKMediaCaptureType, WKURLSchemeHandler, WKUserContentController, WKUserScript, WKUserScriptInjectionTime, WKWebViewConfiguration, WKWebsiteDataStore}; use raw_window_handle::{HasWindowHandle, RawWindowHandle}; use std::{ @@ -1239,6 +1240,14 @@ r#"Object.defineProperty(window, 'ipc', { WKWebsiteDataStore::removeDataStoreForIdentifier_completionHandler(&identifier, &block, mtm); } } + + #[cfg(target_os = "macos")] + pub fn set_display_capture_decision_handler(&self, handler: F) + where + F: Fn(WKMediaCaptureType) -> WKDisplayCapturePermissionDecision + 'static, + { + display_capture::set_decision_handler(&self.webview, Some(Box::new(handler))); + } } pub fn url_from_webview(webview: &WKWebView) -> Result { From ff7d1a4098e800090e67bbc6e4c00bd3fba8efa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Vennberg?= Date: Mon, 29 Sep 2025 13:17:34 +0200 Subject: [PATCH 11/13] pass builder display capture decision handler to webview delegate --- src/wkwebview/class/wry_web_view_ui_delegate.rs | 6 +++++- src/wkwebview/display_capture.rs | 1 + src/wkwebview/mod.rs | 8 ++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/wkwebview/class/wry_web_view_ui_delegate.rs b/src/wkwebview/class/wry_web_view_ui_delegate.rs index 76fa8bec6..850f4eb81 100644 --- a/src/wkwebview/class/wry_web_view_ui_delegate.rs +++ b/src/wkwebview/class/wry_web_view_ui_delegate.rs @@ -294,6 +294,9 @@ impl WryWebViewUIDelegate { new_window_req_handler: Option< Box NewWindowResponse + Send + Sync>, >, + display_capture_decision_handler: Option< + Box WKDisplayCapturePermissionDecision> + >, ) -> Retained { #[cfg(target_os = "ios")] let _new_window_req_handler = new_window_req_handler; @@ -305,7 +308,8 @@ impl WryWebViewUIDelegate { new_window_req_handler, #[cfg(target_os = "macos")] new_windows: Rc::new(RefCell::new(vec![])), - display_capture_decision_handler: RefCell::new(None), + #[cfg(target_os = "macos")] + display_capture_decision_handler: RefCell::new(display_capture_decision_handler), }); unsafe { msg_send![super(delegate), init] } } diff --git a/src/wkwebview/display_capture.rs b/src/wkwebview/display_capture.rs index 78d4c768b..cfcfdf7ec 100644 --- a/src/wkwebview/display_capture.rs +++ b/src/wkwebview/display_capture.rs @@ -27,6 +27,7 @@ impl From for WKDisplayCapturePermissionDecision { } } +#[cfg(target_os = "macos")] pub(crate) fn set_decision_handler( webview: &WryWebView, handler: Option WKDisplayCapturePermissionDecision + 'static>>, diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 77c1fbe8a..6f708383c 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -#[cfg(target_os = "macos")] mod display_capture; mod download; #[cfg(target_os = "macos")] @@ -549,9 +548,14 @@ impl InnerWebView { let proto_navigation_policy_delegate = ProtocolObject::from_ref(&*navigation_policy_delegate); webview.setNavigationDelegate(Some(proto_navigation_policy_delegate)); + + #[cfg(target_os = "macos")] + let display_capture_decision_handler = pl_attrs.display_capture_decision_handler; + #[cfg(not(target_os = "macos"))] + let display_capture_decision_handler = None; let ui_delegate: Retained = - WryWebViewUIDelegate::new(mtm, attributes.new_window_req_handler); + WryWebViewUIDelegate::new(mtm, attributes.new_window_req_handler, display_capture_decision_handler); let proto_ui_delegate = ProtocolObject::from_ref(&*ui_delegate); webview.setUIDelegate(Some(proto_ui_delegate)); From a2745fda8eec0061947d32d50ec7d6967a138092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Vennberg?= Date: Mon, 29 Sep 2025 13:21:18 +0200 Subject: [PATCH 12/13] prompt screen sharing by default --- src/lib.rs | 2 +- src/wkwebview/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb831f806..81ceae966 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1497,7 +1497,7 @@ impl Default for PlatformSpecificWebViewAttributes { #[cfg(target_os = "macos")] webview_configuration: None, #[cfg(target_os = "macos")] - display_capture_decision_handler: None, + display_capture_decision_handler: Some(Box::new(|_| WKDisplayCapturePermissionDecision::ScreenPrompt)), } } } diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index 6f708383c..3843addbc 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -64,8 +64,6 @@ use once_cell::sync::Lazy; #[cfg(target_os = "ios")] use crate::wkwebview::ios::WKWebView::WKWebView; -#[cfg(target_os = "ios")] -use crate::wkwebview::util::operating_system_version; #[cfg(target_os = "macos")] use objc2_web_kit::WKWebView; @@ -104,6 +102,7 @@ use crate::{ use http::Request; use crate::util::Counter; +use crate::wkwebview::util::operating_system_version; static COUNTER: Counter = Counter::new(); @@ -550,7 +549,8 @@ impl InnerWebView { webview.setNavigationDelegate(Some(proto_navigation_policy_delegate)); #[cfg(target_os = "macos")] - let display_capture_decision_handler = pl_attrs.display_capture_decision_handler; + let display_capture_decision_handler = pl_attrs.display_capture_decision_handler + .filter(|_| operating_system_version().0 >= 13); #[cfg(not(target_os = "macos"))] let display_capture_decision_handler = None; From 3bd340b60192d57b065a7e5a16e2eb242a4a6108 Mon Sep 17 00:00:00 2001 From: Kaidan Grantham Date: Fri, 28 Nov 2025 19:29:18 +1000 Subject: [PATCH 13/13] Fix clippy lifetime warning in InnerWebView id function --- src/webview2/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webview2/mod.rs b/src/webview2/mod.rs index a2f5d5b99..d24f813ca 100644 --- a/src/webview2/mod.rs +++ b/src/webview2/mod.rs @@ -1351,7 +1351,7 @@ impl InnerWebView { /// Public APIs impl InnerWebView { - pub fn id(&self) -> crate::WebViewId { + pub fn id(&self) -> crate::WebViewId<'_> { &self.id }