#!/bin/bash # ======================================== # MiniPlayer macOS 打包脚本 # 生成 .app bundle + .dmg 安装包 # ======================================== set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" BUILD_DIR="$PROJECT_DIR/.build/release" APP_NAME="MiniPlayer" BUNDLE_ID="com.miniplayer.app" VERSION=$(date +%Y.%m.%d) APP_BUNDLE="$PROJECT_DIR/$APP_NAME.app" DMG_OUTPUT="$PROJECT_DIR/$APP_NAME-$VERSION.dmg" echo "=== MiniPlayer macOS 打包 ===" echo "项目目录: $PROJECT_DIR" echo "版本: $VERSION" echo "" # 1. 清理旧构建 echo "[1/6] 清理旧构建..." rm -rf "$APP_BUNDLE" rm -f "$DMG_OUTPUT" # 2. 编译 Release echo "[2/6] 编译 Release 版本..." cd "$PROJECT_DIR" swift build -c release echo " ✓ 编译完成" # 3. 创建 .app bundle 结构 echo "[3/6] 创建 .app bundle..." mkdir -p "$APP_BUNDLE/Contents/MacOS" mkdir -p "$APP_BUNDLE/Contents/Resources/i18n" mkdir -p "$APP_BUNDLE/Contents/Resources/zh-Hans.lproj" mkdir -p "$APP_BUNDLE/Contents/Resources/en.lproj" # 4. 拷贝文件 echo "[4/6] 拷贝文件..." # 可执行文件 cp "$BUILD_DIR/$APP_NAME" "$APP_BUNDLE/Contents/MacOS/" # 资源文件 cp "$PROJECT_DIR/Sources/Resources/miniplayer.ui" "$APP_BUNDLE/Contents/Resources/" cp "$PROJECT_DIR/Sources/Resources/i18n/en.json" "$APP_BUNDLE/Contents/Resources/i18n/" cp "$PROJECT_DIR/Sources/Resources/i18n/zh.json" "$APP_BUNDLE/Contents/Resources/i18n/" cp "$PROJECT_DIR/Sources/Resources/zh-Hans.lproj/Localizable.strings" "$APP_BUNDLE/Contents/Resources/zh-Hans.lproj/" cp "$PROJECT_DIR/Sources/Resources/en.lproj/Localizable.strings" "$APP_BUNDLE/Contents/Resources/en.lproj/" # App 图标(如果有) if [ -f "$PROJECT_DIR/Resources/AppIcon.icns" ]; then cp "$PROJECT_DIR/Resources/AppIcon.icns" "$APP_BUNDLE/Contents/Resources/" ICON_FILE="AppIcon.icns" else ICON_FILE="" fi # 5. 生成 Info.plist echo "[5/6] 生成 Info.plist..." cat > "$APP_BUNDLE/Contents/Info.plist" < CFBundleExecutable $APP_NAME CFBundleIdentifier $BUNDLE_ID CFBundleName $APP_NAME CFBundleDisplayName MiniPlayer CFBundleVersion $VERSION CFBundleShortVersionString $VERSION CFBundlePackageType APPL CFBundleInfoDictionaryVersion 6.0 LSMinimumSystemVersion 14.0 NSHighResolutionCapable LSApplicationCategoryType public.app-category.entertainment NSHumanReadableCopyright Copyright © $(date +%Y) MiniPlayer. All rights reserved. CFBundleIconFile ${ICON_FILE:-} CFBundleResourceSpecification NSSupportsAutomaticTermination NSSupportsSuddenTermination NSCameraUsageDescription MiniPlayer 需要摄像头权限来扫描二维码添加播放地址。 NSMicrophoneUsageDescription MiniPlayer 需要麦克风权限来录制音频。 PLIST echo " ✓ .app bundle 创建完成: $APP_BUNDLE" # 6. 创建 DMG echo "[6/6] 创建 DMG 安装包..." DMG_TEMP="$PROJECT_DIR/.dmg_temp" DMG_RW="$PROJECT_DIR/.dmg_rw.dmg" DMG_SIZE="200m" mkdir -p "$DMG_TEMP" cp -R "$APP_BUNDLE" "$DMG_TEMP/" # 创建 Applications 快捷方式 ln -s /Applications "$DMG_TEMP/Applications" # 创建临时 DMG hdiutil create -srcfolder "$DMG_TEMP" -volname "$APP_NAME" \ -fs HFS+ -fsargs "-c c=64,a=16,e=16" \ -format UDRW -size "$DMG_SIZE" "$DMG_RW" 2>/dev/null # 转换为压缩 DMG hdiutil convert "$DMG_RW" -format UDZO -imagekey zlib-level=9 -o "$DMG_OUTPUT" 2>/dev/null # 清理临时文件 rm -rf "$DMG_TEMP" rm -f "$DMG_RW" echo " ✓ DMG 创建完成: $DMG_OUTPUT" # 显示结果 echo "" echo "==============================" echo " 打包完成!" echo "==============================" echo " .app: $APP_BUNDLE" echo " .dmg: $DMG_OUTPUT" APP_SIZE=$(du -sh "$APP_BUNDLE" | cut -f1) DMG_SIZE=$(du -sh "$DMG_OUTPUT" | cut -f1) echo " .app 大小: $APP_SIZE" echo " .dmg 大小: $DMG_SIZE" echo "" echo " 双击 .app 直接运行" echo " 双击 .dmg 安装(拖入 Applications)"