Tauri 2.0 Cross-Platform Development: From Desktop to Mobile in 2026
开发教程
Tauri 2.0: One Codebase, Six Platforms
Tauri 2.0's biggest breakthrough is extending from desktop to mobile. Now you can use the same Rust backend + Web frontend to build apps for Windows, macOS, Linux, iOS, and Android simultaneously.
Comparison: Same-feature app — Tauri 2.0 package size 8MB vs Electron 150MB, memory usage 45MB vs 280MB, startup speed 0.3s vs 2.5s.
Tauri vs Electron Full Comparison
| Dimension | Tauri 2.0 | Electron |
|---|---|---|
| Package size | 5-15MB | 100-200MB |
| Memory usage | 30-60MB | 200-400MB |
| Startup speed | 0.2-0.5s | 1.5-3s |
| Backend language | Rust | Node.js |
| WebView | System native | Bundled Chromium |
| Mobile support | iOS/Android | Not supported |
| Native capabilities | Rust FFI | Node.js N-API |
| Security model | Permission sandbox | Full Node.js |
| Ecosystem maturity | Growing | Mature |
Tauri 2.0 New Architecture
┌──────────────────────────────────────────────────────┐
│ Web Frontend Layer │
│ React / Vue / Svelte / Vanilla JS │
├──────────────────────────────────────────────────────┤
│ IPC Communication Layer │
│ invoke() / listen() / emit() │
├──────────────────────────────────────────────────────┤
│ Tauri Core │
│ ┌──────────┬──────────┬──────────┬───────────────┐ │
│ │ Window │ Plugin │ Event │ Permission │ │
│ │ Mgmt │ System │ System │ Mgmt │ │
│ ├──────────┴──────────┴──────────┴───────────────┤ │
│ │ Command Handler │ │
│ ├─────────────────────────────────────────────────┤ │
│ │ Platform Adapter Layer │ │
│ │ Windows │ macOS │ Linux │ iOS │ Android │ │
│ └─────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────┤
│ Rust Backend Layer │
│ Business logic │ File ops │ Network │ Crypto │
└──────────────────────────────────────────────────────┘
Rust Backend + Web Frontend IPC Communication
Frontend Calling Rust Commands
// 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!("Cannot open image: {}", 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("Unsupported operation".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(),
}
}
// Frontend invocation
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(`Done: ${result.output_path}, size: ${result.file_size}`);
}
Event Communication
// Rust side emitting events
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(())
}
// Frontend listening to events
import { listen } from "@tauri-apps/api/event";
const unlisten = await listen<BatchProgress>("batch-progress", (event) => {
console.log(`Progress: ${event.payload.current}/${event.payload.total}`);
updateProgressBar(event.payload.current / event.payload.total);
});
unlisten();
Tauri Plugin System
Common Official Plugins
| Plugin | Function | Platforms |
|---|---|---|
| @tauri-apps/plugin-fs | File system read/write | All |
| @tauri-apps/plugin-notification | System notifications | All |
| @tauri-apps/plugin-clipboard | Clipboard operations | All |
| @tauri-apps/plugin-biometric | Biometric auth | iOS/Android/macOS |
| @tauri-apps/plugin-camera | Camera access | iOS/Android |
| @tauri-apps/plugin-geolocation | Geolocation | iOS/Android |
| @tauri-apps/plugin-barcode-scanner | Barcode scanning | iOS/Android |
| @tauri-apps/plugin-store | Local persistent storage | All |
Custom Plugin Development
// 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!("Encryption failed: {}", 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 decode failed: {}", e))?;
let decrypted = aes_decrypt(&decoded, key.as_bytes())
.map_err(|e| format!("Decryption failed: {}", 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()
}
Mobile Adaptation
iOS/Android Native Capability Calls
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: "Share" });
} else {
await navigator.clipboard.writeText(content);
showToast("Copied to clipboard");
}
}
async function authenticateUser() {
if (platform() === "ios" || platform() === "android") {
const { authenticate } = await import("@tauri-apps/plugin-biometric");
const result = await authenticate({
reason: "Please verify your identity",
fallbackToPin: true,
});
return result.isAuthenticated;
}
return true;
}
Mobile UI Adaptation
.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);
}
Packaging and Distribution
Platform-Specific Build Commands
# Windows NSIS installer
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
Auto-Update Configuration
{
"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();
}
}
Performance Optimization
Rust-Side Compute Offloading
// Offload CPU-intensive computation to 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()),
})
}
Summary
- Tauri 2.0 is the best choice for cross-platform development — Small package size, high performance, one codebase for five platforms
- Rust backend is the core advantage — CPU-intensive tasks offloaded to Rust, 10-100x faster than Node.js
- Rich plugin system — File system, biometrics, camera and other native capabilities out of the box
- Mobile support is the killer feature — What Electron can't do, Tauri 2.0 can
If you're still using Electron in 2026, it's time to seriously consider Tauri 2.0. The 8MB vs 150MB package size gap — users will vote with downloads.
Try these browser-local tools — no sign-up required →
#Tauri#Rust#跨平台#桌面应用#移动端