Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changes/datastore_api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tauri-apps/api": minor:feat
---

add `AppHandle.fetch_data_store_identifiers` and `AppHandle.remove_data_store` (macOS and iOS only)
4 changes: 2 additions & 2 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 @@ -17,7 +17,7 @@ rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
wry = { version = "0.50.3", default-features = false, features = [
wry = { version = "0.50.4", default-features = false, features = [
"drag-drop",
"protocol",
"os-webview",
Expand Down
53 changes: 47 additions & 6 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};
use webview2_com::FocusChangedEventHandler;
#[cfg(windows)]
use windows::Win32::Foundation::HWND;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use wry::WebViewBuilderExtDarwin;
#[cfg(windows)]
use wry::WebViewBuilderExtWindows;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use wry::{WebViewBuilderExtDarwin, WebViewExtDarwin};

use tao::{
dpi::{
Expand Down Expand Up @@ -1180,11 +1180,15 @@ unsafe impl Send for GtkBox {}
pub struct SendRawWindowHandle(pub raw_window_handle::RawWindowHandle);
unsafe impl Send for SendRawWindowHandle {}

#[cfg(target_os = "macos")]
#[derive(Debug, Clone)]
pub enum ApplicationMessage {
#[cfg(target_os = "macos")]
Show,
#[cfg(target_os = "macos")]
Hide,
#[cfg(any(target_os = "macos", target_os = "ios"))]
FetchDataStoreIdentifiers(Box<dyn FnOnce(Vec<[u8; 16]>) + Send + 'static>),
#[cfg(any(target_os = "macos", target_os = "ios"))]
RemoveDataStore([u8; 16], Box<dyn FnOnce(Result<()>) + Send + 'static>),
}

pub enum WindowMessage {
Expand Down Expand Up @@ -1347,7 +1351,6 @@ pub enum Message<T: 'static> {
#[cfg(target_os = "macos")]
SetActivationPolicy(ActivationPolicy),
RequestExit(i32),
#[cfg(target_os = "macos")]
Application(ApplicationMessage),
Window(WindowId, WindowMessage),
Webview(WindowId, WebviewId, WebviewMessage),
Expand Down Expand Up @@ -2507,6 +2510,29 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
{
dispatch(f)
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(
&self,
cb: F,
) -> Result<()> {
send_user_message(
&self.context,
Message::Application(ApplicationMessage::FetchDataStoreIdentifiers(Box::new(cb))),
)
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(
&self,
uuid: [u8; 16],
cb: F,
) -> Result<()> {
send_user_message(
&self.context,
Message::Application(ApplicationMessage::RemoveDataStore(uuid, Box::new(cb))),
)
}
}

impl<T: UserEvent> Wry<T> {
Expand Down Expand Up @@ -2923,14 +2949,29 @@ fn handle_user_message<T: UserEvent>(
event_loop.set_activation_policy_at_runtime(tao_activation_policy(activation_policy))
}
Message::RequestExit(_code) => panic!("cannot handle RequestExit on the main thread"),
#[cfg(target_os = "macos")]
Message::Application(application_message) => match application_message {
#[cfg(target_os = "macos")]
ApplicationMessage::Show => {
event_loop.show_application();
}
#[cfg(target_os = "macos")]
ApplicationMessage::Hide => {
event_loop.hide_application();
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
ApplicationMessage::FetchDataStoreIdentifiers(cb) => {
if let Err(e) = WebView::fetch_data_store_identifiers(cb) {
// this shouldn't ever happen because we're running on the main thread
// but let's be safe and warn here
log::error!("failed to fetch data store identifiers: {e}");
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
ApplicationMessage::RemoveDataStore(uuid, cb) => {
WebView::remove_data_store(&uuid, move |res| {
cb(res.map_err(|_| Error::FailedToRemoveDataStore))
})
}
},
Message::Window(id, window_message) => {
let w = windows.0.borrow().get(&id).map(|w| {
Expand Down
18 changes: 18 additions & 0 deletions crates/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ pub enum Error {
InvalidProxyUrl,
#[error("window not found")]
WindowNotFound,
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[error("failed to remove data store")]
FailedToRemoveDataStore,
}

/// Result type.
Expand Down Expand Up @@ -338,6 +341,21 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
fn run_on_android_context<F>(&self, f: F)
where
F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static;

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "macos", target_os = "ios"))))]
fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(
&self,
cb: F,
) -> Result<()>;

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "macos", target_os = "ios"))))]
fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(
&self,
uuid: [u8; 16],
cb: F,
) -> Result<()>;
}

pub trait EventLoopProxy<T: UserEvent>: Debug + Clone + Send + Sync {
Expand Down
2 changes: 2 additions & 0 deletions crates/tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("identifier", true),
("app_show", false),
("app_hide", false),
("fetch_data_store_identifiers", false),
("remove_data_store", false),
("default_window_icon", false),
("set_app_theme", false),
],
Expand Down
52 changes: 52 additions & 0 deletions crates/tauri/permissions/app/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,32 @@ Denies the default_window_icon command without any pre-configured scope.
<tr>
<td>

`core:app:allow-fetch-data-store-identifiers`

</td>
<td>

Enables the fetch_data_store_identifiers command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:app:deny-fetch-data-store-identifiers`

</td>
<td>

Denies the fetch_data_store_identifiers command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:app:allow-identifier`

</td>
Expand Down Expand Up @@ -149,6 +175,32 @@ Denies the name command without any pre-configured scope.
<tr>
<td>

`core:app:allow-remove-data-store`

</td>
<td>

Enables the remove_data_store command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:app:deny-remove-data-store`

</td>
<td>

Denies the remove_data_store command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:app:allow-set-app-theme`

</td>
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions crates/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,59 @@ impl AppHandle<crate::Wry> {
}
}

#[cfg(target_vendor = "apple")]
impl<R: Runtime> AppHandle<R> {
/// Fetches all Data Store Indentifiers by this app
///
/// Needs to be called from Main Thread
pub async fn fetch_data_store_identifiers(&self) -> crate::Result<Vec<[u8; 16]>> {
use std::sync::Mutex;

let (tx, rx) = tokio::sync::oneshot::channel::<Result<Vec<[u8; 16]>, tauri_runtime::Error>>();
let lock: Arc<Mutex<Option<_>>> = Arc::new(Mutex::new(Some(tx)));
let runtime_handle = self.runtime_handle.clone();

self.run_on_main_thread(move || {
let cloned_lock = lock.clone();
if let Err(err) = runtime_handle.fetch_data_store_identifiers(move |ids| {
if let Some(tx) = cloned_lock.lock().unwrap().take() {
let _ = tx.send(Ok(ids));
}
}) {
if let Some(tx) = lock.lock().unwrap().take() {
let _ = tx.send(Err(err));
}
}
})?;

rx.await?.map_err(Into::into)
}
/// Deletes a Data Store of this app
///
/// Needs to be called from Main Thread
pub async fn remove_data_store(&self, uuid: [u8; 16]) -> crate::Result<()> {
use std::sync::Mutex;

let (tx, rx) = tokio::sync::oneshot::channel::<Result<(), tauri_runtime::Error>>();
let lock: Arc<Mutex<Option<_>>> = Arc::new(Mutex::new(Some(tx)));
let runtime_handle = self.runtime_handle.clone();

self.run_on_main_thread(move || {
let cloned_lock = lock.clone();
if let Err(err) = runtime_handle.remove_data_store(uuid, move |result| {
if let Some(tx) = cloned_lock.lock().unwrap().take() {
let _ = tx.send(result);
}
}) {
if let Some(tx) = lock.lock().unwrap().take() {
let _ = tx.send(Err(err));
}
}
})?;
rx.await?.map_err(Into::into)
}
}

impl<R: Runtime> Clone for AppHandle<R> {
fn clone(&self) -> Self {
Self {
Expand Down
23 changes: 23 additions & 0 deletions crates/tauri/src/app/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,27 @@ pub fn app_hide<R: Runtime>(app: AppHandle<R>) -> crate::Result<()> {
Ok(())
}

#[command(root = "crate")]
#[allow(unused_variables)]
pub async fn fetch_data_store_identifiers<R: Runtime>(
app: AppHandle<R>,
) -> crate::Result<Vec<[u8; 16]>> {
#[cfg(target_vendor = "apple")]
return app.fetch_data_store_identifiers().await;
#[cfg(not(target_vendor = "apple"))]
return Ok(Vec::new());
}

#[command(root = "crate")]
#[allow(unused_variables)]
pub async fn remove_data_store<R: Runtime>(app: AppHandle<R>, uuid: [u8; 16]) -> crate::Result<()> {
#[cfg(target_vendor = "apple")]
app.remove_data_store(uuid).await?;
#[cfg(not(target_vendor = "apple"))]
let _ = uuid;
Ok(())
}

#[command(root = "crate")]
pub fn default_window_icon<R: Runtime>(
webview: Webview<R>,
Expand All @@ -71,6 +92,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
identifier,
app_show,
app_hide,
fetch_data_store_identifiers,
remove_data_store,
default_window_icon,
set_app_theme,
])
Expand Down
3 changes: 3 additions & 0 deletions crates/tauri/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ pub enum Error {
/// Illegal event name.
#[error("only alphanumeric, '-', '/', ':', '_' permitted for event names: {0:?}")]
IllegalEventName(String),
/// tokio oneshot channel failed to receive message
#[error(transparent)]
TokioOneshotRecv(#[from] tokio::sync::oneshot::error::RecvError),
}

impl From<getrandom::Error> for Error {
Expand Down
17 changes: 17 additions & 0 deletions crates/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,23 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
todo!()
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn fetch_data_store_identifiers<F: FnOnce(Vec<[u8; 16]>) + Send + 'static>(
&self,
cb: F,
) -> Result<()> {
todo!()
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
fn remove_data_store<F: FnOnce(Result<()>) + Send + 'static>(
&self,
uuid: [u8; 16],
cb: F,
) -> Result<()> {
todo!()
}

fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
Ok(PhysicalPosition::new(0.0, 0.0))
}
Expand Down
Loading