Tauri 2.0跨端開發:2026年從桌面到移動端的統一框架
开发教程
Tauri 2.0:一套程式碼,六個平台
Tauri 2.0最大的突破是從桌面端擴展到移動端。現在你可以用同一套Rust後端+Web前端,同時構建Windows、macOS、Linux、iOS、Android五個平台的應用。
對比資料:同功能應用,Tauri 2.0包體積8MB vs Electron 150MB,記憶體佔用45MB vs 280MB,啟動速度0.3s vs 2.5s。
Tauri vs Electron 全面對比
| 維度 | Tauri 2.0 | Electron |
|---|---|---|
| 包體積 | 5-15MB | 100-200MB |
| 記憶體佔用 | 30-60MB | 200-400MB |
| 啟動速度 | 0.2-0.5s | 1.5-3s |
| 後端語言 | Rust | Node.js |
| WebView | 系統原生 | 內建Chromium |
| 移動端支援 | iOS/Android | 不支援 |
| 原生能力 | Rust FFI | Node.js N-API |
| 安全模型 | 權限沙箱 | 完整Node.js |
| 生態成熟度 | 成長中 | 成熟 |
Tauri 2.0新架構
┌──────────────────────────────────────────────────────┐
│ Web前端層 │
│ React / Vue / Svelte / Vanilla JS │
├──────────────────────────────────────────────────────┤
│ IPC通訊層 │
│ invoke() / listen() / emit() │
├──────────────────────────────────────────────────────┤
│ Tauri Core │
│ ┌──────────┬──────────┬──────────┬───────────────┐ │
│ │ 視窗管理 │ 外掛系統 │ 事件系統 │ 權限管理 │ │
│ ├──────────┴──────────┴──────────┴───────────────┤ │
│ │ 命令處理器(Commands) │ │
│ ├─────────────────────────────────────────────────┤ │
│ │ 平台適配層 │ │
│ │ Windows │ macOS │ Linux │ iOS │ Android │ │
│ └─────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────┤
│ Rust後端層 │
│ 業務邏輯 │ 檔案操作 │ 網路請求 │ 加密解密 │
└──────────────────────────────────────────────────────┘
Rust後端 + Web前端的IPC通訊
前端呼叫Rust命令
// src-tauri/src/commands.rs
#[tauri::command]
async fn process_image(image_path: String, options: ProcessOptions) -> Result<ProcessResult, String> {
let img = image::open(&image_path)
.map_err(|e| format!("無法開啟圖片: {}", e))?;
let processed = match options.operation.as_str() {
"compress" => compress_image(img, options.quality)?,
"resize" => resize_image(img, options.width, options.height)?,
"convert" => convert_format(img, options.format)?,
_ => return Err("不支援的操作".to_string()),
};
let output_path = save_processed_image(processed, &options.output_dir)?;
Ok(ProcessResult {
output_path,
file_size: fs::metadata(&output_path)?.len(),
})
}
#[tauri::command]
fn get_system_info() -> SystemInfo {
SystemInfo {
os: System::os(),
arch: System::arch(),
memory: System::total_memory(),
cpu_count: System::cpu_count(),
}
}
// 前端呼叫
import { invoke } from "@tauri-apps/api/core";
async function processImage() {
const result = await invoke<ProcessResult>("process_image", {
imagePath: "/path/to/image.png",
options: {
operation: "compress",
quality: 80,
outputDir: "/path/to/output",
},
});
console.log(`處理完成: ${result.output_path}, 大小: ${result.file_size}`);
}
事件通訊
// Rust端發送事件
use tauri::Emitter;
#[tauri::command]
async fn start_batch_process(app: tauri::AppHandle, files: Vec<String>) -> Result<(), String> {
for (index, file) in files.iter().enumerate() {
process_single_file(file)?;
app.emit("batch-progress", BatchProgress {
current: index + 1,
total: files.len(),
file: file.clone(),
}).map_err(|e| e.to_string())?;
}
Ok(())
}
// 前端監聽事件
import { listen } from "@tauri-apps/api/event";
const unlisten = await listen<BatchProgress>("batch-progress", (event) => {
console.log(`進度: ${event.payload.current}/${event.payload.total}`);
updateProgressBar(event.payload.current / event.payload.total);
});
// 處理完成後取消監聽
unlisten();
Tauri外掛系統
常用官方外掛
| 外掛 | 功能 | 支援平台 |
|---|---|---|
| @tauri-apps/plugin-fs | 檔案系統讀寫 | 全平台 |
| @tauri-apps/plugin-notification | 系統通知 | 全平台 |
| @tauri-apps/plugin-clipboard | 剪貼簿操作 | 全平台 |
| @tauri-apps/plugin-biometric | 生物識別 | iOS/Android/macOS |
| @tauri-apps/plugin-camera | 相機存取 | iOS/Android |
| @tauri-apps/plugin-geolocation | 地理定位 | iOS/Android |
| @tauri-apps/plugin-barcode-scanner | 條碼掃描 | iOS/Android |
| @tauri-apps/plugin-store | 本地持久化儲存 | 全平台 |
自訂外掛開發
// plugins/my-plugin/src/lib.rs
use tauri::{
plugin::{Builder, TauriPlugin},
AppHandle, Runtime,
};
#[tauri::command]
async fn encrypt_data(app: AppHandle<Runtime>, data: String, key: String) -> Result<String, String> {
let encrypted = aes_encrypt(data.as_bytes(), key.as_bytes())
.map_err(|e| format!("加密失敗: {}", e))?;
Ok(base64::encode(&encrypted))
}
#[tauri::command]
async fn decrypt_data(app: AppHandle<Runtime>, data: String, key: String) -> Result<String, String> {
let decoded = base64::decode(&data).map_err(|e| format!("Base64解碼失敗: {}", e))?;
let decrypted = aes_decrypt(&decoded, key.as_bytes())
.map_err(|e| format!("解密失敗: {}", e))?;
Ok(String::from_utf8(decrypted).map_err(|e| e.to_string())?)
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("my-encrypt")
.invoke_handler(tauri::generate_handler![encrypt_data, decrypt_data])
.build()
}
移動端適配
iOS/Android的原生能力呼叫
// 移動端條件邏輯
import { platform } from "@tauri-apps/plugin-os";
async function shareContent(content: string) {
if (platform() === "ios" || platform() === "android") {
const { share } = await import("@tauri-apps/plugin-share");
await share({
text: content,
title: "分享",
});
} else {
await navigator.clipboard.writeText(content);
showToast("已複製到剪貼簿");
}
}
async function authenticateUser() {
if (platform() === "ios" || platform() === "android") {
const { authenticate } = await import("@tauri-apps/plugin-biometric");
const result = await authenticate({
reason: "請驗證身份以繼續操作",
fallbackToPin: true,
});
return result.isAuthenticated;
}
return true;
}
移動端UI適配
/* 響應式佈局適配移動端 */
.app-container {
display: grid;
grid-template-columns: 280px 1fr;
gap: 1rem;
height: 100vh;
}
@media (max-width: 768px) {
.app-container {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
}
.sidebar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 60px;
z-index: 100;
display: flex;
flex-direction: row;
overflow-x: auto;
}
}
/* 安全區域適配(劉海屏/底部橫條) */
.toolbar {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
實戰:構建跨端工具應用
專案結構
tool-app/
├── src/ # Web前端
│ ├── components/
│ ├── pages/
│ ├── hooks/
│ └── App.tsx
├── src-tauri/ # Rust後端
│ ├── src/
│ │ ├── commands/
│ │ │ ├── json.rs # JSON處理命令
│ │ │ ├── image.rs # 圖片處理命令
│ │ │ └── text.rs # 文字處理命令
│ │ ├── plugins/
│ │ └── main.rs
│ ├── Cargo.toml
│ └── tauri.conf.json
├── package.json
└── tsconfig.json
tauri.conf.json 關鍵配置
{
"productName": "ToolApp",
"version": "1.0.0",
"identifier": "com.toolsku.app",
"build": {
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "npm run build",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"title": "ToolApp",
"width": 1200,
"height": 800,
"minWidth": 800,
"minHeight": 600,
"resizable": true,
"fullscreen": false
}
],
"security": {
"csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
}
},
"plugins": {
"fs": { "scope": ["$APPDATA/**", "$DOWNLOAD/**", "$PICTURES/**"] },
"notification": { "all": true },
"clipboard": { "all": true },
"biometric": { "all": true }
}
}
打包與分發
各平台打包命令
# Windows NSIS安裝包
npm run tauri build -- --bundles nsis
# macOS DMG
npm run tauri build -- --bundles dmg
# Linux AppImage/Deb
npm run tauri build -- --bundles appimage,deb
# iOS
npm run tauri ios build -- --release
# Android APK/AAB
npm run tauri android build -- --release
自動更新配置
{
"plugins": {
"updater": {
"endpoints": [
"https://api.toolsku.com/updates/{{target}}/{{arch}}/{{current_version}}"
],
"pubkey": "PUBLIC_KEY_HERE"
}
}
}
import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
async function checkForUpdates() {
const update = await check();
if (update?.available) {
await update.downloadAndInstall();
await relaunch();
}
}
效能最佳化
WebView渲染最佳化
// 虛擬列表處理大資料
import { VirtualList } from "@tanstack/react-virtual";
function LargeFileList({ files }: { files: FileInfo[] }) {
const parentRef = useRef<HTMLDivElement>(null);
const rowVirtualizer = useVirtualizer({
count: files.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 48,
overscan: 10,
});
return (
<div ref={parentRef} style={{ height: "600px", overflow: "auto" }}>
<div style={{ height: `${rowVirtualizer.getTotalSize()}px` }}>
{rowVirtualizer.getVirtualItems().map((virtualRow) => (
<FileRow key={virtualRow.index} file={files[virtualRow.index]} />
))}
</div>
</div>
);
}
Rust側計算卸載
// 將CPU密集計算放在Rust側
#[tauri::command]
async fn calculate_hash(file_path: String) -> Result<FileHash, String> {
let mut hasher = Sha256::new();
let mut file = File::open(&file_path).map_err(|e| e.to_string())?;
let mut buffer = [0u8; 8192];
loop {
let n = file.read(&mut buffer).map_err(|e| e.to_string())?;
if n == 0 { break; }
hasher.update(&buffer[..n]);
}
Ok(FileHash {
algorithm: "SHA-256".to_string(),
hash: format!("{:x}", hasher.finalize()),
})
}
總結
- Tauri 2.0是跨端開發的最佳選擇 — 包體積小、效能高、一套程式碼五平台
- Rust後端是核心優勢 — CPU密集任務卸載到Rust,比Node.js快10-100倍
- 外掛系統豐富 — 檔案系統、生物識別、相機等原生能力開箱即用
- 移動端支援是殺手鐧 — Electron做不到的,Tauri 2.0做到了
如果你在2026年還在用Electron,是時候認真考慮Tauri 2.0了。8MB vs 150MB的包體積差距,使用者會用下載量投票。
本站提供浏览器本地工具,免注册即可试用 →
#Tauri#Rust#跨平台#桌面应用#移动端