[feat] Support for Browser Profiles
(see Wry issue here: https://github.com/tauri-apps/wry/issues/1321)
Describe the problem
I would ideally like to be able to create separate browsing profiles to segment Cookies, localStorage, and IndexedDB data into different profiles. Here are some use cases which could benefit from this feature:
- Supporting multiple account login without any further server-side development
- Local-first applications like Excalidraw which typically stores user data within either localStorage or an IndexedDB table
- To limit third party tracking cookies across different webviews
The above use cases are very similar to the use cases for the data_directory() api. However, as I noted in the Alternatives considered section, the data_directory() api is not supported on MacOS.
Describe the solution you'd like
Platform-Specific Implementation Details
In macOS 14 and iOS 17 Apple has released new DataStore APIs which should enable this feature.
In Windows Microsoft has released new Multiple Profile Support which should enable this feature.
I assume we can polyfill this feature to WebkitGTK using the existing data_directory() function on the WebviewBuilder struct. Ideally the polyfill would create additional subdirectories within the default data directory to support the different profile names. For private profiles (i.e. incognito windows) which shouldn't be persisted I propose the use of the tmp directory to store those temporary profiles. While we won't get the performance advantages listed below in the Alternatives Considered, a polyfill will at least allow some support in the interim before GTK supports browser profiles.
Proposed API
The following is inspired by the above linked guides from the shared features which both Apple and Microsoft support. Note that Microsoft supports one additional configuration for a Profile, ScriptLocale, which I chose to exclude from the API since WebKit does not support it in their implementation. Conveniently both support private windows and custom names, although WebKit requires that the name is a UUID whereas Webview2 has some arbitrary name constraints.
In terms of the API itself, I propose one new struct, a WebviewProfile which will store all of the necessary references and metadata needed for profiles. I also propose the following public functions for WebviewProfile, App, and WebviewBuilder:
For WebviewProfile
-
WebviewProfile::default() -> WebviewProfilereturns the default profile. -
WebviewProfile::private() -> WebviewProfilereturns a temporary profile. -
WebviewProfile::new(name: String) -> WebviewProfilereturns a new profile, storing the display name as metadata. It will not check whether the name has been used before as that would require access to theAppstate. -
WebviewProfile::filePath(&self) -> Option<Path>returnsSome(directory)where all of the user data is stored if it isn't private, otherwise returnsNone. Note that this option resolves the complaint (#8635) around trying to locate where the browser persists user data when using the default data_directory(), both in the default case, and in the case of a custom profile. I assume that we can hard-code platform-dependent paths manually to support this api. -
WebviewProfile::display() -> Stringreturns the configured display name,"private", or"default"depending on the type of profile.- Should also implement
std::fmtwhich should call the above function.
- Should also implement
For App
-
App::getWebviewProfiles(&self) -> HashMap<String, WebviewProfile>which will function similarly toApp::windows(&self)in returning aHashMapwith Strings mapping to WebviewProfiles. The keys are the same as theStringpassed intoWebviewProfile::new(). Note that private profiles will not be included in the returnedHashMap. -
App::addWebviewProfile(&mut self, profile: WebviewProfile) -> Result(Self)which will add a new profile to the app. It will return Ok(Self) if the profile was successfully created or an error detailing what went wrong. For example it should return anAlreadyExistserror if a profile with the same ID already exists. -
App::deleteWebviewProfile(&mut self, profile: WebviewProfile) -> Result(boolean)which will delete the webview profile and return true if it exists within the app, otherwise returning false. Will refuse to delete the profile if it is still in use by a webview, instead returning an error. Will also refuse to delete the default profile, instead returning an error.
For WebviewBuilder
-
WebviewBuilder::profile(mut self, profile: WebviewProfile) -> Selfwhich will configure the profile to be used for that webview. When the WebviewBuilder is used to make a webview if the existing profiles do not contain a profile with the passed in profile's id then it will attempt to calladdWebviewProfile()on theAppand return the result from that call. Otherwise it will use the existing profile's ID.
For Webview
-
Webview::profile(self) -> WebviewProfilewhich will return the active profile for the webview.
Alternatives considered
I initially considered using the data_directory() api to emulate different profiles across all platforms, similar to what I proposed for the WebkitGTK polyfill. Unfortunately, as @FabianLars points out in #8637, "We can't control the data dir on macos."
Additionally, Microsoft justifies the addition of multiple profiles (over the existing data folder api) as follows:
Previously, without multi-profile support, to achieve data separation, a WebView2 app could use different user data folders for different WebView2 controls. However, in that approach, you must run multiple WebView2 runtime instances (each including a browser process and a bunch of child processes), which consumed more system resources including memory, CPU footprint, and disk space. source
Additional context
No response
Also I just wanted to clarify that I am happy to attempt the implementation of this myself as long as this feature request is given the go ahead.
This sounds like a good proposal and would need to be implemented in wry crate first. Requiring macOS 14 is annoying though so might need to be put behind a feature flag or something. Also what about android?
Anyways feel free to experiment and open a PR if you want, contributions are always welcome.
For Android I suggest we use the same polyfill that I proposed for WebkitGTK as Android currently also lacks support for multiple browser profiles. Also yeah, having limited backwards support for MacOS is annoying so I agree a feature flag would be appropriate for this feature.
Is there any result yet
Unfortunately I've been too busy with other projects to work on this. If you (or anyone else) would like to take it over, feel free! I might eventually get around to it if no one else takes it over.
@zphrs Is there any progress on this function at present?
Nope, see my comment from March 28.