第一个应用 #
一、创建项目 #
1.1 使用脚手架创建 #
bash
# 创建新项目
npm create tauri-app@latest my-first-app
# 进入项目目录
cd my-first-app
1.2 选择配置 #
text
✔ Project name · my-first-app
✔ Choose which language to use for your frontend · TypeScript / JavaScript
✔ Choose your package manager · pnpm
✔ Choose your UI template · React
✔ Choose your UI flavor · TypeScript
1.3 安装依赖 #
bash
# 安装前端依赖
pnpm install
二、项目结构 #
2.1 目录概览 #
text
my-first-app/
├── src/ # 前端源码
│ ├── App.tsx # 主组件
│ ├── main.tsx # 入口文件
│ └── App.css # 样式文件
├── src-tauri/ # Tauri 后端
│ ├── src/
│ │ ├── main.rs # 主入口
│ │ └── lib.rs # 库文件
│ ├── Cargo.toml # Rust 配置
│ └── tauri.conf.json # Tauri 配置
├── index.html # HTML 模板
├── package.json # 项目配置
└── vite.config.ts # Vite 配置
2.2 关键文件 #
| 文件 | 作用 |
|---|---|
| src-tauri/src/lib.rs | Rust 后端逻辑 |
| src/App.tsx | 前端主组件 |
| tauri.conf.json | Tauri 配置 |
三、编写后端代码 #
3.1 修改 lib.rs #
编辑 src-tauri/src/lib.rs:
rust
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! Welcome to Tauri!", name)
}
#[tauri::command]
fn add(a: i32, b: i32) -> i32 {
a + b
}
#[tauri::command]
fn get_system_info() -> SystemInfo {
SystemInfo {
os: std::env::consts::OS.to_string(),
arch: std::env::consts::ARCH.to_string(),
}
}
#[derive(serde::Serialize)]
struct SystemInfo {
os: String,
arch: String,
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.invoke_handler(tauri::generate_handler![
greet,
add,
get_system_info
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
3.2 命令详解 #
| 注解/函数 | 说明 |
|---|---|
#[tauri::command] |
标记函数为可调用命令 |
invoke_handler |
注册命令处理器 |
generate_handler! |
生成命令处理代码 |
3.3 命令参数类型 #
rust
// 基本类型
#[tauri::command]
fn basic_types(
string_param: String,
int_param: i32,
float_param: f64,
bool_param: bool,
) -> String {
format!("Received: {}, {}, {}, {}", string_param, int_param, float_param, bool_param)
}
// 可选参数
#[tauri::command]
fn optional_param(name: Option<String>) -> String {
match name {
Some(n) => format!("Hello, {}!", n),
None => "Hello, stranger!".to_string(),
}
}
// 结构体参数
#[derive(serde::Deserialize)]
struct User {
name: String,
age: u32,
}
#[tauri::command]
fn struct_param(user: User) -> String {
format!("User: {}, age: {}", user.name, user.age)
}
// 返回 Result
#[tauri::command]
fn may_fail(input: i32) -> Result<String, String> {
if input > 0 {
Ok(format!("Success: {}", input))
} else {
Err("Input must be positive".to_string())
}
}
四、编写前端代码 #
4.1 修改 App.tsx #
编辑 src/App.tsx:
tsx
import { useState } from 'react';
import { invoke } from '@tauri-apps/api/core';
import './App.css';
interface SystemInfo {
os: string;
arch: string;
}
function App() {
const [name, setName] = useState('');
const [greeting, setGreeting] = useState('');
const [sum, setSum] = useState<number | null>(null);
const [systemInfo, setSystemInfo] = useState<SystemInfo | null>(null);
const handleGreet = async () => {
try {
const result = await invoke<string>('greet', { name });
setGreeting(result);
} catch (error) {
console.error('Error:', error);
}
};
const handleAdd = async () => {
try {
const result = await invoke<number>('add', { a: 10, b: 20 });
setSum(result);
} catch (error) {
console.error('Error:', error);
}
};
const handleGetSystemInfo = async () => {
try {
const info = await invoke<SystemInfo>('get_system_info');
setSystemInfo(info);
} catch (error) {
console.error('Error:', error);
}
};
return (
<div className="container">
<h1>我的第一个 Tauri 应用</h1>
<div className="section">
<h2>问候功能</h2>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="输入你的名字"
/>
<button onClick={handleGreet}>问候</button>
{greeting && <p className="result">{greeting}</p>}
</div>
<div className="section">
<h2>计算功能</h2>
<button onClick={handleAdd}>计算 10 + 20</button>
{sum !== null && <p className="result">结果: {sum}</p>}
</div>
<div className="section">
<h2>系统信息</h2>
<button onClick={handleGetSystemInfo}>获取系统信息</button>
{systemInfo && (
<div className="result">
<p>操作系统: {systemInfo.os}</p>
<p>架构: {systemInfo.arch}</p>
</div>
)}
</div>
</div>
);
}
export default App;
4.2 添加样式 #
编辑 src/App.css:
css
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
.section {
background: #f5f5f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
h2 {
color: #666;
font-size: 18px;
margin-bottom: 15px;
}
input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
margin-bottom: 10px;
font-size: 14px;
}
button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: transform 0.2s, box-shadow 0.2s;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
.result {
margin-top: 15px;
padding: 10px;
background: #fff;
border-radius: 4px;
border-left: 4px solid #667eea;
}
五、配置文件 #
5.1 tauri.conf.json #
json
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "my-first-app",
"version": "0.1.0",
"identifier": "com.example.my-first-app",
"build": {
"beforeDevCommand": "pnpm dev",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "pnpm build",
"frontendDist": "../dist"
},
"app": {
"withGlobalTauri": true,
"windows": [
{
"title": "我的第一个 Tauri 应用",
"width": 800,
"height": 600,
"center": true,
"resizable": true
}
]
},
"bundle": {
"active": true,
"targets": "all",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}
5.2 Cargo.toml #
toml
[package]
name = "my-first-app"
version = "0.1.0"
edition = "2021"
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
[features]
default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
六、运行应用 #
6.1 开发模式 #
bash
# 启动开发服务器
pnpm tauri dev
6.2 预期效果 #
text
┌────────────────────────────────────────┐
│ 我的第一个 Tauri 应用 ─ □ × │
├────────────────────────────────────────┤
│ │
│ 我的第一个 Tauri 应用 │
│ │
│ ┌────────────────────────────────┐ │
│ │ 问候功能 │ │
│ │ [输入你的名字 ] │ │
│ │ [问候] │ │
│ │ Hello, World! Welcome to Tauri! │ │
│ └────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────┐ │
│ │ 计算功能 │ │
│ │ [计算 10 + 20] │ │
│ │ 结果: 30 │ │
│ └────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────┐ │
│ │ 系统信息 │ │
│ │ [获取系统信息] │ │
│ │ 操作系统: macos │ │
│ │ 架构: aarch64 │ │
│ └────────────────────────────────┘ │
│ │
└────────────────────────────────────────┘
七、调试技巧 #
7.1 前端调试 #
typescript
// 使用 console.log
console.log('Debug info:', data);
// 打开开发者工具
// Windows/Linux: Ctrl + Shift + I
// macOS: Cmd + Option + I
7.2 后端调试 #
rust
// 使用 println!
println!("Debug: {:?}", data);
// 使用 log crate
use log::{info, debug, error};
#[tauri::command]
fn debug_command() {
info!("This is an info message");
debug!("This is a debug message");
error!("This is an error message");
}
7.3 VS Code 调试 #
json
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug Tauri App",
"cargo": {
"args": [
"build",
"--manifest-path=./src-tauri/Cargo.toml"
]
},
"preLaunchTask": "ui:dev"
}
]
}
八、错误处理 #
8.1 前端错误处理 #
typescript
try {
const result = await invoke<string>('greet', { name });
setGreeting(result);
} catch (error) {
console.error('Command failed:', error);
alert(`Error: ${error}`);
}
8.2 后端错误处理 #
rust
#[tauri::command]
fn safe_divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}
九、常见问题 #
9.1 命令未找到 #
rust
// 确保命令已注册
.invoke_handler(tauri::generate_handler![
greet, // 确保这里包含了你的命令
add,
get_system_info
])
9.2 类型不匹配 #
rust
// 确保添加 Serialize/Deserialize
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct MyData {
field: String,
}
9.3 跨域问题 #
json
// tauri.conf.json
{
"app": {
"security": {
"csp": "default-src 'self'; script-src 'self' 'unsafe-inline'"
}
}
}
十、总结 #
10.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 命令定义 | 使用 #[tauri::command] 注解 |
| 命令注册 | 在 invoke_handler 中注册 |
| 前端调用 | 使用 invoke() 函数 |
| 类型支持 | 需要实现 Serialize/Deserialize |
10.2 下一步 #
现在你已经创建了第一个 Tauri 应用,接下来让我们学习 项目结构,了解如何组织一个规范的 Tauri 项目!
最后更新:2026-03-28