DEV Community

Rain9
Rain9

Posted on

2 1 1 2 1

Tauri (9) - Implementing automatic startup of desktop applications

Introduction

In many desktop applications, implementing the "launch at startup" feature is a common requirement, especially when the app needs to automatically start and stay running as soon as the operating system boots. This article will introduce how to implement the startup launch feature for desktop applications using Tauri.

Implementation Principle

Tauri provides the tauri-plugin-autostart plugin, allowing developers to easily configure applications to launch at startup. This plugin supports multiple operating systems (Windows, macOS, Linux) and provides simple APIs to manage the auto-start functionality.

Installing the Plugin

  1. Install the Plugin: To enable the startup launch feature, you need to install the tauri-plugin-autostart plugin in your Tauri project.

    Open the terminal in the project root directory and run the following command:

    cargo tauri plugin add tauri-plugin-autostart
    
  2. Configure Permissions: After installing the plugin, update the configuration in the src-tauri/capabilities/default.json file.

    Add the following to the permissions section in the src-tauri/capabilities/default.json file:

    {
      "$schema": "../gen/schemas/desktop-schema.json",
      "identifier": "default",
      "description": "Capability for the main window",
      "windows": ["main", "chat", "settings"],
      "permissions": [
        "autostart:allow-enable",
        "autostart:allow-disable",
        "autostart:allow-is-enabled"
      ]
    }
    

Rust Code Implementation

Implement the core functionality in src-tauri/src/autostart.rs:

use std::{fs::create_dir, io::Read};
use tauri::{Manager, Runtime};
use tauri_plugin_autostart::ManagerExt;

pub fn enable_autostart(app: &mut tauri::App) {
    use tauri_plugin_autostart::MacosLauncher;

    app.handle()
        .plugin(tauri_plugin_autostart::init(
            MacosLauncher::AppleScript,
            None,
        ))
        .unwrap();

    let autostart_manager = app.autolaunch();

    match (
        autostart_manager.is_enabled(),
        current_autostart(app.app_handle()),
    ) {
        (Ok(false), Ok(true)) => match autostart_manager.enable() {
            Ok(_) => println!("Autostart enabled successfully."),
            Err(err) => eprintln!("Failed to enable autostart: {}", err),
        },
        (Ok(true), Ok(false)) => match autostart_manager.disable() {
            Ok(_) => println!("Autostart disabled successfully."),
            Err(err) => eprintln!("Failed to disable autostart: {}", err),
        },
        _ => (),
    }
}

fn current_autostart<R: Runtime>(app: &tauri::AppHandle<R>) -> Result<bool, String> {
    use std::fs::File;

    let path = app.path().app_config_dir().unwrap();
    let mut old_value = true;

    if path.exists() {
        let file_path = path.join("autostart.txt");
        if file_path.exists() {
            let mut file = File::open(file_path).unwrap();
            let mut data = String::new();
            if let Ok(_) = file.read_to_string(&mut data) {
                if !data.is_empty() {
                    old_value = data.parse().unwrap_or(true);
                }
            }
        }
    };

    Ok(old_value)
}

#[tauri::command]
pub fn change_autostart<R: Runtime>(app: tauri::AppHandle<R>, open: bool) -> Result<(), String> {
    use std::fs::File;
    use std::io::Write;

    let autostart_manager = app.autolaunch();

    let change = |open: bool| -> Result<(), String> {
        let mut open_str = String::from("");
        if open {
            autostart_manager
                .enable()
                .map_err(|_| "enable autostart failed".to_owned())?;
            open_str = "true".to_owned();
        } else {
            autostart_manager
                .disable()
                .map_err(|_| "disable autostart failed".to_owned())?;
            open_str = "false".to_owned();
        }

        let path = app
            .path()
            .app_config_dir()
            .map_err(|_| "not found app config directory".to_owned())?;
        if !path.exists() {
            create_dir(&path).map_err(|_| "creating app config directory failed".to_owned())?;
        }

        let file_path = path.join("autostart.txt");
        let mut file = File::create(file_path).unwrap();
        file.write_all(open_str.as_bytes()).unwrap();

        Ok(())
    };

    match (autostart_manager.is_enabled().unwrap(), open) {
        (false, true) => change(true),
        (true, false) => change(false),
        _ => Err("no change".to_owned()),
    }
}
Enter fullscreen mode Exit fullscreen mode

Register the module in src-tauri/src/lib.rs:

mod autostart;

use autostart::{change_autostart, enable_autostart};
use tauri_plugin_autostart::MacosLauncher;

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    let mut ctx = tauri::generate_context!();

    tauri::Builder::default()
        .plugin(tauri_plugin_autostart::init(
            MacosLauncher::AppleScript,
            None,
        ))
        .invoke_handler(tauri::generate_handler![change_autostart])
        .setup(|app| {
            enable_autostart(app);
            Ok(())
        })
        .run(ctx)
        .expect("error while running tauri application");
}
Enter fullscreen mode Exit fullscreen mode

Frontend: Configuring Auto-Start

In the frontend, call the backend commands to toggle the startup launch status:

import { isTauri, invoke } from "@tauri-apps/api/core";
import { isEnabled } from "@tauri-apps/plugin-autostart";

const [launchAtLogin, setLaunchAtLogin] = useState(true);

useEffect(() => {
  const fetchAutoStartStatus = async () => {
    if (isTauri()) {
      try {
        const status = await isEnabled();
        setLaunchAtLogin(status);
      } catch (error) {
        console.error("Failed to fetch autostart status:", error);
      }
    }
  };

  fetchAutoStartStatus();
}, []);

const enableAutoStart = async () => {
  if (isTauri()) {
    try {
      invoke("change_autostart", { open: true });
    } catch (error) {
      console.error("Failed to enable autostart:", error);
    }
  }
  setLaunchAtLogin(true);
};

const disableAutoStart = async () => {
  if (isTauri()) {
    try {
      invoke("change_autostart", { open: false });
    } catch (error) {
      console.error("Failed to disable autostart:", error);
    }
  }
  setLaunchAtLogin(false);
};
Enter fullscreen mode Exit fullscreen mode

Conclusion

With the tauri-plugin-autostart plugin, implementing the "launch at startup" feature for Tauri apps becomes straightforward. The plugin supports multiple platforms, simplifying the cross-platform development of this functionality. By configuring and using Tauri's API, you can easily manage your app's auto-start status.

I hope this article helps you implement startup launch functionality for your Tauri desktop app. Feel free to discuss if you have any questions!

Open Source

Recently, I’ve been working on a project based on Tauri called Coco. It’s open source and under continuous improvement. I’d love your support—please give the project a free star 🌟!

This is my first Tauri project, and I’ve been learning while exploring. I look forward to connecting with like-minded individuals to share experiences and grow together!

Thank you for your support and attention!

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay