From f7620b2b9076e612bd230d28a833271c5ea29ee8 Mon Sep 17 00:00:00 2001 From: David Lemarier Date: Wed, 17 Mar 2021 09:47:59 -0400 Subject: [PATCH 1/5] WIP: Allow webview2 to use optional user_data folder. Actually only supported on Windows. Attention the folder need to exist or webview will failed to run. --- examples/custom_user_data.rs | 22 ++++++++++++++++++++++ src/application/attributes.rs | 13 ++++++++++++- src/application/general.rs | 5 ++++- src/webview/linux/mod.rs | 3 ++- src/webview/macos/mod.rs | 2 ++ src/webview/mod.rs | 27 +++++++++++++++++++++++++-- src/webview/win/mod.rs | 16 ++++++++++++++-- 7 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 examples/custom_user_data.rs diff --git a/examples/custom_user_data.rs b/examples/custom_user_data.rs new file mode 100644 index 000000000..f4be498ae --- /dev/null +++ b/examples/custom_user_data.rs @@ -0,0 +1,22 @@ +use std::path::PathBuf; +use wry::{Application, Attributes, Result}; + +fn main() -> Result<()> { + let mut app = Application::new()?; + + let test_path = PathBuf::from(env!("OUT_DIR")); + + println!("Webview storage path: {:#?}", test_path); + + let attributes = Attributes { + url: Some("https://tauri.studio/".to_string()), + title: String::from("Hello World!"), + // Currently supported only on Windows + user_data_path: Some(test_path), + ..Default::default() + }; + + app.add_window(attributes)?; + app.run(); + Ok(()) +} diff --git a/src/application/attributes.rs b/src/application/attributes.rs index 370369272..fec8cd2ec 100644 --- a/src/application/attributes.rs +++ b/src/application/attributes.rs @@ -1,6 +1,9 @@ use crate::{Result, RpcRequest, RpcResponse, WindowProxy}; -use std::{fs::read, path::Path}; +use std::{ + fs::read, + path::{Path, PathBuf}, +}; /// The RPC handler to Communicate between the host Rust code and Javascript on webview. /// @@ -191,6 +194,11 @@ pub struct Attributes { /// /// The default is an empty vector. pub initialization_scripts: Vec, + + /// Webview user data path. + /// + /// The default is `None`. + pub user_data_path: Option, } impl Attributes { @@ -220,6 +228,7 @@ impl Attributes { transparent: self.transparent, url: self.url, initialization_scripts: self.initialization_scripts, + user_data_path: self.user_data_path, }, ) } @@ -249,6 +258,7 @@ impl Default for Attributes { skip_taskbar: false, url: None, initialization_scripts: vec![], + user_data_path: None, } } } @@ -278,4 +288,5 @@ pub(crate) struct InnerWebViewAttributes { pub transparent: bool, pub url: Option, pub initialization_scripts: Vec, + pub user_data_path: Option, } diff --git a/src/application/general.rs b/src/application/general.rs index 5b2f76643..bbb8cc571 100644 --- a/src/application/general.rs +++ b/src/application/general.rs @@ -354,7 +354,10 @@ fn _create_webview( ) -> Result { let window_id = window.id(); - let mut webview = WebViewBuilder::new(window)?.transparent(attributes.transparent); + let mut webview = WebViewBuilder::new(window)? + .transparent(attributes.transparent) + .user_data_path(attributes.user_data_path); + for js in attributes.initialization_scripts { webview = webview.initialize_script(&js); } diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index 60b7798ea..55368c6cf 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -5,7 +5,7 @@ use crate::{ Error, FileDropHandler, Result, RpcHandler, }; -use std::rc::Rc; +use std::{path::PathBuf, rc::Rc}; use gdk::RGBA; use gio::Cancellable; @@ -33,6 +33,7 @@ impl WV for InnerWebView { custom_protocol: Option<(String, F)>, rpc_handler: Option, file_drop_handler: Option, + _user_data_path: Option, ) -> Result { // Webview widget let manager = UserContentManager::new(); diff --git a/src/webview/macos/mod.rs b/src/webview/macos/mod.rs index 62bfb068e..c4cd24668 100644 --- a/src/webview/macos/mod.rs +++ b/src/webview/macos/mod.rs @@ -9,6 +9,7 @@ use file_drop::{add_file_drop_methods, set_file_drop_handler}; use std::{ ffi::{c_void, CStr}, os::raw::c_char, + path::PathBuf, ptr::null, slice, str, }; @@ -42,6 +43,7 @@ impl WV for InnerWebView { custom_protocol: Option<(String, F)>, rpc_handler: Option, file_drop_handler: Option, + _user_data_path: Option, ) -> Result { // Function for rpc handler extern "C" fn did_receive(this: &Object, _: Sel, _: id, msg: id) { diff --git a/src/webview/mod.rs b/src/webview/mod.rs index cecdbbb54..008123fb9 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -17,7 +17,10 @@ use win::*; use crate::{Error, FileDropHandler, Result}; -use std::sync::mpsc::{channel, Receiver, Sender}; +use std::{ + path::PathBuf, + sync::mpsc::{channel, Receiver, Sender}, +}; use serde_json::Value; use url::Url; @@ -85,6 +88,7 @@ pub struct WebViewBuilder { custom_protocol: Option<(String, Box Result>>)>, rpc_handler: Option, file_drop_handler: Option, + user_data_path: Option, } impl WebViewBuilder { @@ -102,6 +106,7 @@ impl WebViewBuilder { custom_protocol: None, rpc_handler: None, file_drop_handler: None, + user_data_path: None, }) } @@ -120,6 +125,13 @@ impl WebViewBuilder { self } + /// Whether the WebView window should have a custom user data path. This is usefull in Windows + /// when a bundled application can't have the webview data inside `Program Files`. + pub fn user_data_path(mut self, user_data_path: Option) -> Self { + self.user_data_path = user_data_path; + self + } + /// Create a [`Dispatcher`] to send evaluation scripts to the WebView. [`WebView`] is not thread /// safe because it must be run on the main thread who creates it. [`Dispatcher`] can let you /// send the scripts from other threads. @@ -213,6 +225,7 @@ impl WebViewBuilder { self.custom_protocol, self.rpc_handler, self.file_drop_handler, + self.user_data_path, )?; Ok(WebView { window: self.window, @@ -251,7 +264,16 @@ impl WebView { pub fn new_with_configs(window: Window, transparent: bool) -> Result { let picky_none: Option<(String, Box Result>>)> = None; - let webview = InnerWebView::new(&window, vec![], None, transparent, picky_none, None, None)?; + let webview = InnerWebView::new( + &window, + vec![], + None, + transparent, + picky_none, + None, + None, + None, + )?; let (tx, rx) = channel(); @@ -327,6 +349,7 @@ pub(crate) trait WV: Sized { custom_protocol: Option<(String, F)>, rpc_handler: Option, file_drop_handler: Option, + user_data_path: Option, ) -> Result; fn eval(&self, js: &str) -> Result<()>; diff --git a/src/webview/win/mod.rs b/src/webview/win/mod.rs index 822bfe4f6..2489e8146 100644 --- a/src/webview/win/mod.rs +++ b/src/webview/win/mod.rs @@ -7,7 +7,7 @@ use crate::{ use file_drop::FileDropController; -use std::{os::raw::c_void, rc::Rc}; +use std::{os::raw::c_void, path::PathBuf, rc::Rc}; use once_cell::unsync::OnceCell; use url::Url; @@ -37,6 +37,7 @@ impl WV for InnerWebView { custom_protocol: Option<(String, F)>, rpc_handler: Option, file_drop_handler: Option, + user_data_path: Option, ) -> Result { let hwnd = window.hwnd() as HWND; @@ -46,8 +47,19 @@ impl WV for InnerWebView { let file_drop_controller: Rc> = Rc::new(OnceCell::new()); let file_drop_controller_clone = file_drop_controller.clone(); + let webview_builder: webview2::EnvironmentBuilder; + let user_data_path_provided: PathBuf; + + if user_data_path.is_some() { + user_data_path_provided = user_data_path.unwrap(); + webview_builder = + webview2::EnvironmentBuilder::new().with_user_data_folder(&user_data_path_provided); + } else { + webview_builder = webview2::EnvironmentBuilder::new(); + } + // Webview controller - webview2::EnvironmentBuilder::new().build(move |env| { + webview_builder.build(move |env| { let env = env?; let env_ = env.clone(); env.create_controller(hwnd, move |controller| { From 241b7c90fea4c961762572c9bf9972ad135fe1b6 Mon Sep 17 00:00:00 2001 From: David Lemarier Date: Wed, 17 Mar 2021 10:33:52 -0400 Subject: [PATCH 2/5] Use `./target/webview_data` as sample directory for `user_data_path` example. --- examples/custom_user_data.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/custom_user_data.rs b/examples/custom_user_data.rs index f4be498ae..1de9ef45d 100644 --- a/examples/custom_user_data.rs +++ b/examples/custom_user_data.rs @@ -1,12 +1,15 @@ use std::path::PathBuf; +use std::fs; use wry::{Application, Attributes, Result}; fn main() -> Result<()> { let mut app = Application::new()?; - let test_path = PathBuf::from(env!("OUT_DIR")); - - println!("Webview storage path: {:#?}", test_path); + // Use a sample directory at the root of the project + let test_path = PathBuf::from("./target/webview_data"); + // The directory need to exist or the Webview will panic + fs::create_dir_all(&test_path)?; + println!("Webview storage path: {:#?}", &test_path); let attributes = Attributes { url: Some("https://tauri.studio/".to_string()), From 17e902f0a817e961103a35ccb6f75595d7a267ec Mon Sep 17 00:00:00 2001 From: David Lemarier Date: Wed, 17 Mar 2021 10:40:32 -0400 Subject: [PATCH 3/5] Use canonicalized path as we require an absolute path for the webview --- examples/custom_user_data.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/custom_user_data.rs b/examples/custom_user_data.rs index 1de9ef45d..f0ffa93f5 100644 --- a/examples/custom_user_data.rs +++ b/examples/custom_user_data.rs @@ -6,7 +6,8 @@ fn main() -> Result<()> { let mut app = Application::new()?; // Use a sample directory at the root of the project - let test_path = PathBuf::from("./target/webview_data"); + // We need an absoulte path + let test_path = fs::canonicalize(PathBuf::from("./target/webview_data"))?; // The directory need to exist or the Webview will panic fs::create_dir_all(&test_path)?; println!("Webview storage path: {:#?}", &test_path); From 8f76cb336b63f2eca17b59d3843fc2e583d9bf8c Mon Sep 17 00:00:00 2001 From: David Lemarier Date: Wed, 17 Mar 2021 10:45:19 -0400 Subject: [PATCH 4/5] Make sure to create the directory before we can canonicalize --- examples/custom_user_data.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/custom_user_data.rs b/examples/custom_user_data.rs index f0ffa93f5..4804a9d48 100644 --- a/examples/custom_user_data.rs +++ b/examples/custom_user_data.rs @@ -6,10 +6,12 @@ fn main() -> Result<()> { let mut app = Application::new()?; // Use a sample directory at the root of the project - // We need an absoulte path - let test_path = fs::canonicalize(PathBuf::from("./target/webview_data"))?; + let mut test_path = PathBuf::from("./target/webview_data"); // The directory need to exist or the Webview will panic fs::create_dir_all(&test_path)?; + // We need an absoulte path for the webview + test_path = fs::canonicalize(&test_path)?; + // The directory need to exist or the Webview will panic println!("Webview storage path: {:#?}", &test_path); let attributes = Attributes { From 369cf56fdb9d2759eb8942c3ac0b435b85addeb7 Mon Sep 17 00:00:00 2001 From: David Lemarier Date: Wed, 17 Mar 2021 10:47:03 -0400 Subject: [PATCH 5/5] fmt --- examples/custom_user_data.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/custom_user_data.rs b/examples/custom_user_data.rs index 4804a9d48..8355a9bff 100644 --- a/examples/custom_user_data.rs +++ b/examples/custom_user_data.rs @@ -1,5 +1,4 @@ -use std::path::PathBuf; -use std::fs; +use std::{fs, path::PathBuf}; use wry::{Application, Attributes, Result}; fn main() -> Result<()> {