mcpField
C
Cross-Platform Build Expert

Cross-Platform Build Expert

github.com/martinholovsky开发48209 次安装47 周前更新
代码仓库

关于 Cross-Platform Build Expert

Cross-Platform Build Expert 是面向 Tauri 桌面应用开发者的技能,涵盖 Windows、macOS 和 Linux 构建。内容包括平台配置、签名与分发、CI 构建和优化,并强调安全与测试。

主要功能

  1. 01Tauri 多平台构建配置
  2. 02Windows、macOS 和 Linux 目标
  3. 03代码签名与公证指南
  4. 04CI 构建矩阵模式
  5. 05构建体积与性能优化

适用场景

  1. 01设置 Tauri 多平台构建
  2. 02准备签名后的应用发布
  3. 03配置平台目标的 CI
  4. 04缩短构建时间或减小包体积

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/martinholovsky/claude-skills-generator --skill cross-platform-build-expert

安装后在 Claude Code 中输入/cross-platform-build-expert确认已加载。

附带文件references/security-examples.mdreferences/advanced-patterns.md

详细介绍

跨平台构建专家

0. 强制阅读流程

重要:在配置任何平台专属的构建选项之前,必须先阅读相关参考文件:

参考文件触发条件

在以下情况下阅读 references/advanced-patterns.md:

  • 配置平台专属的构建矩阵
  • 设置条件编译
  • 实现平台专属功能
  • 优化构建体积和性能

在以下情况下阅读 references/security-examples.md:

  • 设置代码签名证书
  • 配置 macOS 公证
  • 实现安全的构建环境
  • 管理签名凭据

1. 概述

风险级别:中

原因:跨平台构建涉及代码签名凭据、平台专属安全配置,以及通过各种应用商店进行分发。签名不当会导致安全警告、安装失败或提交被拒。构建配置还可能泄露敏感信息或造成平台专属漏洞。

你是跨平台桌面应用构建专家,专长包括:

  • 平台专属配置,适用于 Windows、macOS 和 Linux
  • 代码签名和公证流程
  • 各平台的分发要求
  • 构建优化,提升体积和性能
  • 面向多平台构建的 Tauri 配置
主要用例
  • 为所有桌面平台构建 Tauri 应用
  • 设置代码签名,实现可信分发
  • 配置多平台构建的 CI/CD
  • 优化应用程序包
  • 满足平台分发要求

2. 核心原则

  1. 优先采用 TDD——实现前先编写构建配置测试
  2. 关注性能——优化构建时间、程序包体积和启动速度
  3. 在所有目标平台上测试——不要假设跨平台兼容
  4. 使用平台抽象——通过 Rust std、Tauri API 处理平台差异
  5. 处理路径差异——正斜杠与反斜杠、大小写敏感性
  6. 遵循平台惯例——文件位置、UI 指南
  7. 为所有发行版本签名——用户信任经过签名的应用
  8. 保护签名凭据——绝不提交证书
  9. 验证签名——分发前进行检查
  10. 使用时间戳——证书过期后,签名仍然有效

3. 技术基础

3.1 平台构建目标
平台Rust 目标Tauri 程序包
Windows x64x86_64-pc-windows-msvcmsi、nsis
Windows ARMaarch64-pc-windows-msvcmsi、nsis
macOS Intelx86_64-apple-darwindmg、app
macOS Apple Siliconaarch64-apple-darwindmg、app
Linux x64x86_64-unknown-linux-gnudeb、appimage
Linux ARMaarch64-unknown-linux-gnudeb、appimage
3.2 构建依赖项

Windows:

  • Visual Studio Build Tools
  • Windows SDK
  • WebView2 Runtime(由 Tauri 打包)

macOS:

  • Xcode 命令行工具
  • Apple 开发者证书
  • 用于公证的应用专用密码

Linux:

  • GTK3 开发库
  • WebKitGTK
  • AppIndicator(用于系统托盘)

4. 实现模式

4.1 Tauri 配置
// tauri.conf.json
{
  "build": {
    "beforeBuildCommand": "npm run build",
    "beforeDevCommand": "npm run dev",
    "devPath": "http://localhost:3000",
    "distDir": "../dist"
  },
  "package": {
    "productName": "MyApp",
    "version": "1.0.0"
  },
  "tauri": {
    "bundle": {
      "active": true,
      "identifier": "com.company.myapp",
      "icon": [
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/[email protected]",
        "icons/icon.icns",
        "icons/icon.ico"
      ],
      "targets": "all",
      "windows": {
        "certificateThumbprint": null,
        "digestAlgorithm": "sha256",
        "timestampUrl": "http://timestamp.digicert.com",
        "wix": {
          "language": "en-US"
        }
      },
      "macOS": {
        "entitlements": "./entitlements.plist",
        "exceptionDomain": "",
        "frameworks": [],
        "minimumSystemVersion": "10.15",
        "signingIdentity": null
      },
      "linux": {
        "deb": {
          "depends": ["libgtk-3-0", "libwebkit2gtk-4.0-37"]
        },
        "appimage": {
          "bundleMediaFramework": true
        }
      }
    },
    "security": {
      "csp": "default-src 'self'; script-src 'self'"
    }
  }
}
4.2 平台专属代码
// src-tauri/src/main.rs

#[cfg(target_os = "windows")]
fn platform_init() {
    // Windows-specific initialization
    use windows::Win32::System::Console::SetConsoleOutputCP;
    unsafe { SetConsoleOutputCP(65001); }  // UTF-8 support
}

#[cfg(target_os = "macos")]
fn platform_init() {
    // macOS-specific initialization
    // Handle Dock, menu bar, etc.
}

#[cfg(target_os = "linux")]
fn platform_init() {
    // Linux-specific initialization
    // Handle DBus, system tray, etc.
}

fn main() {
    platform_init();

    tauri::Builder::default()
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
4.3 GitHub Actions 构建矩阵
name: Build

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - platform: windows-latest
            args: ''
            target: x86_64-pc-windows-msvc
          - platform: macos-latest
            args: '--target x86_64-apple-darwin'
            target: x86_64-apple-darwin
          - platform: macos-latest
            args: '--target aarch64-apple-darwin'
            target: aarch64-apple-darwin
          - platform: ubuntu-22.04
            args: ''
            target: x86_64-unknown-linux-gnu

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

    steps:
      - uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install Linux Dependencies
        if: matrix.platform == 'ubuntu-22.04'
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            libgtk-3-dev \
            libwebkit2gtk-4.0-dev \
            libappindicator3-dev \
            librsvg2-dev \
            patchelf

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Build
        run: npm run tauri build -- ${{ matrix.args }}

      - name: Upload Artifacts
        uses: actions/upload-artifact@v3
        with:
          name: ${{ matrix.target }}
          path: |
            src-tauri/target/${{ matrix.target }}/release/bundle/
4.4 代码签名配置

Windows(tauri.conf.json):

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

macOS(tauri.conf.json):

{
  "tauri": {
    "bundle": {
      "macOS": {
        "signingIdentity": "Developer ID Application: Company Name (TEAM_ID)",
        "entitlements": "./entitlements.plist"
      }
    }
  }
}

macOS 权限配置(entitlements.plist):

<?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.disable-library-validation</key>
    <true/>
</dict>
</plist>

5. 安全标准

5.1 代码签名要求
平台证书类型用途
WindowsEV 代码签名立即获得 SmartScreen 信任
Windows标准代码签名建立信誉后获得信任
macOSDeveloper ID Application在 App Store 之外分发
macOSDeveloper ID Installer对 PKG 安装程序签名
LinuxGPG 密钥对软件包签名
5.2 签名最佳实践
# Windows: Verify signature
signtool verify /pa /v MyApp.exe

# macOS: Verify signature
codesign --verify --deep --strict MyApp.app
spctl --assess --type execute MyApp.app

# macOS: Check notarization
xcrun stapler validate MyApp.app
5.3 构建安全
  • 证书存储在 CI/CD 密钥中,而非代码仓库
  • 仅在带标签的发布版本中进行签名
  • 构建环境干净且临时
  • 依赖项已固定版本并经过验证
  • 签名后对构件进行校验和计算

6. 实施工作流(TDD)

步骤 1:先编写失败测试
// tests/build_config_test.rs
#[cfg(test)]
mod tests {
    use std::path::Path;
    use std::process::Command;

    #[test]
    fn test_tauri_config_exists() {
        assert!(Path::new("src-tauri/tauri.conf.json").exists());
    }

    #[test]
    fn test_icons_all_platforms() {
        let required_icons = vec![
            "icons/icon.ico",      // Windows
            "icons/icon.icns",     // macOS
            "icons/icon.png",      // Linux
        ];
        for icon in required_icons {
            assert!(Path::new(&format!("src-tauri/{}", icon)).exists(),
                "Missing icon: {}", icon);
        }
    }

    #[test]
    fn test_bundle_identifier_format() {
        let config: serde_json::Value = serde_json::from_str(
            &std::fs::read_to_string("src-tauri/tauri.conf.json").unwrap()
        ).unwrap();
        let identifier = config["tauri"]["bundle"]["identifier"].as_str().unwrap();
        assert!(identifier.contains('.'), "Bundle ID must use reverse domain");
    }

    #[test]
    fn test_frontend_builds_successfully() {
        let output = Command::new("npm")
            .args(["run", "build"])
            .output()
            .expect("Failed to run build");
        assert!(output.status.success(), "Frontend build failed");
    }
}
步骤 2:实现通过测试所需的最小功能
// Create minimal tauri.conf.json
{
  "package": { "productName": "MyApp", "version": "0.1.0" },
  "tauri": {
    "bundle": {
      "identifier": "com.company.myapp",
      "icon": ["icons/icon.ico", "icons/icon.icns", "icons/icon.png"]
    }
  }
}
步骤 3:重构并扩展

扩展配置时,添加特定平台的测试:

#[test]
fn test_windows_signing_config() {
    let config: serde_json::Value = serde_json::from_str(
        &std::fs::read_to_string("src-tauri/tauri.conf.json").unwrap()
    ).unwrap();
    let windows = &config["tauri"]["bundle"]["windows"];
    assert!(windows["timestampUrl"].as_str().is_some());
}

#[test]
fn test_macos_minimum_version() {
    let config: serde_json::Value = serde_json::from_str(
        &std::fs::read_to_string("src-tauri/tauri.conf.json").unwrap()
    ).unwrap();
    let min_ver = config["tauri"]["bundle"]["macOS"]["minimumSystemVersion"]
        .as_str().unwrap();
    assert!(min_ver >= "10.15", "Must support macOS 10.15+");
}
步骤 4:运行完整验证
# Run all build tests
cargo test --manifest-path src-tauri/Cargo.toml

# Verify builds on all platforms (CI)
npm run tauri build -- --target x86_64-pc-windows-msvc
npm run tauri build -- --target x86_64-apple-darwin
npm run tauri build -- --target x86_64-unknown-linux-gnu

# Verify signatures
signtool verify /pa target/release/bundle/msi/*.msi
codesign --verify --deep target/release/bundle/macos/*.app

7. 性能模式

7.1 增量构建
# Cargo.toml - Enable incremental compilation
[profile.dev]
incremental = true

[profile.release]
incremental = true
lto = "thin"  # Faster than "fat" LTO

好:增量构建会复用已编译的构件

# First build: 2-3 minutes
cargo build --release
# Subsequent builds: 10-30 seconds
cargo build --release

不好:每次都进行干净构建

cargo clean && cargo build --release  # Always slow
7.2 构建缓存

好:在 CI 中缓存 Rust 依赖项

- name: Cache Cargo
  uses: actions/cache@v4
  with:
    path: |
      ~/.cargo/registry
      ~/.cargo/git
      target
    key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

不好:不使用缓存——每次构建都下载依赖项

- name: Build
  run: cargo build --release  # Downloads everything
7.3 并行编译

好:尽可能增加并行任务数

# .cargo/config.toml
[build]
jobs = 8  # Match CPU cores

[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=mold"]  # Fast linker

不好:单线程编译

cargo build -j 1  # Extremely slow
7.4 树摇优化与死代码消除

好:启用 LTO 以减小二进制文件

[profile.release]
lto = true
codegen-units = 1
panic = "abort"
strip = true

不好:发布版本中包含调试符号

[profile.release]
debug = true  # Bloats binary size
7.5 代码拆分(前端)

好:延迟加载路由

// nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    treeshakeClientOnly: true
  },
  vite: {
    build: {
      rollupOptions: {
        output: {
          manualChunks: {
            'vendor': ['vue', 'pinia'],
            'three': ['three', '@tresjs/core']
          }
        }
      }
    }
  }
})

不好:将所有内容打包在一起

// Single massive bundle
import * as everything from './all-modules'
7.6 构建体积优化

好:分析并优化打包体积

# Analyze Rust binary
cargo bloat --release --crates

# Analyze frontend bundle
npx nuxi analyze

不好:忽略打包体积

npm run build  # Never check what's included

8. 常见错误与反模式

8.1 硬编码路径
// WRONG: Windows-style path
let config = std::fs::read("C:\\Users\\app\\config.json")?;

// WRONG: Unix-style absolute path
let config = std::fs::read("/home/user/.config/app/config.json")?;

// CORRECT: Platform-appropriate paths
use directories::ProjectDirs;

let dirs = ProjectDirs::from("com", "company", "app")
    .expect("Failed to get project directories");
let config_path = dirs.config_dir().join("config.json");
let config = std::fs::read(config_path)?;
8.2 缺少平台依赖项
# WRONG: Missing Linux dependencies
- name: Build
  run: npm run tauri build  # Fails on Linux!

# CORRECT: Install platform dependencies
- name: Install Dependencies (Linux)
  if: matrix.platform == 'ubuntu-22.04'
  run: |
    sudo apt-get update
    sudo apt-get install -y \
      libgtk-3-dev \
      libwebkit2gtk-4.0-dev \
      libappindicator3-dev
8.3 通用二进制文件问题
# WRONG: Build universal without both targets
- name: Build macOS Universal
  run: npm run tauri build -- --target universal-apple-darwin
  # Fails if x86_64 or aarch64 not available!

# CORRECT: Build each architecture separately
- name: Build macOS Intel
  run: npm run tauri build -- --target x86_64-apple-darwin

- name: Build macOS ARM
  run: npm run tauri build -- --target aarch64-apple-darwin

- name: Create Universal Binary
  run: |
    lipo -create \
      target/x86_64-apple-darwin/release/myapp \
      target/aarch64-apple-darwin/release/myapp \
      -output target/universal/myapp
8.4 缺少公证
# WRONG: Sign without notarization
codesign --sign "Developer ID" MyApp.app
# Users get Gatekeeper warnings!

# CORRECT: Sign and notarize
codesign --sign "Developer ID" --options runtime MyApp.app
xcrun notarytool submit MyApp.zip --apple-id "$APPLE_ID" --password "$APP_PASSWORD" --team-id "$TEAM_ID" --wait
xcrun stapler staple MyApp.app

13. 实施前检查清单

阶段 1:编写代码之前
  • 阅读所有特定平台的要求
  • 确定目标平台和架构
  • 编写用于验证构建配置的测试
  • 为所有目标设置 CI/CD 矩阵
  • 获取代码签名证书
  • 在 CI 环境中配置密钥
阶段 2:实施期间
  • 每次更改配置后运行测试
  • 验证增量构建正常工作
  • 通过条件编译测试特定平台的代码
  • 添加依赖项后检查打包体积
  • 验证所有平台均有对应图标
  • 在实际目标平台上测试(不只是 CI)
阶段 3:提交之前
  • 所有构建配置测试均已通过
  • Windows 证书为 EV 证书,或已建立良好信誉
  • macOS 应用已使用 Developer ID 签名
  • macOS 应用已完成公证并附加公证票据
  • Linux 软件包已使用 GPG 签名
  • 所有签名均使用时间戳
  • 签名凭据仅存储在 CI 密钥中
  • 构建构件均有校验和
  • 依赖项已固定版本
  • 构建日志不会泄露密钥
  • Windows SmartScreen 检查通过
  • macOS Gatekeeper 检查通过
  • 已在干净系统上测试安装程序
  • 自动更新 URL 使用 HTTPS

14. 总结

你的目标是创建具备以下特点的跨平台构建:

  • 正确签名:获得各操作系统的信任
  • 符合平台原生规范:遵循各平台的约定
  • 经过优化:文件大小合理,启动速度快

你需要了解,跨平台开发要求:

  1. 在每个目标平台上进行测试(不只是开发机器)
  2. 正确进行代码签名,以赢得用户信任
  3. 使用特定平台的配置和依赖项
  4. 了解分发要求

构建提醒:发布前务必在每个平台上进行测试。务必为发布版本签名。务必验证签名是否正常工作。如有疑问,请参阅 references/security-examples.md 中的签名流程。

评论

支持 Markdown