#!/bin/bash # BearVPN macOS 签名、公证和打包脚本 # 作者: AI Assistant # 日期: $(date) set -e # 配置变量 APP_NAME="BearVPN" APP_VERSION="1.0.0" DMG_NAME="${APP_NAME}-${APP_VERSION}-macOS-Signed" APP_PATH="build/macos/Build/Products/Release/${APP_NAME}.app" DMG_PATH="build/macos/Build/Products/Release/${DMG_NAME}.dmg" # 签名配置 DEVELOPER_ID="Developer ID Application: Civil Rights Corps (3UR892FAP3)" TEAM_ID="3UR892FAP3" APPLE_ID="kieran@newlifeephrata.us" APPLE_PASSWORD="Asd112211@" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # 检查证书 check_certificates() { log_info "检查开发者证书..." # 检查证书是否存在 if ! security find-certificate -a -c "Civil Rights Corps" > /dev/null 2>&1; then log_error "未找到 Developer ID Application 证书" log_info "请确保已安装有效的开发者证书" exit 1 fi log_success "找到 Developer ID Application 证书" } # 清理旧文件 cleanup() { log_info "清理旧的构建文件..." rm -rf build/macos/Build/Products/Release/* log_success "清理完成" } # 构建应用 build_app() { log_info "开始构建 macOS 应用..." flutter build macos --release if [ ! -d "$APP_PATH" ]; then log_error "应用构建失败" exit 1 fi log_success "应用构建完成" } # 签名应用 sign_app() { log_info "开始签名应用..." # 签名应用 codesign --force --deep --sign "$DEVELOPER_ID" "$APP_PATH" if [ $? -eq 0 ]; then log_success "应用签名成功" else log_error "应用签名失败" exit 1 fi # 验证签名 log_info "验证应用签名..." codesign --verify --verbose "$APP_PATH" if [ $? -eq 0 ]; then log_success "应用签名验证通过" else log_error "应用签名验证失败" exit 1 fi } # 创建 DMG create_dmg() { log_info "开始创建 DMG 文件..." # 使用 create-dmg 创建 DMG create-dmg \ --volname "$APP_NAME" \ --volicon "macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png" \ --window-pos 200 120 \ --window-size 600 400 \ --icon-size 100 \ --icon "$APP_NAME.app" 175 190 \ --hide-extension "$APP_NAME.app" \ --app-drop-link 425 190 \ --no-internet-enable \ "$DMG_PATH" \ "$APP_PATH" if [ $? -eq 0 ]; then log_success "DMG 文件创建成功: $DMG_PATH" else log_error "DMG 文件创建失败" exit 1 fi } # 签名 DMG sign_dmg() { log_info "开始签名 DMG 文件..." # 签名 DMG codesign --force --sign "$DEVELOPER_ID" "$DMG_PATH" if [ $? -eq 0 ]; then log_success "DMG 签名成功" else log_error "DMG 签名失败" exit 1 fi # 验证 DMG 签名 log_info "验证 DMG 签名..." codesign --verify --verbose "$DMG_PATH" if [ $? -eq 0 ]; then log_success "DMG 签名验证通过" else log_error "DMG 签名验证失败" exit 1 fi } # 公证应用 notarize_app() { log_info "开始公证应用..." # 创建 ZIP 文件用于公证 ZIP_PATH="build/macos/Build/Products/Release/${APP_NAME}-${APP_VERSION}.zip" ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" log_info "上传应用进行公证..." log_warning "请确保您已生成应用专用密码:" log_warning "1. 访问 https://appleid.apple.com" log_warning "2. 登录您的 Apple ID" log_warning "3. 在'安全'部分生成应用专用密码" log_warning "4. 使用该密码进行公证" # 上传进行公证 xcrun notarytool submit "$ZIP_PATH" \ --apple-id "$APPLE_ID" \ --team-id "$TEAM_ID" \ --wait if [ $? -eq 0 ]; then log_success "应用公证成功" # 装订公证票据 log_info "装订公证票据到应用..." xcrun stapler staple "$APP_PATH" if [ $? -eq 0 ]; then log_success "公证票据装订成功" else log_warning "公证票据装订失败,但应用已公证" fi else log_error "应用公证失败" log_info "请检查 Apple ID 和应用专用密码是否正确" exit 1 fi # 清理 ZIP 文件 rm -f "$ZIP_PATH" } # 公证 DMG notarize_dmg() { log_info "开始公证 DMG..." # 上传 DMG 进行公证 xcrun notarytool submit "$DMG_PATH" \ --apple-id "$APPLE_ID" \ --team-id "$TEAM_ID" \ --wait if [ $? -eq 0 ]; then log_success "DMG 公证成功" # 装订公证票据 log_info "装订公证票据到 DMG..." xcrun stapler staple "$DMG_PATH" if [ $? -eq 0 ]; then log_success "DMG 公证票据装订成功" else log_warning "DMG 公证票据装订失败,但 DMG 已公证" fi else log_error "DMG 公证失败" log_info "请检查 Apple ID 和应用专用密码是否正确" exit 1 fi } # 验证最终结果 verify_final() { log_info "验证最终结果..." # 检查文件大小 APP_SIZE=$(du -h "$APP_PATH" | cut -f1) DMG_SIZE=$(du -h "$DMG_PATH" | cut -f1) log_info "应用大小: $APP_SIZE" log_info "DMG 大小: $DMG_SIZE" # 检查签名状态 log_info "应用签名状态:" codesign -dv "$APP_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier|BundleId)" log_info "DMG 签名状态:" codesign -dv "$DMG_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier)" # 检查公证状态 log_info "应用公证状态:" xcrun stapler validate "$APP_PATH" log_info "DMG 公证状态:" xcrun stapler validate "$DMG_PATH" } # 显示结果 show_result() { log_success "==========================================" log_success "签名、公证和打包完成!" log_success "==========================================" log_info "应用名称: $APP_NAME" log_info "版本: $APP_VERSION" log_info "签名应用: $APP_PATH" log_info "签名 DMG: $DMG_PATH" log_info "开发者: $DEVELOPER_ID" log_success "==========================================" log_info "现在可以安全地分发给用户" log_info "用户安装时不会看到安全警告" log_info "应用已通过 Apple 公证,可在任何 Mac 上运行" log_success "==========================================" } # 主函数 main() { log_info "开始 BearVPN macOS 签名、公证和打包流程..." log_info "==========================================" check_certificates cleanup build_app sign_app notarize_app create_dmg sign_dmg notarize_dmg verify_final show_result log_success "所有操作完成!" } # 运行主函数 main "$@"