macos-spm-app-packaging について
Xcode を使わずに SwiftPM の macOS アプリを構成、ビルド、パッケージ化、リリースするためのスキルです。アプリバンドル、コード署名、公証、任意の Sparkle 更新メタデータを扱います。
主な機能
- 01SwiftPM アプリプロジェクトの構成
- 02SwiftPM によるビルドとテスト
- 03macOS .app バンドルの作成
- 04開発用またはリリース用の署名
- 05公証とリリース配布の手順
- 06任意の Sparkle appcast エントリー生成
活用シーン
- 01Xcode を使わず macOS アプリを開始
- 02SwiftPM の成果物をアプリバンドル化
- 03署名・公証済みリリースの準備
- 04バージョン付き GitHub リリースの公開
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ patrickserrano/ skills --skill macos-spm-app-packagingインストール後、Claude Code で/macos-spm-app-packagingを入力して読み込まれたか確認します。
詳細
macOS SwiftPM アプリのパッケージ化
概要
完全な SwiftPM macOS アプリを立ち上げ、Xcode を使わずにビルド、パッケージ化、実行します。このスキルでは、プロジェクトのひな形作成からリリース配布までのワークフロー全体を扱います。
プロジェクトのひな形作成
基本構成
MyApp/
├── Package.swift
├── Sources/
│ └── MyApp/
│ ├── MyApp.swift # @main App entry
│ └── ContentView.swift
├── Resources/
│ ├── Assets.xcassets/
│ └── Info.plist
├── Scripts/
│ ├── package_app.sh
│ ├── compile_and_run.sh
│ └── sign-and-notarize.sh
└── version.env
Package.swift
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "MyApp",
platforms: [.macOS(.v14)],
products: [
.executable(name: "MyApp", targets: ["MyApp"])
],
targets: [
.executableTarget(
name: "MyApp",
resources: [
.process("Resources")
]
)
]
)
version.env
APP_NAME="MyApp"
BUNDLE_ID="com.example.myapp"
VERSION="1.0.0"
BUILD_NUMBER="1"
MIN_MACOS="14.0"
# Set to 1 for menu bar apps
MENU_BAR_APP=0
ビルドと実行
SwiftPM でビルド
# Debug build
swift build
# Release build
swift build -c release
# Run tests
swift test
.app バンドルとしてパッケージ化
Scripts/package_app.sh を作成します。
#!/bin/bash
set -e
source version.env
BUILD_DIR=".build/release"
APP_BUNDLE="$BUILD_DIR/$APP_NAME.app"
CONTENTS="$APP_BUNDLE/Contents"
MACOS="$CONTENTS/MacOS"
RESOURCES="$CONTENTS/Resources"
# Build release
swift build -c release
# Create bundle structure
rm -rf "$APP_BUNDLE"
mkdir -p "$MACOS" "$RESOURCES"
# Copy binary
cp "$BUILD_DIR/$APP_NAME" "$MACOS/"
# Copy resources
cp -r Resources/* "$RESOURCES/" 2>/dev/null || true
# Generate Info.plist
cat > "$CONTENTS/Info.plist" << EOF
<?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>CFBundleExecutable</key>
<string>$APP_NAME</string>
<key>CFBundleIdentifier</key>
<string>$BUNDLE_ID</string>
<key>CFBundleName</key>
<string>$APP_NAME</string>
<key>CFBundleVersion</key>
<string>$BUILD_NUMBER</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION</string>
<key>LSMinimumSystemVersion</key>
<string>$MIN_MACOS</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
$([ "$MENU_BAR_APP" = "1" ] && echo " <key>LSUIElement</key>
<true/>")
</dict>
</plist>
EOF
echo "Created $APP_BUNDLE"
開発用実行スクリプト
Scripts/compile_and_run.sh を作成します。
#!/bin/bash
set -e
source version.env
# Kill existing instance
pkill -x "$APP_NAME" 2>/dev/null || true
# Package
./Scripts/package_app.sh
# Launch
open ".build/release/$APP_NAME.app"
コード署名
開発用署名
# Sign for local development
codesign --force --sign - ".build/release/MyApp.app"
# Or with a specific identity
codesign --force --sign "Developer ID Application: Your Name" ".build/release/MyApp.app"
安定した開発用 ID を作成
# Generate self-signed certificate for consistent dev signing
security create-keychain -p "" dev-signing.keychain
security default-keychain -s dev-signing.keychain
# Follow prompts in Keychain Access to create certificate
公証とリリース
Scripts/sign-and-notarize.sh を作成します。
#!/bin/bash
set -e
source version.env
APP_PATH=".build/release/$APP_NAME.app"
ZIP_PATH=".build/release/$APP_NAME-$VERSION.zip"
# Sign with Developer ID
codesign --force --options runtime --sign "Developer ID Application: Your Name" "$APP_PATH"
# Create zip for notarization
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
# Submit for notarization
xcrun notarytool submit "$ZIP_PATH" \
--apple-id "[email protected]" \
--team-id "TEAM_ID" \
--password "@keychain:AC_PASSWORD" \
--wait
# Staple the ticket
xcrun stapler staple "$APP_PATH"
# Re-zip with stapled ticket
rm "$ZIP_PATH"
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
echo "Release ready: $ZIP_PATH"
Sparkle アップデート(任意)
Appcast エントリーを生成
#!/bin/bash
source version.env
ZIP_PATH=".build/release/$APP_NAME-$VERSION.zip"
SIZE=$(stat -f%z "$ZIP_PATH")
SIGNATURE=$(./bin/sign_update "$ZIP_PATH")
DATE=$(date -R)
cat << EOF
<item>
<title>Version $VERSION</title>
<pubDate>$DATE</pubDate>
<sparkle:version>$BUILD_NUMBER</sparkle:version>
<sparkle:shortVersionString>$VERSION</sparkle:shortVersionString>
<enclosure
url="https://example.com/releases/$APP_NAME-$VERSION.zip"
length="$SIZE"
type="application/octet-stream"
sparkle:edSignature="$SIGNATURE"
/>
</item>
EOF
GitHub リリース
# Create tag
git tag -a "v$VERSION" -m "Release $VERSION"
git push origin "v$VERSION"
# Create GitHub release
gh release create "v$VERSION" \
".build/release/$APP_NAME-$VERSION.zip" \
--title "v$VERSION" \
--notes "Release notes here"
チェックリスト
ひな形作成
- 適切なターゲットとリソースを含む Package.swift
- アプリのメタデータを含む version.env
- Info.plist テンプレートまたは生成スクリプト
- 基本的なアプリのエントリーポイント(@main App)
ビルド
-
swift buildが成功する -
swift testが合格する - リソースが正しくコピーされる
パッケージ化
- .app バンドルの構成が正しい
- Info.plist が正しい値で生成される
- Finder からアプリを起動できる
リリース
- Developer ID でコード署名されている
- 公証され、チケットが付与されている
- 配布用の Zip が作成されている
- (任意)Sparkle の appcast が更新されている
コメント
Markdown 対応