@@ -64,6 +64,7 @@ use std::{
64
64
pub ( crate ) type WebResourceRequestHandler =
65
65
dyn Fn ( http:: Request < Vec < u8 > > , & mut http:: Response < Cow < ' static , [ u8 ] > > ) + Send + Sync ;
66
66
pub ( crate ) type NavigationHandler = dyn Fn ( & Url ) -> bool + Send ;
67
+ pub ( crate ) type DownloadHandler < R > = dyn Fn ( Window < R > , DownloadEvent < ' _ > ) -> bool + Send + Sync ;
67
68
pub ( crate ) type UriSchemeProtocolHandler =
68
69
Box < dyn Fn ( http:: Request < Vec < u8 > > , UriSchemeResponder ) + Send + Sync > ;
69
70
pub ( crate ) type OnPageLoad < R > = dyn Fn ( Window < R > , PageLoadPayload < ' _ > ) + Send + Sync + ' static ;
@@ -92,6 +93,38 @@ impl<'a> PageLoadPayload<'a> {
92
93
}
93
94
}
94
95
96
+ /// Download event for the [`WindowBuilder#method.on_download`] hook.
97
+ #[ non_exhaustive]
98
+ pub enum DownloadEvent < ' a > {
99
+ /// Download requested.
100
+ Requested {
101
+ /// The url being downloaded.
102
+ url : Url ,
103
+ /// Represents where the file will be downloaded to.
104
+ /// Can be used to set the download location by assigning a new path to it.
105
+ /// The assigned path _must_ be absolute.
106
+ destination : & ' a mut PathBuf ,
107
+ } ,
108
+ /// Download finished.
109
+ Finished {
110
+ /// The URL of the original download request.
111
+ url : Url ,
112
+ /// Potentially representing the filesystem path the file was downloaded to.
113
+ ///
114
+ /// A value of `None` being passed instead of a `PathBuf` does not necessarily indicate that the download
115
+ /// did not succeed, and may instead indicate some other failure - always check the third parameter if you need to
116
+ /// know if the download succeeded.
117
+ ///
118
+ /// ## Platform-specific:
119
+ ///
120
+ /// - **macOS**: The second parameter indicating the path the file was saved to is always empty, due to API
121
+ /// limitations.
122
+ path : Option < PathBuf > ,
123
+ /// Indicates if the download succeeded or not.
124
+ success : bool ,
125
+ } ,
126
+ }
127
+
95
128
/// Monitor descriptor.
96
129
#[ derive( Debug , Clone , Serialize ) ]
97
130
#[ serde( rename_all = "camelCase" ) ]
@@ -149,6 +182,7 @@ pub struct WindowBuilder<'a, R: Runtime> {
149
182
pub ( crate ) webview_attributes : WebviewAttributes ,
150
183
web_resource_request_handler : Option < Box < WebResourceRequestHandler > > ,
151
184
navigation_handler : Option < Box < NavigationHandler > > ,
185
+ download_handler : Option < Arc < DownloadHandler < R > > > ,
152
186
on_page_load_handler : Option < Box < OnPageLoad < R > > > ,
153
187
#[ cfg( desktop) ]
154
188
on_menu_event : Option < crate :: app:: GlobalMenuEventListener < Window < R > > > ,
@@ -228,6 +262,7 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
228
262
webview_attributes : WebviewAttributes :: new ( url) ,
229
263
web_resource_request_handler : None ,
230
264
navigation_handler : None ,
265
+ download_handler : None ,
231
266
on_page_load_handler : None ,
232
267
#[ cfg( desktop) ]
233
268
on_menu_event : None ,
@@ -267,6 +302,7 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
267
302
window_builder : <R :: Dispatcher as Dispatch < EventLoopMessage > >:: WindowBuilder :: with_config (
268
303
config,
269
304
) ,
305
+ download_handler : None ,
270
306
web_resource_request_handler : None ,
271
307
#[ cfg( desktop) ]
272
308
menu : None ,
@@ -353,6 +389,47 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
353
389
self
354
390
}
355
391
392
+ /// Set a download event handler to be notified when a download is requested or finished.
393
+ ///
394
+ /// Returning `false` prevents the download from happening on a [`DownloadEvent::Requested`] event.
395
+ ///
396
+ /// # Examples
397
+ ///
398
+ /// ```rust,no_run
399
+ /// use tauri::{
400
+ /// utils::config::{Csp, CspDirectiveSources, WindowUrl},
401
+ /// window::{DownloadEvent, WindowBuilder},
402
+ /// };
403
+ ///
404
+ /// tauri::Builder::default()
405
+ /// .setup(|app| {
406
+ /// WindowBuilder::new(app, "core", WindowUrl::App("index.html".into()))
407
+ /// .on_download(|window, event| {
408
+ /// match event {
409
+ /// DownloadEvent::Requested { url, destination } => {
410
+ /// println!("downloading {}", url);
411
+ /// *destination = "/home/tauri/target/path".into();
412
+ /// }
413
+ /// DownloadEvent::Finished { url, path, success } => {
414
+ /// println!("downloaded {} to {:?}, success: {}", url, path, success);
415
+ /// }
416
+ /// _ => (),
417
+ /// }
418
+ /// // let the download start
419
+ /// true
420
+ /// })
421
+ /// .build()?;
422
+ /// Ok(())
423
+ /// });
424
+ /// ```
425
+ pub fn on_download < F : Fn ( Window < R > , DownloadEvent < ' _ > ) -> bool + Send + Sync + ' static > (
426
+ mut self ,
427
+ f : F ,
428
+ ) -> Self {
429
+ self . download_handler . replace ( Arc :: new ( f) ) ;
430
+ self
431
+ }
432
+
356
433
/// Defines a closure to be executed when a page load event is triggered.
357
434
/// The event can be either [`PageLoadEvent::Started`] if the page has started loading
358
435
/// or [`PageLoadEvent::Finished`] when the page finishes loading.
@@ -361,18 +438,16 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
361
438
///
362
439
/// ```rust,no_run
363
440
/// use tauri::{
364
- /// utils::config::{Csp, CspDirectiveSources, WindowUrl} ,
441
+ /// utils::config::WindowUrl,
365
442
/// window::{PageLoadEvent, WindowBuilder},
366
443
/// };
367
- /// use http::header::HeaderValue;
368
- /// use std::collections::HashMap;
369
444
/// tauri::Builder::default()
370
445
/// .setup(|app| {
371
446
/// WindowBuilder::new(app, "core", WindowUrl::App("index.html".into()))
372
447
/// .on_page_load(|window, payload| {
373
448
/// match payload.event() {
374
449
/// PageLoadEvent::Started => {
375
- /// println!("{} finished loading", payload.url());
450
+ /// println!("{} started loading", payload.url());
376
451
/// }
377
452
/// PageLoadEvent::Finished => {
378
453
/// println!("{} finished loading", payload.url());
@@ -444,6 +519,28 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
444
519
pending. navigation_handler = self . navigation_handler . take ( ) ;
445
520
pending. web_resource_request_handler = self . web_resource_request_handler . take ( ) ;
446
521
522
+ if let Some ( download_handler) = self . download_handler . take ( ) {
523
+ let label = pending. label . clone ( ) ;
524
+ let manager = self . app_handle . manager . clone ( ) ;
525
+ pending. download_handler . replace ( Arc :: new ( move |event| {
526
+ if let Some ( w) = manager. get_window ( & label) {
527
+ download_handler (
528
+ w,
529
+ match event {
530
+ tauri_runtime:: window:: DownloadEvent :: Requested { url, destination } => {
531
+ DownloadEvent :: Requested { url, destination }
532
+ }
533
+ tauri_runtime:: window:: DownloadEvent :: Finished { url, path, success } => {
534
+ DownloadEvent :: Finished { url, path, success }
535
+ }
536
+ } ,
537
+ )
538
+ } else {
539
+ false
540
+ }
541
+ } ) ) ;
542
+ }
543
+
447
544
if let Some ( on_page_load_handler) = self . on_page_load_handler . take ( ) {
448
545
let label = pending. label . clone ( ) ;
449
546
let manager = self . app_handle . manager . clone ( ) ;
0 commit comments