Skip to content

Commit c4ca80f

Browse files
authored
feat(core): use AppHandle instead of Window on the updater logic (#3702)
1 parent 5d538ec commit c4ca80f

File tree

3 files changed

+75
-77
lines changed

3 files changed

+75
-77
lines changed

.changes/updater-no-window.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
Run the updater on startup even if no window was created.

core/tauri/src/app.rs

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -567,54 +567,54 @@ impl<R: Runtime> App<R> {
567567
#[cfg(feature = "updater")]
568568
impl<R: Runtime> App<R> {
569569
/// Runs the updater hook with built-in dialog.
570-
fn run_updater_dialog(&self, window: Window<R>) {
570+
fn run_updater_dialog(&self) {
571571
let updater_config = self.manager.config().tauri.updater.clone();
572572
let package_info = self.manager.package_info().clone();
573+
let handle = self.handle();
573574

574575
crate::async_runtime::spawn(async move {
575-
updater::check_update_with_dialog(updater_config, package_info, window).await
576+
updater::check_update_with_dialog(updater_config, package_info, handle).await
576577
});
577578
}
578579

579580
/// Listen updater events when dialog are disabled.
580-
fn listen_updater_events(&self, window: Window<R>) {
581+
fn listen_updater_events(&self, handle: AppHandle<R>) {
581582
let updater_config = self.manager.config().tauri.updater.clone();
582-
updater::listener(updater_config, self.manager.package_info().clone(), &window);
583+
updater::listener(updater_config, self.manager.package_info().clone(), &handle);
583584
}
584585

585-
fn run_updater(&self, main_window: Option<Window<R>>) {
586-
if let Some(main_window) = main_window {
587-
let event_window = main_window.clone();
588-
let updater_config = self.manager.config().tauri.updater.clone();
589-
// check if updater is active or not
590-
if updater_config.dialog && updater_config.active {
591-
// if updater dialog is enabled spawn a new task
592-
self.run_updater_dialog(main_window.clone());
593-
let config = self.manager.config().tauri.updater.clone();
594-
let package_info = self.manager.package_info().clone();
595-
// When dialog is enabled, if user want to recheck
596-
// if an update is available after first start
597-
// invoke the Event `tauri://update` from JS or rust side.
598-
main_window.listen(updater::EVENT_CHECK_UPDATE, move |_msg| {
599-
let window = event_window.clone();
600-
let package_info = package_info.clone();
601-
let config = config.clone();
602-
// re-spawn task inside tokyo to launch the download
603-
// we don't need to emit anything as everything is handled
604-
// by the process (user is asked to restart at the end)
605-
// and it's handled by the updater
606-
crate::async_runtime::spawn(async move {
607-
updater::check_update_with_dialog(config, package_info, window).await
608-
});
586+
fn run_updater(&self) {
587+
let handle = self.handle();
588+
let handle_ = handle.clone();
589+
let updater_config = self.manager.config().tauri.updater.clone();
590+
// check if updater is active or not
591+
if updater_config.dialog && updater_config.active {
592+
// if updater dialog is enabled spawn a new task
593+
self.run_updater_dialog();
594+
let config = self.manager.config().tauri.updater.clone();
595+
let package_info = self.manager.package_info().clone();
596+
// When dialog is enabled, if user want to recheck
597+
// if an update is available after first start
598+
// invoke the Event `tauri://update` from JS or rust side.
599+
handle.listen_global(updater::EVENT_CHECK_UPDATE, move |_msg| {
600+
let handle = handle_.clone();
601+
let package_info = package_info.clone();
602+
let config = config.clone();
603+
// re-spawn task inside tokyo to launch the download
604+
// we don't need to emit anything as everything is handled
605+
// by the process (user is asked to restart at the end)
606+
// and it's handled by the updater
607+
crate::async_runtime::spawn(async move {
608+
updater::check_update_with_dialog(config, package_info, handle).await
609609
});
610-
} else if updater_config.active {
611-
// we only listen for `tauri://update`
612-
// once we receive the call, we check if an update is available or not
613-
// if there is a new update we emit `tauri://update-available` with details
614-
// this is the user responsabilities to display dialog and ask if user want to install
615-
// to install the update you need to invoke the Event `tauri://update-install`
616-
self.listen_updater_events(main_window);
617-
}
610+
});
611+
} else if updater_config.active {
612+
// we only listen for `tauri://update`
613+
// once we receive the call, we check if an update is available or not
614+
// if there is a new update we emit `tauri://update-available` with details
615+
// this is the user responsabilities to display dialog and ask if user want to install
616+
// to install the update you need to invoke the Event `tauri://update-install`
617+
self.listen_updater_events(handle);
618618
}
619619
}
620620
}
@@ -1330,26 +1330,19 @@ impl<R: Runtime> Builder<R> {
13301330
.map(|p| p.label.clone())
13311331
.collect::<Vec<_>>();
13321332

1333-
#[cfg(feature = "updater")]
1334-
let mut main_window = None;
1335-
13361333
for pending in self.pending_windows {
13371334
let pending =
13381335
app
13391336
.manager
13401337
.prepare_window(app.handle.clone(), pending, &window_labels, None)?;
13411338
let detached = app.runtime.as_ref().unwrap().create_window(pending)?;
13421339
let _window = app.manager.attach_window(app.handle(), detached);
1343-
#[cfg(feature = "updater")]
1344-
if main_window.is_none() {
1345-
main_window = Some(_window);
1346-
}
13471340
}
13481341

13491342
(self.setup)(&mut app).map_err(|e| crate::Error::Setup(e))?;
13501343

13511344
#[cfg(feature = "updater")]
1352-
app.run_updater(main_window);
1345+
app.run_updater();
13531346

13541347
Ok(app)
13551348
}

core/tauri/src/updater/mod.rs

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,8 @@ mod error;
333333
pub use self::error::Error;
334334

335335
use crate::{
336-
api::dialog::blocking::ask, runtime::EventLoopProxy, utils::config::UpdaterConfig, Env,
337-
EventLoopMessage, Manager, Runtime, UpdaterEvent, Window,
336+
api::dialog::blocking::ask, runtime::EventLoopProxy, utils::config::UpdaterConfig, AppHandle,
337+
Env, EventLoopMessage, Manager, Runtime, UpdaterEvent,
338338
};
339339

340340
/// Check for new updates
@@ -374,14 +374,14 @@ struct UpdateManifest {
374374
pub(crate) async fn check_update_with_dialog<R: Runtime>(
375375
updater_config: UpdaterConfig,
376376
package_info: crate::PackageInfo,
377-
window: Window<R>,
377+
handle: AppHandle<R>,
378378
) {
379379
if let Some(endpoints) = updater_config.endpoints.clone() {
380380
let endpoints = endpoints
381381
.iter()
382382
.map(|e| e.to_string())
383383
.collect::<Vec<String>>();
384-
let env = window.state::<Env>().inner().clone();
384+
let env = handle.state::<Env>().inner().clone();
385385
// check updates
386386
match self::core::builder(env)
387387
.urls(&endpoints[..])
@@ -395,9 +395,9 @@ pub(crate) async fn check_update_with_dialog<R: Runtime>(
395395
// if dialog enabled only
396396
if updater.should_update && updater_config.dialog {
397397
let body = updater.body.clone().unwrap_or_else(|| String::from(""));
398-
let window_ = window.clone();
398+
let handle_ = handle.clone();
399399
let dialog = prompt_for_install(
400-
window_,
400+
handle_,
401401
&updater.clone(),
402402
&package_info.name,
403403
&body.clone(),
@@ -406,12 +406,12 @@ pub(crate) async fn check_update_with_dialog<R: Runtime>(
406406
.await;
407407

408408
if let Err(e) = dialog {
409-
send_status_update(window.clone(), UpdaterEvent::Error(e.to_string()));
409+
send_status_update(&handle, UpdaterEvent::Error(e.to_string()));
410410
}
411411
}
412412
}
413413
Err(e) => {
414-
send_status_update(window.clone(), UpdaterEvent::Error(e.to_string()));
414+
send_status_update(&handle, UpdaterEvent::Error(e.to_string()));
415415
}
416416
}
417417
}
@@ -422,13 +422,13 @@ pub(crate) async fn check_update_with_dialog<R: Runtime>(
422422
pub(crate) fn listener<R: Runtime>(
423423
updater_config: UpdaterConfig,
424424
package_info: crate::PackageInfo,
425-
window: &Window<R>,
425+
handle: &AppHandle<R>,
426426
) {
427-
let isolated_window = window.clone();
427+
let handle_ = handle.clone();
428428

429429
// Wait to receive the event `"tauri://update"`
430-
window.listen(EVENT_CHECK_UPDATE, move |_msg| {
431-
let window = isolated_window.clone();
430+
handle.listen_global(EVENT_CHECK_UPDATE, move |_msg| {
431+
let handle = handle_.clone();
432432
let package_info = package_info.clone();
433433

434434
// prepare our endpoints
@@ -444,10 +444,10 @@ pub(crate) fn listener<R: Runtime>(
444444

445445
// check updates
446446
crate::async_runtime::spawn(async move {
447-
let window = window.clone();
448-
let window_isolation = window.clone();
447+
let handle = handle.clone();
448+
let handle_ = handle.clone();
449449
let pubkey = pubkey.clone();
450-
let env = window.state::<Env>().inner().clone();
450+
let env = handle.state::<Env>().inner().clone();
451451

452452
match self::core::builder(env)
453453
.urls(&endpoints[..])
@@ -461,28 +461,27 @@ pub(crate) fn listener<R: Runtime>(
461461
let body = updater.body.clone().unwrap_or_else(|| String::from(""));
462462

463463
// Emit `tauri://update-available`
464-
let _ = window.emit(
464+
let _ = handle.emit_all(
465465
EVENT_UPDATE_AVAILABLE,
466466
UpdateManifest {
467467
body,
468468
date: updater.date.clone(),
469469
version: updater.version.clone(),
470470
},
471471
);
472-
let _ = window
473-
.app_handle
472+
let _ = handle
474473
.create_proxy()
475474
.send_event(EventLoopMessage::Updater(UpdaterEvent::UpdateAvailable));
476475

477476
// Listen for `tauri://update-install`
478-
window.once(EVENT_INSTALL_UPDATE, move |_msg| {
479-
let window = window_isolation.clone();
477+
handle.once_global(EVENT_INSTALL_UPDATE, move |_msg| {
478+
let handle = handle_.clone();
480479
let updater = updater.clone();
481480

482481
// Start installation
483482
crate::async_runtime::spawn(async move {
484483
// emit {"status": "PENDING"}
485-
send_status_update(window.clone(), UpdaterEvent::Pending);
484+
send_status_update(&handle, UpdaterEvent::Pending);
486485

487486
// Launch updater download process
488487
// macOS we display the `Ready to restart dialog` asking to restart
@@ -492,28 +491,28 @@ pub(crate) fn listener<R: Runtime>(
492491

493492
if let Err(err) = update_result {
494493
// emit {"status": "ERROR", "error": "The error message"}
495-
send_status_update(window.clone(), UpdaterEvent::Error(err.to_string()));
494+
send_status_update(&handle, UpdaterEvent::Error(err.to_string()));
496495
} else {
497496
// emit {"status": "DONE"}
498-
send_status_update(window.clone(), UpdaterEvent::Updated);
497+
send_status_update(&handle, UpdaterEvent::Updated);
499498
}
500499
});
501500
});
502501
} else {
503-
send_status_update(window.clone(), UpdaterEvent::AlreadyUpToDate);
502+
send_status_update(&handle, UpdaterEvent::AlreadyUpToDate);
504503
}
505504
}
506505
Err(e) => {
507-
send_status_update(window.clone(), UpdaterEvent::Error(e.to_string()));
506+
send_status_update(&handle, UpdaterEvent::Error(e.to_string()));
508507
}
509508
}
510509
});
511510
});
512511
}
513512

514513
// Send a status update via `tauri://update-status` event.
515-
fn send_status_update<R: Runtime>(window: Window<R>, message: UpdaterEvent) {
516-
let _ = window.emit(
514+
fn send_status_update<R: Runtime>(handle: &AppHandle<R>, message: UpdaterEvent) {
515+
let _ = handle.emit_all(
517516
EVENT_STATUS_UPDATE,
518517
if let UpdaterEvent::Error(error) = &message {
519518
StatusEvent {
@@ -527,28 +526,29 @@ fn send_status_update<R: Runtime>(window: Window<R>, message: UpdaterEvent) {
527526
}
528527
},
529528
);
530-
let _ = window
531-
.app_handle
529+
let _ = handle
532530
.create_proxy()
533531
.send_event(EventLoopMessage::Updater(message));
534532
}
535533

536534
// Prompt a dialog asking if the user want to install the new version
537535
// Maybe we should add an option to customize it in future versions.
538536
async fn prompt_for_install<R: Runtime>(
539-
window: Window<R>,
537+
handle: AppHandle<R>,
540538
updater: &self::core::Update,
541539
app_name: &str,
542540
body: &str,
543541
pubkey: String,
544542
) -> crate::Result<()> {
545543
// remove single & double quote
546544
let escaped_body = body.replace(&['\"', '\''][..], "");
545+
let windows = handle.windows();
546+
let parent_window = windows.values().next();
547547

548548
// todo(lemarier): We should review this and make sure we have
549549
// something more conventional.
550550
let should_install = ask(
551-
Some(&window),
551+
parent_window,
552552
format!(r#"A new version of {} is available! "#, app_name),
553553
format!(
554554
r#"{} {} is now available -- you have {}.
@@ -570,12 +570,12 @@ Release Notes:
570570

571571
// Ask user if we need to restart the application
572572
let should_exit = ask(
573-
Some(&window),
573+
parent_window,
574574
"Ready to Restart",
575575
"The installation was successful, do you want to restart the application now?",
576576
);
577577
if should_exit {
578-
window.app_handle().restart();
578+
handle.restart();
579579
}
580580
}
581581

0 commit comments

Comments
 (0)