Skip to content

Commit

Permalink
fix crash when setting datastore and add methods to fetch all datasto…
Browse files Browse the repository at this point in the history
…res and to remove a datastore (#1512)

* fix: crash when using `WebViewBuilderExtDarwin.with_data_store_identifier`

* feat: macOS: add `wry::fetch_all_data_store_identifiers` and `wry::remove_data_store`

* move api to WebView, make it blocking

* try using a dedicated NSError kind

* fix ios build

* revert back to async, fix crash on error

* update docs

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
  • Loading branch information
Simon-Laux and lucasfernog authored Mar 8, 2025
1 parent 5be87b1 commit 349dfe3
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changes/WebViewExtDarwin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": patch
---

Added `WebViewExtDarwin` to expose WebView functions available to both macOS and iOS.
5 changes: 5 additions & 0 deletions .changes/datastore_id_crash_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": patch
---

fix: crash when using `WebViewBuilderExtDarwin.with_data_store_identifier`
5 changes: 5 additions & 0 deletions .changes/fetch_all_and_remove_data_store.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": patch
---

feat: macOS: add `WebViewExtDarwin::fetch_data_store_identifiers` and `WebViewExtDarwin::remove_data_store`.
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,13 @@ features = [
[target.'cfg(target_vendor = "apple")'.dependencies]
url = "2.5"
block2 = "0.6"
objc2 = { version = "0.6", features = ["exception"] }
objc2 = { version = "0.6", features = [
"exception",
# because `NSUUID::from_bytes` needs it,
# and `WebViewBuilderExtDarwin.with_data_store_identifier` crashes otherwise,
# see https://github.com/tauri-apps/tauri/issues/12843
"disable-encoding-assertions",
] }
objc2-web-kit = { version = "0.3.0", default-features = false, features = [
"std",
"objc2-core-foundation",
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,7 @@ pub enum Error {
#[error(transparent)]
#[cfg(any(target_os = "macos", target_os = "ios"))]
UrlPrase(#[from] url::ParseError),
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[error("data store is currently opened")]
DataStoreInUse,
}
40 changes: 36 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1391,14 +1391,14 @@ impl<'a> WebViewBuilder<'a> {
}
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[derive(Clone, Default)]
pub(crate) struct PlatformSpecificWebViewAttributes {
data_store_identifier: Option<[u8; 16]>,
traffic_light_inset: Option<dpi::Position>,
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub trait WebViewBuilderExtDarwin {
/// Initialize the WebView with a custom data store identifier.
/// Can be used as a replacement for data_directory not being available in WKWebView.
Expand All @@ -1415,7 +1415,7 @@ pub trait WebViewBuilderExtDarwin {
fn with_traffic_light_inset<P: Into<dpi::Position>>(self, position: P) -> Self;
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
#[cfg(any(target_os = "macos", target_os = "ios"))]
impl WebViewBuilderExtDarwin for WebViewBuilder<'_> {
fn with_data_store_identifier(self, identifier: [u8; 16]) -> Self {
self.and_then(|mut b| {
Expand Down Expand Up @@ -2080,6 +2080,38 @@ impl WebViewExtUnix for WebView {
}
}

/// Additional methods on `WebView` that are specific to macOS or iOS.
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub trait WebViewExtDarwin {
/// Prints with extra options
fn print_with_options(&self, options: &PrintOptions) -> Result<()>;
/// Fetches all Data Store Identifiers of this application
///
/// Needs to run on main thread and needs an event loop to run.
fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(cb: F) -> Result<()>;
/// Deletes a Data Store by an identifier.
///
/// You must drop any WebView instances using the data store before you call this method.
///
/// Needs to run on main thread and needs an event loop to run.
fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(uuid: &[u8; 16], cb: F);
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
impl WebViewExtDarwin for WebView {
fn print_with_options(&self, options: &PrintOptions) -> Result<()> {
self.webview.print_with_options(options)
}

fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(cb: F) -> Result<()> {
wkwebview::InnerWebView::fetch_data_store_identifiers(cb)
}

fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(uuid: &[u8; 16], cb: F) {
wkwebview::InnerWebView::remove_data_store(uuid, cb)
}
}

/// Additional methods on `WebView` that are specific to macOS.
#[cfg(target_os = "macos")]
pub trait WebViewExtMacOS {
Expand All @@ -2091,7 +2123,7 @@ pub trait WebViewExtMacOS {
fn ns_window(&self) -> Retained<NSWindow>;
/// Attaches this webview to the given NSWindow and removes it from the current one.
fn reparent(&self, window: *mut NSWindow) -> Result<()>;
// Prints with extra options
/// Prints with extra options
fn print_with_options(&self, options: &PrintOptions) -> Result<()>;
/// Move the window controls to the specified position.
/// Normally this is handled by the Window but because `WebViewBuilder::build()` overwrites the window's NSView the controls will flicker on resizing.
Expand Down
2 changes: 1 addition & 1 deletion src/wkwebview/class/wry_web_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use std::{cell::RefCell, collections::HashMap, sync::Mutex};
use std::{collections::HashMap, sync::Mutex};

#[cfg(target_os = "macos")]
use objc2::runtime::ProtocolObject;
Expand Down
58 changes: 58 additions & 0 deletions src/wkwebview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ use once_cell::sync::Lazy;
use raw_window_handle::{HasWindowHandle, RawWindowHandle};

use std::{
cell::RefCell,
collections::HashSet,
ffi::{c_void, CStr, CString},
net::Ipv4Addr,
Expand Down Expand Up @@ -995,6 +996,63 @@ r#"Object.defineProperty(window, 'ipc', {

Ok(())
}

/// Fetches all Data Store Identifiers of this application
///
/// Needs to run on main thread and needs an event loop to run.
pub fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(
cb: F,
) -> crate::Result<()> {
// make the RcBlock callback be a FnOnce
let cb = RefCell::new(Some(cb));
let block = block2::RcBlock::new(move |stores: NonNull<NSArray<NSUUID>>| {
let uuid_list = unsafe { stores.as_ref() }
.to_vec()
.iter()
.map(|uuid| uuid.as_bytes())
.collect();
if let Some(cb) = cb.take() {
cb(uuid_list);
}
});

match MainThreadMarker::new() {
Some(mtn) => unsafe {
WKWebsiteDataStore::fetchAllDataStoreIdentifiers(&block, mtn);
Ok(())
},
None => Err(Error::NotMainThread),
}
}

/// Deletes a Data Store by an identifier
///
/// Needs to run on main thread and needs an event loop to run.
pub fn remove_data_store<F: FnOnce(crate::Result<()>) + Send + 'static>(uuid: &[u8; 16], cb: F) {
let Some(mtm) = MainThreadMarker::new() else {
cb(Err(Error::NotMainThread));
return;
};
let identifier = NSUUID::from_bytes(uuid.to_owned());

// make the RcBlock callback be a FnOnce
let cb = RefCell::new(Some(cb));
let block = block2::RcBlock::new(move |error: *mut NSError| {
if error.is_null() {
if let Some(cb) = cb.take() {
cb(Ok(()));
}
} else {
if let Some(cb) = cb.take() {
cb(Err(Error::DataStoreInUse));
}
}
});

unsafe {
WKWebsiteDataStore::removeDataStoreForIdentifier_completionHandler(&identifier, &block, mtm);
}
}
}

pub fn url_from_webview(webview: &WKWebView) -> Result<String> {
Expand Down

0 comments on commit 349dfe3

Please # to comment.