Skip to content

Tauri 打包发布完整指南 - 签名、更新、分发

前言

开发完应用后,最后也是最重要的一步就是打包和发布。这一步看似简单,实际上有很多需要注意的地方:如何优化打包体积?如何进行代码签名?如何实现自动更新?如何分发应用?

我第一次打包 Tauri 应用时,遇到了各种问题:Windows 上的 SmartScreen 警告、macOS 的 Gatekeeper 阻止、Linux 的依赖问题等。经过不断摸索,终于掌握了完整的打包发布流程。

今天,我就把这些经验分享给大家,让你少走弯路。

打包前的准备

1. 完善应用信息

编辑 src-tauri/tauri.conf.json

json
{
  "package": {
    "productName": "Todo App",              // 应用名称
    "version": "1.0.0"                      // 应用版本(遵循语义化版本)
  },
  "tauri": {
    "bundle": {
      "active": true,
      "targets": "all",                     // 打包所有格式
      "identifier": "com.example.todoapp",  // 唯一标识符(反向域名)
      "icon": [                             // 应用图标(多尺寸)
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/128x128@2x.png",
        "icons/icon.icns",                  // macOS
        "icons/icon.ico"                    // Windows
      ],
      "copyright": "Copyright © 2025 Your Name",
      "category": "Productivity",           // 应用分类
      "shortDescription": "A simple todo app",
      "longDescription": "A beautiful and efficient todo application built with Tauri"
    }
  }
}

2. 准备应用图标

图标要求:

  • PNG 格式(Windows/Linux)
  • ICNS 格式(macOS)
  • ICO 格式(Windows)

推荐尺寸:

  • 32x32
  • 64x64
  • 128x128
  • 256x256
  • 512x512
  • 1024x1024

自动生成图标

bash
# 安装图标生成工具
npm install -g @tauri-apps/cli

# 从一个 PNG 文件生成所有尺寸的图标
npm run tauri icon path/to/your/icon.png

3. 版本号管理

语义化版本规则

主版本号.次版本号.修订号

1.0.0 - 初始版本
1.0.1 - 修复 bug
1.1.0 - 新增功能(向后兼容)
2.0.0 - 重大更新(可能不兼容旧版本)

同步版本号

json
// package.json
{
  "version": "1.0.0"
}

// src-tauri/Cargo.toml
[package]
version = "1.0.0"

// src-tauri/tauri.conf.json
{
  "package": {
    "version": "1.0.0"
  }
}

Windows 平台打包

基本打包

bash
npm run tauri build

输出文件位置:

src-tauri/target/release/bundle/
├── msi/                          # MSI 安装包
│   └── Todo App_1.0.0_x64_en-US.msi
└── nsis/                         # NSIS 安装包(可选)
    └── Todo App_1.0.0_x64-setup.exe

Windows 配置

json
{
  "tauri": {
    "bundle": {
      "windows": {
        "certificateThumbprint": null,      // 证书指纹
        "digestAlgorithm": "sha256",        // 摘要算法
        "timestampUrl": "",                 // 时间戳服务器
        "wix": {                            // WiX 配置(MSI)
          "language": "en-US",
          "template": null,
          "fragmentPaths": []
        }
      }
    }
  }
}

代码签名

1. 获取代码签名证书

bash
# 选项1:从认证机构购买
# - DigiCert
# - GlobalSign
# - Sectigo

# 选项2:自签名证书(仅用于测试)
# 在 Windows PowerShell 中运行:
New-SelfSignedCertificate `
    -Type CodeSigningCert `
    -Subject "CN=Your Name, O=Your Organization, C=US" `
    -KeyUsage DigitalSignature `
    -FriendlyName "Code Signing Certificate" `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3")

2. 配置签名

json
{
  "tauri": {
    "bundle": {
      "windows": {
        "certificateThumbprint": "YOUR_CERT_THUMBPRINT",
        "timestampUrl": "http://timestamp.digicert.com"
      }
    }
  }
}

3. 手动签名

bash
# 使用 signtool.exe 手动签名
signtool sign /f certificate.pfx /p password /t http://timestamp.digicert.com /fd sha256 "Todo App.exe"

解决 SmartScreen 警告

Windows SmartScreen 会对未签名或不知名的应用显示警告。

解决方案

  1. 使用 EV 代码签名证书(最有效)

    • 立即获得信誉
    • 无需积累下载量
    • 价格较高(约 $300-500/年)
  2. 积累信誉

    • 使用普通代码签名证书
    • 需要大量用户下载(几千次)
    • 需要时间(几周到几个月)
  3. 提交给微软审核

    • 提交到微软的 SmartScreen 服务
    • 审核时间较长

macOS 平台打包

基本打包

bash
npm run tauri build

输出文件位置:

src-tauri/target/release/bundle/
├── dmg/                          # DMG 安装包
│   └── Todo App_1.0.0_x64.dmg
└── macos/                        # .app 应用包
    └── Todo App.app

macOS 配置

json
{
  "tauri": {
    "bundle": {
      "macOS": {
        "frameworks": [],                   // 额外框架
        "minimumSystemVersion": "10.13",    // 最低系统版本
        "entitlements": null,               // 权限配置文件
        "exceptionDomain": "",              // 网络异常域
        "signingIdentity": null,            // 签名身份
        "providerShortName": null,          // 提供商短名称
        "hardenedRuntime": true             // 加固运行时
      }
    }
  }
}

代码签名和公证

1. 获取开发者证书

bash
# 需要加入 Apple Developer Program($99/年)

# 证书类型:
# - Developer ID Application(用于分发)
# - Development(用于开发测试)

# 在钥匙串访问中查看证书
security find-identity -v -p codesigning

2. 配置签名

json
{
  "tauri": {
    "bundle": {
      "macOS": {
        "signingIdentity": "Developer ID Application: Your Name (TEAM_ID)",
        "hardenedRuntime": true,
        "entitlements": "entitlements.plist"
      }
    }
  }
}

3. 创建 entitlements.plist

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
</dict>
</plist>

4. 公证应用

bash
# 1. 上传应用到 Apple
xcrun altool --notarize-app \
    --primary-bundle-id "com.example.todoapp" \
    --username "your@email.com" \
    --password "@keychain:AC_PASSWORD" \
    --file "Todo App.dmg"

# 2. 检查公证状态
xcrun altool --notarization-info REQUEST_UUID \
    --username "your@email.com" \
    --password "@keychain:AC_PASSWORD"

# 3. 公证成功后,装订票据
xcrun stapler staple "Todo App.dmg"

5. 自动化公证

创建 notarize.sh

bash
#!/bin/bash

APP_NAME="Todo App"
BUNDLE_ID="com.example.todoapp"
APPLE_ID="your@email.com"
TEAM_ID="TEAM_ID"

# 签名
codesign --deep --force --verify --verbose --sign "Developer ID Application: Your Name ($TEAM_ID)" \
    --options runtime "$APP_NAME.app"

# 创建 DMG
hdiutil create -volname "$APP_NAME" -srcfolder "$APP_NAME.app" -ov -format UDZO "$APP_NAME.dmg"

# 签名 DMG
codesign --force --sign "Developer ID Application: Your Name ($TEAM_ID)" "$APP_NAME.dmg"

# 公证
xcrun altool --notarize-app \
    --primary-bundle-id "$BUNDLE_ID" \
    --username "$APPLE_ID" \
    --password "@keychain:AC_PASSWORD" \
    --file "$APP_NAME.dmg"

Linux 平台打包

基本打包

bash
npm run tauri build

输出文件位置:

src-tauri/target/release/bundle/
├── deb/                          # Debian/Ubuntu
│   └── todo-app_1.0.0_amd64.deb
├── rpm/                          # Fedora/RHEL
│   └── todo-app-1.0.0-1.x86_64.rpm
└── appimage/                     # AppImage(通用)
    └── todo-app_1.0.0_amd64.AppImage

Linux 配置

json
{
  "tauri": {
    "bundle": {
      "deb": {
        "depends": [],                      // 依赖包
        "files": {},                        // 额外文件
        "desktopTemplate": null             // 桌面文件模板
      },
      "appimage": {
        "bundleMediaFramework": false,      // 是否打包媒体框架
        "files": {}                         // 额外文件
      }
    }
  }
}

创建桌面文件

创建 src-tauri/assets/todo-app.desktop

ini
[Desktop Entry]
Version=1.0
Type=Application
Name=Todo App
Comment=A simple todo application
Exec=todo-app
Icon=todo-app
Categories=Utility;
Terminal=false

依赖处理

bash
# 查看应用依赖
ldd target/release/todo-app

# 常见依赖:
# - libwebkit2gtk-4.0
# - libgtk-3
# - libayatana-appindicator3

# 在 tauri.conf.json 中配置
{
  "tauri": {
    "bundle": {
      "deb": {
        "depends": [
          "libwebkit2gtk-4.0-37",
          "libgtk-3-0",
          "libayatana-appindicator3-1"
        ]
      }
    }
  }
}

自动更新

1. 配置更新器

json
{
  "tauri": {
    "updater": {
      "active": true,
      "endpoints": [
        "https://releases.example.com/{{target}}/{{current_version}}"
      ],
      "dialog": true,                       // 显示更新对话框
      "pubkey": "YOUR_PUBLIC_KEY"           // 公钥(用于验证签名)
    }
  }
}

2. 生成密钥对

bash
# 安装 Tauri CLI
npm install -g @tauri-apps/cli

# 生成密钥对
npm run tauri signer generate

# 输出:
# Public Key: dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6...
# Private Key: saved to ~/.tauri/myapp.key

将公钥配置到 tauri.conf.json

json
{
  "tauri": {
    "updater": {
      "pubkey": "YOUR_PUBLIC_KEY_HERE"
    }
  }
}

3. 签名更新包

bash
# 构建应用
npm run tauri build

# 签名更新文件
npm run tauri signer sign target/release/bundle/msi/Todo\ App_1.0.0_x64_en-US.msi

这会生成 .sig 文件:

Todo App_1.0.0_x64_en-US.msi.sig

4. 创建更新服务器

创建 update-manifest.json

json
{
  "version": "1.0.1",
  "notes": "Bug fixes and improvements",
  "pub_date": "2025-01-21T12:00:00Z",
  "platforms": {
    "windows-x86_64": {
      "signature": "SIGNATURE_FROM_SIG_FILE",
      "url": "https://releases.example.com/windows/Todo_App_1.0.1_x64_en-US.msi"
    },
    "darwin-x86_64": {
      "signature": "SIGNATURE_FROM_SIG_FILE",
      "url": "https://releases.example.com/macos/Todo_App_1.0.1_x64.dmg"
    },
    "darwin-aarch64": {
      "signature": "SIGNATURE_FROM_SIG_FILE",
      "url": "https://releases.example.com/macos/Todo_App_1.0.1_aarch64.dmg"
    },
    "linux-x86_64": {
      "signature": "SIGNATURE_FROM_SIG_FILE",
      "url": "https://releases.example.com/linux/todo-app_1.0.1_amd64.AppImage"
    }
  }
}

5. 前端检查更新

typescript
import { checkUpdate, installUpdate } from '@tauri-apps/api/updater';
import { relaunch } from '@tauri-apps/api/process';

async function checkForUpdates() {
  try {
    const { shouldUpdate, manifest } = await checkUpdate();

    if (shouldUpdate) {
      console.log(`New version available: ${manifest?.version}`);
      console.log(`Release notes: ${manifest?.body}`);

      // 下载并安装更新
      await installUpdate();

      // 重启应用
      await relaunch();
    } else {
      console.log('App is up to date');
    }
  } catch (error) {
    console.error('Failed to check for updates:', error);
  }
}

// 应用启动时检查更新
useEffect(() => {
  checkForUpdates();
}, []);

6. 自动更新最佳实践

typescript
import { useState, useEffect } from 'react';
import { checkUpdate, installUpdate } from '@tauri-apps/api/updater';
import { relaunch } from '@tauri-apps/api/process';

function UpdateChecker() {
  const [updateAvailable, setUpdateAvailable] = useState(false);
  const [updateInfo, setUpdateInfo] = useState<any>(null);
  const [downloading, setDownloading] = useState(false);

  useEffect(() => {
    checkForUpdates();
  }, []);

  const checkForUpdates = async () => {
    try {
      const { shouldUpdate, manifest } = await checkUpdate();
      
      if (shouldUpdate) {
        setUpdateAvailable(true);
        setUpdateInfo(manifest);
      }
    } catch (error) {
      console.error('Update check failed:', error);
    }
  };

  const handleUpdate = async () => {
    setDownloading(true);
    try {
      await installUpdate();
      await relaunch();
    } catch (error) {
      console.error('Update failed:', error);
      setDownloading(false);
    }
  };

  if (!updateAvailable) return null;

  return (
    <div className="update-banner">
      <div className="update-content">
        <h3>New version available: {updateInfo?.version}</h3>
        <p>{updateInfo?.body}</p>
      </div>
      <button 
        onClick={handleUpdate} 
        disabled={downloading}
      >
        {downloading ? 'Downloading...' : 'Update Now'}
      </button>
    </div>
  );
}

打包优化

1. 减小体积

toml
# Cargo.toml
[profile.release]
panic = "abort"           # 禁用堆栈展开
codegen-units = 1         # 减少并行代码生成单元
lto = true                # 启用链接时优化
opt-level = "z"           # 优化体积
strip = true              # 去除符号信息

2. 前端优化

bash
# 使用生产构建
npm run build

# 启用压缩
# vite.config.ts
export default defineConfig({
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,     # 移除 console
        drop_debugger: true     # 移除 debugger
      }
    },
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom']
        }
      }
    }
  }
});

3. 资源优化

bash
# 压缩图片
npm install -g imagemin-cli

imagemin src/assets/*.png --out-dir=dist/assets --plugin=pngquant

# 优化 SVG
npm install -g svgo

svgo src/assets/*.svg

CI/CD 自动化

GitHub Actions 配置

创建 .github/workflows/release.yml

yaml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    strategy:
      matrix:
        platform: [ubuntu-latest, macos-latest, windows-latest]

    runs-on: ${{ matrix.platform }}

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 18

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Install dependencies (Ubuntu)
        if: matrix.platform == 'ubuntu-latest'
        run: |
          sudo apt-get update
          sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev \
            libayatana-appindicator3-dev librsvg2-dev

      - name: Install Node dependencies
        run: npm install

      - name: Build
        run: npm run tauri build

      - name: Upload artifacts
        uses: actions/upload-artifact@v3
        with:
          name: ${{ matrix.platform }}
          path: |
            src-tauri/target/release/bundle/**/*.deb
            src-tauri/target/release/bundle/**/*.dmg
            src-tauri/target/release/bundle/**/*.msi
            src-tauri/target/release/bundle/**/*.AppImage

      - name: Create Release
        uses: softprops/action-gh-release@v1
        if: startsWith(github.ref, 'refs/tags/')
        with:
          files: |
            src-tauri/target/release/bundle/**/*.deb
            src-tauri/target/release/bundle/**/*.dmg
            src-tauri/target/release/bundle/**/*.msi
            src-tauri/target/release/bundle/**/*.AppImage
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

分发渠道

1. 官网下载

html
<!-- 下载页面 -->
<div class="download-section">
  <h2>Download Todo App</h2>
  
  <div class="download-options">
    <a href="/downloads/windows/latest" class="download-btn">
      <i class="icon-windows"></i>
      Windows
    </a>
    
    <a href="/downloads/macos/latest" class="download-btn">
      <i class="icon-apple"></i>
      macOS
    </a>
    
    <a href="/downloads/linux/latest" class="download-btn">
      <i class="icon-linux"></i>
      Linux
    </a>
  </div>
</div>

2. GitHub Releases

bash
# 创建标签
git tag -a v1.0.0 -m "Version 1.0.0"
git push origin v1.0.0

# GitHub Actions 会自动构建并发布

3. 应用商店

Microsoft Store

  1. 注册开发者账号($19 一次性费用)
  2. 准备应用信息和截图
  3. 使用 MSIX 打包(Tauri 支持)
  4. 提交审核

Mac App Store

  1. 加入 Apple Developer Program($99/年)
  2. 配置 App Store 签名和沙盒
  3. 准备应用信息和截图
  4. 使用 Transporter 上传
  5. 提交审核

Snap Store(Linux)

bash
# 创建 snapcraft.yaml
name: todo-app
version: '1.0.0'
summary: A simple todo application
description: |
  A beautiful and efficient todo application

confinement: strict
grade: stable

apps:
  todo-app:
    command: todo-app
    plugs: [network, home]

parts:
  todo-app:
    plugin: dump
    source: .
    stage-packages:
      - libwebkit2gtk-4.0-37
      - libgtk-3-0

# 构建和发布
snapcraft
snapcraft upload todo-app_1.0.0_amd64.snap

4. Homebrew(macOS)

创建 formula:

ruby
class TodoApp < Formula
  desc "A simple todo application"
  homepage "https://example.com/todo-app"
  url "https://github.com/username/todo-app/releases/download/v1.0.0/Todo-App-1.0.0.dmg"
  sha256 "..."
  version "1.0.0"

  def install
    prefix.install "Todo App.app"
  end
end

发布检查清单

打包前

  • [ ] 更新版本号(package.json, Cargo.toml, tauri.conf.json)
  • [ ] 更新 CHANGELOG
  • [ ] 测试所有功能
  • [ ] 检查控制台是否有错误
  • [ ] 优化资源文件
  • [ ] 更新文档

打包后

  • [ ] 在各平台测试安装包
  • [ ] 验证应用功能
  • [ ] 检查应用体积
  • [ ] 测试更新功能
  • [ ] 验证代码签名

发布后

  • [ ] 上传到分发渠道
  • [ ] 更新官网
  • [ ] 发布 Release Notes
  • [ ] 社交媒体宣传
  • [ ] 监控错误报告

常见问题

Windows 相关

问题:SmartScreen 警告

  • 使用 EV 代码签名证书
  • 或积累应用信誉

问题:打包失败

  • 检查 Visual Studio Build Tools 安装
  • 确认 Rust 工具链完整

macOS 相关

问题:Gatekeeper 阻止

  • 进行代码签名和公证
  • 用户可以右键点击"打开"绕过

问题:公证失败

  • 检查 entitlements.plist 配置
  • 确认开发者证书有效

Linux 相关

问题:缺少依赖

  • 在打包配置中声明依赖
  • 或使用 AppImage(包含所有依赖)

问题:权限问题

  • 检查文件权限
  • 使用 chmod +x 赋予执行权限

总结

🎉 恭喜!你已经掌握了 Tauri 应用的完整打包发布流程!

✅ 核心知识

  1. 打包配置

    • 应用信息配置
    • 图标准备
    • 版本管理
  2. 平台特定

    • Windows: MSI/NSIS, 代码签名
    • macOS: DMG/App, 签名和公证
    • Linux: DEB/RPM/AppImage
  3. 自动更新

    • 更新器配置
    • 密钥生成和签名
    • 更新服务器
  4. 优化和自动化

    • 体积优化
    • CI/CD 配置
    • 多渠道分发

🎯 最佳实践

  • 始终进行代码签名
  • 提供自动更新功能
  • 多平台测试
  • 完善的文档和支持

💡 下一步

  • 收集用户反馈
  • 持续优化性能
  • 定期发布更新
  • 扩展功能

至此,Tauri 系列教程就全部完成了!从入门到实战,从开发到发布,相信你已经具备了开发 Tauri 应用的完整能力。


系列文章回顾:

  1. Tauri 是什么?为什么它是桌面应用开发的未来
  2. Tauri 开发环境搭建 - Windows/macOS/Linux 完整指南
  3. Tauri 快速开始 - 15 分钟创建第一个应用
  4. Tauri 核心概念深度解析 - 架构、安全与配置
  5. Tauri 窗口管理与高级通信技巧
  6. Tauri 实战项目 - 从零开始构建 Todo 应用
  7. Tauri 打包发布完整指南 - 签名、更新、分发

感谢阅读!有任何问题欢迎留言讨论!


参考资料: