123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
- // SPDX-License-Identifier: Apache-2.0
- // SPDX-License-Identifier: MIT
- //! A layer between raw [`Runtime`] webviews and Tauri.
- //!
- use crate::{
- window::{
- dpi::{Position, Size},
- is_label_valid,
- },
- Runtime, UserEvent,
- };
- use tauri_utils::config::{WebviewUrl, WindowConfig, WindowEffectsConfig};
- use url::Url;
- use std::{
- borrow::Cow,
- collections::HashMap,
- hash::{Hash, Hasher},
- path::PathBuf,
- sync::Arc,
- };
- type UriSchemeProtocol = dyn Fn(http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
- + Send
- + Sync
- + 'static;
- type WebResourceRequestHandler =
- dyn Fn(http::Request<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync;
- type NavigationHandler = dyn Fn(&Url) -> bool + Send;
- type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send;
- type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync;
- /// Download event.
- pub enum DownloadEvent<'a> {
- /// Download requested.
- Requested {
- /// The url being downloaded.
- url: Url,
- /// Represents where the file will be downloaded to.
- /// Can be used to set the download location by assigning a new path to it.
- /// The assigned path _must_ be absolute.
- destination: &'a mut PathBuf,
- },
- /// Download finished.
- Finished {
- /// The URL of the original download request.
- url: Url,
- /// Potentially representing the filesystem path the file was downloaded to.
- path: Option<PathBuf>,
- /// Indicates if the download succeeded or not.
- success: bool,
- },
- }
- #[cfg(target_os = "android")]
- pub struct CreationContext<'a, 'b> {
- pub env: &'a mut jni::JNIEnv<'b>,
- pub activity: &'a jni::objects::JObject<'b>,
- pub webview: &'a jni::objects::JObject<'b>,
- }
- /// Kind of event for the page load handler.
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
- pub enum PageLoadEvent {
- /// Page started to load.
- Started,
- /// Page finished loading.
- Finished,
- }
- /// A webview that has yet to be built.
- pub struct PendingWebview<T: UserEvent, R: Runtime<T>> {
- /// The label that the webview will be named.
- pub label: String,
- /// The [`WebviewAttributes`] that the webview will be created with.
- pub webview_attributes: WebviewAttributes,
- pub uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocol>>,
- /// How to handle IPC calls on the webview.
- pub ipc_handler: Option<WebviewIpcHandler<T, R>>,
- /// A handler to decide if incoming url is allowed to navigate.
- pub navigation_handler: Option<Box<NavigationHandler>>,
- /// The resolved URL to load on the webview.
- pub url: String,
- #[cfg(target_os = "android")]
- #[allow(clippy::type_complexity)]
- pub on_webview_created:
- Option<Box<dyn Fn(CreationContext<'_, '_>) -> Result<(), jni::errors::Error> + Send>>,
- pub web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,
- pub on_page_load_handler: Option<Box<OnPageLoadHandler>>,
- pub download_handler: Option<Arc<DownloadHandler>>,
- }
- impl<T: UserEvent, R: Runtime<T>> PendingWebview<T, R> {
- /// Create a new [`PendingWebview`] with a label from the given [`WebviewAttributes`].
- pub fn new(
- webview_attributes: WebviewAttributes,
- label: impl Into<String>,
- ) -> crate::Result<Self> {
- let label = label.into();
- if !is_label_valid(&label) {
- Err(crate::Error::InvalidWindowLabel)
- } else {
- Ok(Self {
- webview_attributes,
- uri_scheme_protocols: Default::default(),
- label,
- ipc_handler: None,
- navigation_handler: None,
- url: "tauri://localhost".to_string(),
- #[cfg(target_os = "android")]
- on_webview_created: None,
- web_resource_request_handler: None,
- on_page_load_handler: None,
- download_handler: None,
- })
- }
- }
- pub fn register_uri_scheme_protocol<
- N: Into<String>,
- H: Fn(http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
- + Send
- + Sync
- + 'static,
- >(
- &mut self,
- uri_scheme: N,
- protocol: H,
- ) {
- let uri_scheme = uri_scheme.into();
- self
- .uri_scheme_protocols
- .insert(uri_scheme, Box::new(protocol));
- }
- #[cfg(target_os = "android")]
- pub fn on_webview_created<
- F: Fn(CreationContext<'_, '_>) -> Result<(), jni::errors::Error> + Send + 'static,
- >(
- mut self,
- f: F,
- ) -> Self {
- self.on_webview_created.replace(Box::new(f));
- self
- }
- }
- /// A webview that is not yet managed by Tauri.
- #[derive(Debug)]
- pub struct DetachedWebview<T: UserEvent, R: Runtime<T>> {
- /// Name of the window
- pub label: String,
- /// The [`crate::WebviewDispatch`] associated with the window.
- pub dispatcher: R::WebviewDispatcher,
- }
- impl<T: UserEvent, R: Runtime<T>> Clone for DetachedWebview<T, R> {
- fn clone(&self) -> Self {
- Self {
- label: self.label.clone(),
- dispatcher: self.dispatcher.clone(),
- }
- }
- }
- impl<T: UserEvent, R: Runtime<T>> Hash for DetachedWebview<T, R> {
- /// Only use the [`DetachedWebview`]'s label to represent its hash.
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.label.hash(state)
- }
- }
- impl<T: UserEvent, R: Runtime<T>> Eq for DetachedWebview<T, R> {}
- impl<T: UserEvent, R: Runtime<T>> PartialEq for DetachedWebview<T, R> {
- /// Only use the [`DetachedWebview`]'s label to compare equality.
- fn eq(&self, other: &Self) -> bool {
- self.label.eq(&other.label)
- }
- }
- /// The attributes used to create an webview.
- #[derive(Debug, Clone)]
- pub struct WebviewAttributes {
- pub url: WebviewUrl,
- pub user_agent: Option<String>,
- pub initialization_scripts: Vec<String>,
- pub data_directory: Option<PathBuf>,
- pub file_drop_handler_enabled: bool,
- pub clipboard: bool,
- pub accept_first_mouse: bool,
- pub additional_browser_args: Option<String>,
- pub window_effects: Option<WindowEffectsConfig>,
- pub incognito: bool,
- pub transparent: bool,
- pub bounds: Option<(Position, Size)>,
- pub auto_resize: bool,
- pub proxy_url: Option<Url>,
- }
- impl From<&WindowConfig> for WebviewAttributes {
- fn from(config: &WindowConfig) -> Self {
- let mut builder = Self::new(config.url.clone());
- builder = builder.incognito(config.incognito);
- #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
- {
- builder = builder.transparent(config.transparent);
- }
- builder = builder.accept_first_mouse(config.accept_first_mouse);
- if !config.file_drop_enabled {
- builder = builder.disable_file_drop_handler();
- }
- if let Some(user_agent) = &config.user_agent {
- builder = builder.user_agent(user_agent);
- }
- if let Some(additional_browser_args) = &config.additional_browser_args {
- builder = builder.additional_browser_args(additional_browser_args);
- }
- if let Some(effects) = &config.window_effects {
- builder = builder.window_effects(effects.clone());
- }
- if let Some(url) = &config.proxy_url {
- builder = builder.proxy_url(url.to_owned());
- }
- builder
- }
- }
- impl WebviewAttributes {
- /// Initializes the default attributes for a webview.
- pub fn new(url: WebviewUrl) -> Self {
- Self {
- url,
- user_agent: None,
- initialization_scripts: Vec::new(),
- data_directory: None,
- file_drop_handler_enabled: true,
- clipboard: false,
- accept_first_mouse: false,
- additional_browser_args: None,
- window_effects: None,
- incognito: false,
- transparent: false,
- bounds: None,
- auto_resize: false,
- proxy_url: None,
- }
- }
- /// Sets the user agent
- #[must_use]
- pub fn user_agent(mut self, user_agent: &str) -> Self {
- self.user_agent = Some(user_agent.to_string());
- self
- }
- /// Sets the init script.
- #[must_use]
- pub fn initialization_script(mut self, script: &str) -> Self {
- self.initialization_scripts.push(script.to_string());
- self
- }
- /// Data directory for the webview.
- #[must_use]
- pub fn data_directory(mut self, data_directory: PathBuf) -> Self {
- self.data_directory.replace(data_directory);
- self
- }
- /// Disables the file drop handler. This is required to use drag and drop APIs on the front end on Windows.
- #[must_use]
- pub fn disable_file_drop_handler(mut self) -> Self {
- self.file_drop_handler_enabled = false;
- self
- }
- /// Enables clipboard access for the page rendered on **Linux** and **Windows**.
- ///
- /// **macOS** doesn't provide such method and is always enabled by default,
- /// but you still need to add menu item accelerators to use shortcuts.
- #[must_use]
- pub fn enable_clipboard_access(mut self) -> Self {
- self.clipboard = true;
- self
- }
- /// Sets whether clicking an inactive window also clicks through to the webview.
- #[must_use]
- pub fn accept_first_mouse(mut self, accept: bool) -> Self {
- self.accept_first_mouse = accept;
- self
- }
- /// Sets additional browser arguments. **Windows Only**
- #[must_use]
- pub fn additional_browser_args(mut self, additional_args: &str) -> Self {
- self.additional_browser_args = Some(additional_args.to_string());
- self
- }
- /// Sets window effects
- #[must_use]
- pub fn window_effects(mut self, effects: WindowEffectsConfig) -> Self {
- self.window_effects = Some(effects);
- self
- }
- /// Enable or disable incognito mode for the WebView.
- #[must_use]
- pub fn incognito(mut self, incognito: bool) -> Self {
- self.incognito = incognito;
- self
- }
- /// Enable or disable transparency for the WebView.
- #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
- #[must_use]
- pub fn transparent(mut self, transparent: bool) -> Self {
- self.transparent = transparent;
- self
- }
- /// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
- #[must_use]
- pub fn auto_resize(mut self) -> Self {
- self.auto_resize = true;
- self
- }
- /// Enable proxy for the WebView
- #[must_use]
- pub fn proxy_url(mut self, url: Url) -> Self {
- self.proxy_url = Some(url);
- self
- }
- }
- /// IPC handler.
- pub type WebviewIpcHandler<T, R> = Box<dyn Fn(DetachedWebview<T, R>, String) + Send>;
|