Cross-Platform Build Expert について
Cross-Platform Build Expert は、Windows、macOS、Linux 向けに Tauri デスクトップアプリを構築する開発者向けのスキルです。プラットフォーム設定、署名と配布、CI ビルド、最適化を扱い、セキュリティとテストにも重点を置きます。
主な機能
- 01Tauri のマルチプラットフォームビルド設定
- 02Windows、macOS、Linux のターゲット
- 03コード署名と公証のガイダンス
- 04CI ビルドマトリクスのパターン
- 05ビルドサイズと性能の最適化
活用シーン
- 01Tauri のマルチプラットフォームビルド設定
- 02署名付きアプリリリースの準備
- 03各プラットフォーム向け CI の設定
- 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. 基本原則
- まず TDD - 実装前にビルド設定のテストを書く
- パフォーマンスを意識する - ビルド時間、バンドルサイズ、起動時間を最適化する
- すべての対象プラットフォームでテストする - クロスプラットフォームの互換性を決めつけない
- プラットフォーム抽象化を利用する - プラットフォーム間の違いには Rust std と Tauri API を使用する
- パスの違いに対処する - スラッシュとバックスラッシュ、大文字と小文字の区別
- プラットフォームの慣例を尊重する - ファイルの配置場所、UI ガイドライン
- すべてのリリースに署名する - ユーザーは署名済みアプリケーションを信頼します
- 署名資格情報を保護する - 証明書を決してコミットしない
- 署名を検証する - 配布前に確認する
- タイムスタンプを使用する - 証明書の有効期限が切れた後も署名が有効であるようにする
3. 技術的な基礎
3.1 プラットフォームのビルドターゲット
| プラットフォーム | Rust ターゲット | Tauri バンドル |
|---|---|---|
| Windows x64 | x86_64-pc-windows-msvc | msi, nsis |
| Windows ARM | aarch64-pc-windows-msvc | msi, nsis |
| macOS Intel | x86_64-apple-darwin | dmg, app |
| macOS Apple Silicon | aarch64-apple-darwin | dmg, app |
| Linux x64 | x86_64-unknown-linux-gnu | deb, appimage |
| Linux ARM | aarch64-unknown-linux-gnu | deb, appimage |
3.2 ビルドの依存関係
Windows:
- Visual Studio Build Tools
- Windows SDK
- WebView2 Runtime(Tauri がバンドル)
macOS:
- Xcode Command Line Tools
- Apple Developer Certificate
- 公証用のアプリ固有パスワード
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 コード署名の要件
| プラットフォーム | 証明書の種類 | 用途 |
|---|---|---|
| Windows | EV Code Signing | SmartScreen の信頼を即座に獲得 |
| Windows | Standard Code Signing | 評判の獲得後に信頼を得る |
| macOS | Developer ID Application | App Store 外での配布 |
| macOS | Developer ID Installer | 署名済み PKG インストーラー |
| Linux | GPG Key | パッケージ署名 |
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. まとめ
目標は、次の条件を満たすクロスプラットフォームビルドを作成することです。
- 適切に署名されている:各オペレーティングシステムから信頼される
- プラットフォームに適合している:各プラットフォームの慣例に従っている
- 最適化されている:ファイルサイズが妥当で、起動が速い
クロスプラットフォーム開発では、次の点が必要です。
- 各対象プラットフォームでテストする(開発マシンだけで済ませない)
- ユーザーからの信頼を得るため、適切にコード署名する
- プラットフォーム固有の設定と依存関係を管理する
- 配布要件を把握する
ビルド時の注意:リリース前には、必ず各プラットフォームでテストしてください。必ずリリースに署名してください。署名が正しく機能することを必ず確認してください。不明な場合は、署名手順について references/security-examples.md を参照してください。