From 59089723fc20d66f3f305f2008adeb279bf87462 Mon Sep 17 00:00:00 2001 From: Fabian-Lars Date: Mon, 1 Sep 2025 18:56:26 +0200 Subject: [PATCH] feat(api): add dataDirectory setting config (#14091) * feat(api): ad dataDirectory setting config * changefile fmt * chain, log if dirs::data_local_dir fails --------- Co-authored-by: Lucas Nogueira --- .changes/data-dir-js.md | 6 +++ crates/tauri-cli/config.schema.json | 21 ++++++++++ .../schemas/config.schema.json | 21 ++++++++++ crates/tauri-utils/src/config.rs | 33 ++++++++++++++- crates/tauri/src/webview/mod.rs | 41 ++++++++++++++++++- packages/api/src/webview.ts | 27 ++++++++++++ 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 .changes/data-dir-js.md diff --git a/.changes/data-dir-js.md b/.changes/data-dir-js.md new file mode 100644 index 000000000..9fff3317d --- /dev/null +++ b/.changes/data-dir-js.md @@ -0,0 +1,6 @@ +--- +"tauri-utils": "minor:enhance" +"@tauri-apps/api": "minor:enhance" +--- + +Added a config to set a data_directory relative to the app-specific data dir in JavaScript and `tauri.conf.json`. diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index 599642243..75840cf31 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -572,6 +572,27 @@ "description": "Allows disabling the input accessory view on iOS.\n\n The accessory view is the view that appears above the keyboard when a text input element is focused.\n It usually displays a view with \"Done\", \"Next\" buttons.", "default": false, "type": "boolean" + }, + "dataDirectory": { + "description": "Set a custom path for the webview's data directory (localStorage, cache, etc.) **relative to [`appDataDir()`]/${label}**.\n\n To set absolute paths, use [`WebviewWindowBuilder::data_directory`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.data_directory)\n\n #### Platform-specific:\n\n - **Windows**: WebViews with different values for settings like `additionalBrowserArgs`, `browserExtensionsEnabled` or `scrollBarStyle` must have different data directories.\n - **macOS / iOS**: Unsupported, use `dataStoreIdentifier` instead.\n - **Android**: Unsupported.", + "type": [ + "string", + "null" + ] + }, + "dataStoreIdentifier": { + "description": "Initialize the WebView with a custom data store identifier. This can be seen as a replacement for `dataDirectory` which is unavailable in WKWebView.\n See https://developer.apple.com/documentation/webkit/wkwebsitedatastore/init(foridentifier:)?language=objc\n\n The array must contain 16 u8 numbers.\n\n #### Platform-specific:\n\n - **iOS**: Supported since version 17.0+.\n - **macOS**: Supported since version 14.0+.\n - **Windows / Linux / Android**: Unsupported.", + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 16, + "minItems": 16 } }, "additionalProperties": false diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index 599642243..75840cf31 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -572,6 +572,27 @@ "description": "Allows disabling the input accessory view on iOS.\n\n The accessory view is the view that appears above the keyboard when a text input element is focused.\n It usually displays a view with \"Done\", \"Next\" buttons.", "default": false, "type": "boolean" + }, + "dataDirectory": { + "description": "Set a custom path for the webview's data directory (localStorage, cache, etc.) **relative to [`appDataDir()`]/${label}**.\n\n To set absolute paths, use [`WebviewWindowBuilder::data_directory`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.data_directory)\n\n #### Platform-specific:\n\n - **Windows**: WebViews with different values for settings like `additionalBrowserArgs`, `browserExtensionsEnabled` or `scrollBarStyle` must have different data directories.\n - **macOS / iOS**: Unsupported, use `dataStoreIdentifier` instead.\n - **Android**: Unsupported.", + "type": [ + "string", + "null" + ] + }, + "dataStoreIdentifier": { + "description": "Initialize the WebView with a custom data store identifier. This can be seen as a replacement for `dataDirectory` which is unavailable in WKWebView.\n See https://developer.apple.com/documentation/webkit/wkwebsitedatastore/init(foridentifier:)?language=objc\n\n The array must contain 16 u8 numbers.\n\n #### Platform-specific:\n\n - **iOS**: Supported since version 17.0+.\n - **macOS**: Supported since version 14.0+.\n - **Windows / Linux / Android**: Unsupported.", + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 16, + "minItems": 16 } }, "additionalProperties": false diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index bd9aac375..372792f1f 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -1894,6 +1894,31 @@ pub struct WindowConfig { alias = "disable_input_accessory_view" )] pub disable_input_accessory_view: bool, + /// + /// Set a custom path for the webview's data directory (localStorage, cache, etc.) **relative to [`appDataDir()`]/${label}**. + /// + /// To set absolute paths, use [`WebviewWindowBuilder::data_directory`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.data_directory) + /// + /// #### Platform-specific: + /// + /// - **Windows**: WebViews with different values for settings like `additionalBrowserArgs`, `browserExtensionsEnabled` or `scrollBarStyle` must have different data directories. + /// - **macOS / iOS**: Unsupported, use `dataStoreIdentifier` instead. + /// - **Android**: Unsupported. + #[serde(default, alias = "data-directory")] + pub data_directory: Option, + /// + /// Initialize the WebView with a custom data store identifier. This can be seen as a replacement for `dataDirectory` which is unavailable in WKWebView. + /// See https://developer.apple.com/documentation/webkit/wkwebsitedatastore/init(foridentifier:)?language=objc + /// + /// The array must contain 16 u8 numbers. + /// + /// #### Platform-specific: + /// + /// - **iOS**: Supported since version 17.0+. + /// - **macOS**: Supported since version 14.0+. + /// - **Windows / Linux / Android**: Unsupported. + #[serde(default, alias = "data-store-identifier")] + pub data_store_identifier: Option<[u8; 16]>, } impl Default for WindowConfig { @@ -1953,6 +1978,8 @@ impl Default for WindowConfig { javascript_disabled: false, allow_link_preview: true, disable_input_accessory_view: false, + data_directory: None, + data_store_identifier: None, } } } @@ -3459,6 +3486,8 @@ mod build { let javascript_disabled = self.javascript_disabled; let allow_link_preview = self.allow_link_preview; let disable_input_accessory_view = self.disable_input_accessory_view; + let data_directory = opt_lit(self.data_directory.as_ref().map(path_buf_lit).as_ref()); + let data_store_identifier = opt_vec_lit(self.data_store_identifier, identity); literal_struct!( tokens, @@ -3516,7 +3545,9 @@ mod build { background_throttling, javascript_disabled, allow_link_preview, - disable_input_accessory_view + disable_input_accessory_view, + data_directory, + data_store_identifier ); } } diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index 6be175d90..0fb6fd977 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -42,6 +42,7 @@ use crate::{ InvokeError, InvokeMessage, InvokeResolver, Origin, OwnedInvokeResponder, ScopeObject, }, manager::AppManager, + path::SafePathBuf, sealed::{ManagerBase, RuntimeOrDispatch}, AppHandle, Emitter, Event, EventId, EventLoopMessage, EventName, Listener, Manager, ResourceTable, Runtime, Window, @@ -387,9 +388,47 @@ async fn create_window(app: tauri::AppHandle) { /// /// [the Webview2 issue]: https://github.com/tauri-apps/wry/issues/583 pub fn from_config(config: &WindowConfig) -> Self { + let mut config = config.to_owned(); + + if let Some(data_directory) = &config.data_directory { + let resolve_data_dir_res = dirs::data_local_dir() + .or({ + #[cfg(feature = "tracing")] + tracing::error!("failed to resolve data directory"); + None + }) + .and_then(|local_dir| { + SafePathBuf::new(data_directory.clone()) + .inspect_err(|_err| { + #[cfg(feature = "tracing")] + tracing::error!( + "data_directory `{}` is not a safe path, ignoring config. Validation error was: {_err}", + data_directory.display() + ); + }) + .map(|p| (local_dir, p)) + .ok() + }) + .and_then(|(local_dir, data_directory)| { + if data_directory.as_ref().is_relative() { + Some(local_dir.join(&config.label).join(data_directory.as_ref())) + } else { + #[cfg(feature = "tracing")] + tracing::error!( + "data_directory `{}` is not a relative path, ignoring config.", + data_directory.display() + ); + None + } + }); + if let Some(resolved_data_directory) = resolve_data_dir_res { + config.data_directory = Some(resolved_data_directory); + } + } + Self { label: config.label.clone(), - webview_attributes: WebviewAttributes::from(config), + webview_attributes: WebviewAttributes::from(&config), web_resource_request_handler: None, navigation_handler: None, new_window_handler: None, diff --git a/packages/api/src/webview.ts b/packages/api/src/webview.ts index c691669f1..d5998cb61 100644 --- a/packages/api/src/webview.ts +++ b/packages/api/src/webview.ts @@ -854,6 +854,33 @@ interface WebviewOptions { * It usually displays a view with "Done", "Next" buttons. */ disableInputAccessoryView?: boolean + /** + * Set a custom path for the webview's data directory (localStorage, cache, etc.) **relative to [`appDataDir()`]/${label}**. + * For security reasons, paths outside of that location can only be configured on the Rust side. + * + * #### Platform-specific: + * + * - **Windows**: WebViews with different values for settings like `additionalBrowserArgs`, `browserExtensionsEnabled` or `scrollBarStyle` must have different data directories. + * - **macOS / iOS**: Unsupported, use `dataStoreIdentifier` instead. + * - **Android**: Unsupported. + * + * @since 2.9.0 + */ + dataDirectory?: string + /** + * Initialize the WebView with a custom data store identifier. This can be seen as a replacement for `dataDirectory` which is unavailable in WKWebView. + * See https://developer.apple.com/documentation/webkit/wkwebsitedatastore/init(foridentifier:)?language=objc + * + * The array must contain 16 u8 numbers. + * + * #### Platform-specific: + * + * - **macOS / iOS**: Available on macOS >= 14 and iOS >= 17 + * - **Windows / Linux / Android**: Unsupported. + * + * @since 2.9.0 + */ + dataStoreIdentifier?: number[] } export { Webview, getCurrentWebview, getAllWebviews }