mcpField
M
macos-spm-app-packaging

macos-spm-app-packaging

github.com/patrickserrano開発1354 回インストール41 週間前に更新
リポジトリ

macos-spm-app-packaging について

Xcode を使わずに SwiftPM の macOS アプリを構成、ビルド、パッケージ化、リリースするためのスキルです。アプリバンドル、コード署名、公証、任意の Sparkle 更新メタデータを扱います。

主な機能

  1. 01SwiftPM アプリプロジェクトの構成
  2. 02SwiftPM によるビルドとテスト
  3. 03macOS .app バンドルの作成
  4. 04開発用またはリリース用の署名
  5. 05公証とリリース配布の手順
  6. 06任意の Sparkle appcast エントリー生成

活用シーン

  1. 01Xcode を使わず macOS アプリを開始
  2. 02SwiftPM の成果物をアプリバンドル化
  3. 03署名・公証済みリリースの準備
  4. 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 が更新されている

コメント