tauri-apps/tauri

[bug] App::restart does not restart after update.download_and_install in rust

jacobbuck72 opened this issue · 0 comments

Describe the bug

When a new version on macOS has been downloaded and installed the app closes down but does not start again.

It is a desktop app for macOS and Windows. It has a main window that the user can close/hide while the icon tray remains. So on WindowEvent::CloseRequested we prevent closing the app. Could this cause the issue?

We just migrated to Tauri 2 so had to provide our own dialog (see updater.rs below) and doing version check and triggering download, install and restart (which fails on macOS).

The app is built with our self hosted GitLab CI/CD pipeline producing a static updater.json uploaded to S3 together with the artefacts:

{
    "version": "#VERSION",
    "notes": "",
    "pub_date": "#PUB_TIME",
    "platforms": {
        "universal-apple-darwin": {
            "signature": "#UNIVERSAL_APPLE_DARWIN_SIGNATURE",
            "url": "https://autoremind-app.xxx/release/autoremind-app.app.tar.gz"
        },
    }
}

Important part of my main.rs:

use tauri::{ Builder, Manager, Window, WindowEvent, WebviewWindowBuilder, WebviewUrl};

#[path = "updater.rs"]
mod updater;

fn main() {
    let context = tauri::generate_context!();
    let url = format!("http://localhost:{}", BUILD_PORT).parse().unwrap();
    let window_url = WebviewUrl::External(url);

    //let app2 = tauri::Builder::default()
    Builder::default()
        .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
            println!("Trying to open another instance");
            let window = app.get_webview_window("main")
                .expect("no main window");
            window.show().map_err(|err| println!("{:?}", err)).ok();
            let _ = window.set_focus();
        }))
        .plugin(tauri_plugin_localhost::Builder::new(BUILD_PORT).build())
        .plugin(tauri_plugin_updater::Builder::new().build())
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_process::init())
        .setup(|app| {
            WebviewWindowBuilder::new(
                app,
                "main".to_string(),
                if cfg!(dev) {
                    Default::default()
                } else {
                    window_url
                },
            )
                .title(MAIN_WINDOW_TITLE)
                .position(30.0, 30.0)
                .inner_size(800.0, 650.0)
                .initialization_script(&pass_app_environment_to_window())
                .build()?;

            menubar::build_tray_and_menus(app);

            badge::set_badge(app.handle(), 5);

            updater::init(&app);
            Ok(())
        })
        .on_window_event(handle_window_event)
        //.enable_macos_default_menu(false)
        .invoke_handler(tauri::generate_handler![
            open_two_way,
            close_two_way,
            set_badge
        ])
        //.build(context)  // in this case app.run() below is needed
        .run(context)
        .expect("error while running tauri application");
}

fn handle_window_event(window: &Window, event: &WindowEvent) {
    match event {
        WindowEvent::CloseRequested { api, .. } => {
            api.prevent_close(); // We want the icon tray to remain after closing main window
            window.hide().unwrap();
        }
        _ => {}
    }
}

I have created updater.rs:

use tauri::App;
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons};
use tauri_plugin_updater::UpdaterExt;

pub fn init(app: &App) {
    let handle = app.handle().clone();
    tauri::async_runtime::spawn(async move {
        let _response = update_setup(handle).await;
    });
}

async fn update_setup(app: tauri::AppHandle) -> tauri::Result<()> {
  if let Some(update) = app.updater().unwrap().check().await.unwrap() {

    let current_version = app.package_info().version.to_string();
    let new_version = update.version.to_string();

    app.dialog()
        .message(&format!("Version {new_version} is now available -- you have {current_version}. \nWould you like to install it now?"))
        .title("A new version of AutoRemind App is available")
        .buttons(MessageDialogButtons::OkCancelCustom("Yes".to_string(), "No".to_string()))
        .show(|result| match result {
            false => {
                println!("Ignored update");
                },
            true => {
                tauri::async_runtime::spawn(async move {
                    let mut downloaded = 0;
                    update.download_and_install(|chunk_length, content_length| {
                        downloaded += chunk_length;
                        println!("downloaded {downloaded} / {content_length:?}");
                    }, || {
                        println!("download finished");
                    }).await.unwrap();

                    println!("update installed. Restarting.");
                    app.restart(); // This shuts down but does not not relaunch new version
            });
        }
    });
  }

  Ok(())
}

capabilities/main.json

{
    "$schema": "./schemas/desktop-schema.json",
    "identifier": "main-capability",
    "description": "Capability for the main window",
    "windows": ["main"],
    "local": false,
    "remote": {
        "urls": ["http://localhost:4000/", "http://localhost:4200/"]
    },
    "permissions": [
        "core:event:allow-emit",
        "core:event:allow-listen",
        "core:window:allow-set-resizable",
        "core:window:allow-set-size",
        "core:webview:allow-internal-toggle-devtools",
        "updater:allow-check",
        "updater:allow-download",
        "updater:allow-download-and-install",
        "updater:allow-install",
        "process:default",
        "process:allow-exit",
        "process:allow-restart"
    ]
}

Important parts of tauri.config.json:

{
    "productName": "AutoRemind App",
    "mainBinaryName": "AutoRemind App",
    "version": "0.1.10000", //replaced by the CI/CD script
    "identifier": "com.autoremind.app",
    "bundle": {
        "active": true,
        "externalBin": [],
        "targets": [
            "nsis",
            "dmg",
            "app"
        ],
        "macOS": {
            "entitlements": null,
            "exceptionDomain": "",
            "frameworks": [],
            "providerShortName": null,
            "signingIdentity": "Developer ID Application: AutoRemind Inc (XXXXXXXX)"
        },
        "resources": [],
        "createUpdaterArtifacts": true
    },
    "app": {
        "windows": [],
        "security": {
            "csp": null
        }
    },
    "plugins": {
        "updater": {
            "endpoints": [
                "https://autoremind-app.xxx/updater.json"
            ],
            "windows": {
                "installMode": "passive"
            },
            "pubkey": "XXXXXXXXXXXX"
        }
    }
}

zx

Reproduction

I have not tried building a simple app since this would require a full CI pipeline and new S3 bucket to test. But it's the same every time I do this:

  1. Let our GitLab CI pipeline build a new set of artefacts (DMG and .app.tar.gz file with .app.tar.sig file), create new updater.json file and upload all to S3 - version 1
  2. Build a newer version 2
  3. Download version 1 DMG and install (move app to Applications)
  4. Launch the application clicking on the app in Applications
  5. Accept dialog asking me to upgrade to version 2
  6. Observe the app closing (but not starting again)
  7. Manually launch the app from Applications and observe (in an About dialog) that it's on version 2

Expected behavior

After installing the update the app should start again.

Full tauri info output

[✔] Environment
    - OS: Mac OS 14.6.1 arm64 (X64)
    ✔ Xcode Command Line Tools: installed
    ✔ rustc: 1.81.0 (eeb90cda1 2024-09-04)
    ✔ cargo: 1.81.0 (2dbb1af80 2024-08-20)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-aarch64-apple-darwin (default)
    - node: 22.3.0
    - pnpm: 9.7.0
    - npm: 10.8.1

[-] Packages
    - tauri 🦀: 2.0.2
    - tauri-build 🦀: 2.0.1
    - wry 🦀: 0.44.1
    - tao 🦀: 0.30.3

[-] Plugins
    - tauri-plugin-fs 🦀: 2.0.1
    - tauri-plugin-process 🦀: 2.0.1
    - tauri-plugin-updater 🦀: 2.0.2
    - tauri-plugin-localhost 🦀: 2.0.1
    - tauri-plugin-dialog 🦀: 2.0.1
    - tauri-plugin-single-instance 🦀: 2.0.1

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../dist/apps/portal-desktop/.next
    - devUrl: http://localhost:4200/

Stack trace

I do not know how to produce a stack trace. I've built a version with --debug and launched from Termial with RUST_LOG=debug (also tested with "trace") and got no errors or exceptions - only the app printing that it was restarting. This is the last I see:

downloaded 30171747 / Some(30203582)
downloaded 30188131 / Some(30203582)
downloaded 30203582 / Some(30203582)
download finished
update installed. Restarting.

Additional context

No response