mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-01 10:01:07 +02:00
add AppHandle.fetch_data_store_identifiers and AppHandle.remove_data_store (#12900)
* add `AppHandle::fetch_all_data_store_identifiers` and `AppHandle::remove_data_store` * make it run on main thread, so you can call the function from any thread and it works. * changes file * update signature, move functions to RuntimeHandle * add api --------- Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
5
.changes/datastore_api.md
Normal file
5
.changes/datastore_api.md
Normal file
@@ -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
Cargo.lock
generated
4
Cargo.lock
generated
@@ -10854,9 +10854,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.50.3"
|
||||
version = "0.50.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ec139df5102db821f92a42033c3fa0467c5ab434511e79c65881d6bdf2b369"
|
||||
checksum = "804a7d1613bd699beccaa60f3b3c679acee21cebba1945a693f5eab95c08d1fa"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.6.0",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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::{
|
||||
@@ -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 {
|
||||
@@ -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),
|
||||
@@ -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> {
|
||||
@@ -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| {
|
||||
|
||||
@@ -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.
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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 {
|
||||
|
||||
@@ -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>,
|
||||
@@ -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,
|
||||
])
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -6,6 +6,25 @@ import { invoke } from './core'
|
||||
import { Image } from './image'
|
||||
import { Theme } from './window'
|
||||
|
||||
export type DataStoreIdentifier = [
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
number
|
||||
]
|
||||
|
||||
/**
|
||||
* Application metadata and related APIs.
|
||||
*
|
||||
@@ -101,6 +120,46 @@ async function hide(): Promise<void> {
|
||||
return invoke('plugin:app|app_hide')
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the data store identifiers on macOS and iOS.
|
||||
*
|
||||
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { fetchDataStoreIdentifiers } from '@tauri-apps/api/app';
|
||||
* const ids = await fetchDataStoreIdentifiers();
|
||||
* ```
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
async function fetchDataStoreIdentifiers(): Promise<DataStoreIdentifier[]> {
|
||||
return invoke('plugin:app|fetch_data_store_identifiers')
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the data store with the given identifier.
|
||||
*
|
||||
* Note that any webview using this data store should be closed before running this API.
|
||||
*
|
||||
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { fetchDataStoreIdentifiers, removeDataStore } from '@tauri-apps/api/app';
|
||||
* for (const id of (await fetchDataStoreIdentifiers())) {
|
||||
* await removeDataStore(id);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
async function removeDataStore(
|
||||
uuid: DataStoreIdentifier
|
||||
): Promise<DataStoreIdentifier[]> {
|
||||
return invoke('plugin:app|remove_data_store', { uuid })
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default window icon.
|
||||
*
|
||||
@@ -145,5 +204,7 @@ export {
|
||||
show,
|
||||
hide,
|
||||
defaultWindowIcon,
|
||||
setTheme
|
||||
setTheme,
|
||||
fetchDataStoreIdentifiers,
|
||||
removeDataStore
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user