feat: 添加开机自启支持与开发版本提示
This commit is contained in:
@@ -195,6 +195,10 @@ pnpm dev
|
||||
|
||||
### 常用脚本
|
||||
|
||||
开机自启需要使用 `pnpm tauri build` 或 `pnpm tauri build --no-bundle` 生成的正式程序。正式程序内置前端资源,不依赖 Vite,Windows 下也不会弹出调试控制台。开发模式和 debug 构建不支持开启自启。
|
||||
|
||||
自启路径由插件动态获取当前运行的正式程序路径,不写死盘符、安装目录或项目构建目录。正式程序启动时,若已开启自启,会自动更新已有启动项的路径。因此重新安装或移动程序后,只需从新位置打开一次正式程序,即可校正旧路径;已关闭的自启不会被自动开启。
|
||||
|
||||
| 命令 | 说明 |
|
||||
| ------------------ | ----------------------------------------- |
|
||||
| `pnpm dev` | 启动 Vite 开发服务器(端口 `1420`) |
|
||||
|
||||
@@ -4,6 +4,21 @@
|
||||
|
||||
---
|
||||
|
||||
## v1.3.2(2026-10-22)
|
||||
|
||||
### 🐛 修复
|
||||
|
||||
- **开机自启路径动态校正**:自启项动态获取当前正式程序的 EXE 路径,不写死盘符、安装目录或项目构建目录。已开启自启时,正式程序启动后会自动更新已有启动项;重新安装或移动程序后,从新位置打开一次即可校正旧路径,已关闭的自启保持关闭。
|
||||
- **阻止开发版本注册自启**:开发模式及 debug 构建不再注册自启插件,避免将依赖 Vite 本地服务的开发程序写入启动项,导致重启后主界面显示 `ERR_CONNECTION_REFUSED`,并弹出调试控制台窗口。
|
||||
|
||||
### 🎨 优化
|
||||
|
||||
- **自启设置提示**:开发版本的自启开关自动置灰,并明确提示需要在正式构建中开启;同步补充简体中文与英文文案。
|
||||
|
||||
### 📝 文档
|
||||
|
||||
- README 补充正式构建的自启使用说明,以及重新安装或移动程序后的路径校正方式。
|
||||
|
||||
## v1.3.0(2026-10-20)
|
||||
|
||||
### ✨ 新增功能
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "frpcpilot",
|
||||
"private": true,
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -7,6 +7,12 @@ use tauri_helper::auto_collect_command;
|
||||
use crate::models::{ApiResponse, SystemDetails, SystemInfo};
|
||||
use crate::services::system::SystemStats;
|
||||
|
||||
#[tauri::command]
|
||||
#[auto_collect_command]
|
||||
pub fn is_autostart_supported() -> bool {
|
||||
!tauri::is_dev() && !cfg!(debug_assertions)
|
||||
}
|
||||
|
||||
/// 获取系统资源占用(CPU / 内存百分比)
|
||||
#[tauri::command]
|
||||
#[auto_collect_command]
|
||||
|
||||
+28
-6
@@ -3,6 +3,7 @@ mod models;
|
||||
mod services;
|
||||
|
||||
use tauri::{Manager, RunEvent};
|
||||
use tauri_plugin_autostart::ManagerExt as _;
|
||||
|
||||
use crate::commands::frp::{
|
||||
delete_frp, download_frp, get_frp_downloads, get_frp_releases, import_frp,
|
||||
@@ -12,7 +13,7 @@ use crate::commands::server::{
|
||||
create_server, delete_server, get_server_list, set_server_enabled, set_server_pinned,
|
||||
update_server,
|
||||
};
|
||||
use crate::commands::system::{get_system_details, get_system_info};
|
||||
use crate::commands::system::{get_system_details, get_system_info, is_autostart_supported};
|
||||
use crate::commands::tunnel::{
|
||||
create_tunnel, delete_tunnel, get_tunnel_list, set_tunnel_enabled, set_tunnel_pinned,
|
||||
update_tunnel,
|
||||
@@ -23,18 +24,39 @@ use crate::services::system::SystemStats;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let app = tauri::Builder::default()
|
||||
let mut builder = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_dialog::init()) // 对话框插件
|
||||
.plugin(tauri_plugin_updater::Builder::new().build()) // 更新插件
|
||||
.plugin(tauri_plugin_process::init()) // 进程插件(更新后重启)
|
||||
// 开机自启插件:读写系统启动项(Windows 注册表 Run 键 / macOS LaunchAgent / Linux XDG autostart)
|
||||
.plugin(tauri_plugin_autostart::init(
|
||||
.plugin(tauri_plugin_prevent_default::Builder::new().build());
|
||||
|
||||
// Development executables require Vite; debug builds also open a Windows console.
|
||||
if is_autostart_supported() {
|
||||
builder = builder.plugin(tauri_plugin_autostart::init(
|
||||
tauri_plugin_autostart::MacosLauncher::LaunchAgent,
|
||||
None,
|
||||
))
|
||||
.plugin(tauri_plugin_prevent_default::Builder::new().build())
|
||||
));
|
||||
}
|
||||
|
||||
let app = builder
|
||||
.setup(|app| {
|
||||
// The plugin resolves the running executable dynamically. Refresh enabled
|
||||
// entries after reinstalling or moving the app, preserving disabled state.
|
||||
if is_autostart_supported() {
|
||||
let autostart = app.autolaunch();
|
||||
let result = autostart.is_enabled().and_then(|enabled| {
|
||||
if enabled {
|
||||
autostart.enable()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
if let Err(error) = result {
|
||||
eprintln!("Failed to refresh autostart executable path: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
let pool = tauri::async_runtime::block_on(async {
|
||||
init_pool(app.handle())
|
||||
.await
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { isTauri } from "@/utils/window"
|
||||
import { invoke } from "@tauri-apps/api/core"
|
||||
|
||||
export async function isAutostartSupported(): Promise<boolean> {
|
||||
if (!isTauri()) return false
|
||||
return invoke<boolean>("is_autostart_supported")
|
||||
}
|
||||
|
||||
/**
|
||||
* 开机自启封装(Tauri 官方 autostart 插件)。
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
"autostart": "Launch at startup",
|
||||
"autostartTip": "Start FrpcPilot automatically after you sign in. The switch writes straight to the system startup entry.",
|
||||
"autostartUnsupported": "System startup entries are not accessible here, so this setting is unavailable.",
|
||||
"autostartRequiresRelease": "Enable launch at startup in a release build. Development builds require a local server and cannot run independently after a restart.",
|
||||
"autostartEnabled": "Launch at startup enabled",
|
||||
"autostartDisabled": "Launch at startup disabled",
|
||||
"autostartFailed": "Failed to update launch at startup: {message}",
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
"autostart": "开机自启",
|
||||
"autostartTip": "登录系统后自动启动 FrpcPilot,开关状态直接写入系统启动项",
|
||||
"autostartUnsupported": "当前环境无法读写系统启动项,暂不支持该设置",
|
||||
"autostartRequiresRelease": "请在正式构建的应用中开启自启;开发版本依赖本地服务,无法在重启后独立运行",
|
||||
"autostartEnabled": "已开启开机自启",
|
||||
"autostartDisabled": "已关闭开机自启",
|
||||
"autostartFailed": "设置开机自启失败:{message}",
|
||||
|
||||
+10
-3
@@ -1,7 +1,7 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { message } from "ant-design-vue"
|
||||
import { isTauri } from "@/utils/window"
|
||||
import { isAutostartEnabled, setAutostartEnabled } from "@/api/autostart"
|
||||
import { isAutostartEnabled, isAutostartSupported, setAutostartEnabled } from "@/api/autostart"
|
||||
import { translate } from "@/i18n"
|
||||
|
||||
/**
|
||||
@@ -17,7 +17,8 @@ export const useAutostartStore = defineStore("autostart", () => {
|
||||
/** 读取 / 写入系统启动项期间显示加载态,同时防止重复操作 */
|
||||
const loading = ref(isTauri())
|
||||
/** 当前环境能否读写系统启动项 */
|
||||
const supported = ref(isTauri())
|
||||
const supported = ref(false)
|
||||
const requiresRelease = ref(false)
|
||||
|
||||
function errMsg(e: unknown) {
|
||||
return e instanceof Error ? e.message : String(e)
|
||||
@@ -28,6 +29,12 @@ export const useAutostartStore = defineStore("autostart", () => {
|
||||
if (!isTauri()) return
|
||||
loading.value = true
|
||||
try {
|
||||
requiresRelease.value = !(await isAutostartSupported())
|
||||
if (requiresRelease.value) {
|
||||
enabled.value = false
|
||||
supported.value = false
|
||||
return
|
||||
}
|
||||
enabled.value = await isAutostartEnabled()
|
||||
supported.value = true
|
||||
} catch {
|
||||
@@ -61,5 +68,5 @@ export const useAutostartStore = defineStore("autostart", () => {
|
||||
}
|
||||
}
|
||||
|
||||
return { enabled, loading, supported, refresh, toggle }
|
||||
return { enabled, loading, supported, requiresRelease, refresh, toggle }
|
||||
})
|
||||
|
||||
@@ -81,9 +81,11 @@ const languageRadios = languageOptions.map((item) => ({ label: item.label, value
|
||||
|
||||
/** 无法访问系统启动项时(非桌面环境)给出说明,避免开关无故置灰 */
|
||||
const autostartTip = computed(() =>
|
||||
autostartStore.supported
|
||||
? t("settings.general.autostartTip")
|
||||
: t("settings.general.autostartUnsupported"),
|
||||
autostartStore.requiresRelease
|
||||
? t("settings.general.autostartRequiresRelease")
|
||||
: autostartStore.supported
|
||||
? t("settings.general.autostartTip")
|
||||
: t("settings.general.autostartUnsupported"),
|
||||
)
|
||||
|
||||
/** 切换开机自启:失败时由 store 回滚开关状态并提示原因 */
|
||||
|
||||
Reference in New Issue
Block a user