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()),
    })
}

總結

  1. Tauri 2.0是跨端開發的最佳選擇 — 包體積小、效能高、一套程式碼五平台
  2. Rust後端是核心優勢 — CPU密集任務卸載到Rust,比Node.js快10-100倍
  3. 外掛系統豐富 — 檔案系統、生物識別、相機等原生能力開箱即用
  4. 移動端支援是殺手鐧 — Electron做不到的,Tauri 2.0做到了

如果你在2026年還在用Electron,是時候認真考慮Tauri 2.0了。8MB vs 150MB的包體積差距,使用者會用下載量投票。

本站提供浏览器本地工具,免注册即可试用 →

#Tauri#Rust#跨平台#桌面应用#移动端