DEV Community

Rain9
Rain9

Posted on

1 1 1 1 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!

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

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

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay