hi-client/sign_and_notarize.sh

234 lines
8.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
set -e
# ╔═══════════════════════════════════════════════════════════════════════════╗
# ║ HiFastVPN macOS 签名和公证脚本 ║
# ║ ║
# ║ 使用方法: ║
# ║ 1. 修改下面的配置变量 ║
# ║ 2. chmod +x sign_and_notarize.sh ║
# ║ 3. ./sign_and_notarize.sh ║
# ╚═══════════════════════════════════════════════════════════════════════════╝
# ======================== 配置变量(请修改这里)========================
SIGNING_IDENTITY="Developer ID Application: TAW TRADERS SDN. BHD. (NJRRF427XB)"
APPLE_ID="speakeloudest@gmail.com"
APP_PASSWORD="lvry-umfn-pqgz-lnwk" # App-specific password
TEAM_ID="NJRRF427XB"
# 路径配置
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
APP_PATH="${PROJECT_DIR}/hi-client/build/macos/Build/Products/Release/HiFastVPN.app"
ENTITLEMENTS="${PROJECT_DIR}/hi-client/macos/Runner/Release.entitlements"
OUTPUT_DIR="${PROJECT_DIR}/dist"
# =====================================================================
echo "╔═══════════════════════════════════════════════════════════════════╗"
echo "║ HiFastVPN macOS 签名和公证脚本 ║"
echo "╚═══════════════════════════════════════════════════════════════════╝"
echo ""
echo "📁 项目目录: ${PROJECT_DIR}"
echo "📦 应用路径: ${APP_PATH}"
echo "📄 Entitlements: ${ENTITLEMENTS}"
echo ""
# 检查 .app 是否存在
if [ ! -d "${APP_PATH}" ]; then
echo "❌ 错误: ${APP_PATH} 不存在"
echo "请先运行: flutter build macos --release"
exit 1
fi
# 检查 entitlements 是否存在
if [ ! -f "${ENTITLEMENTS}" ]; then
echo "❌ 错误: ${ENTITLEMENTS} 不存在"
exit 1
fi
# 创建输出目录
mkdir -p "${OUTPUT_DIR}"
# ======================== Step 1: 清理 ========================
echo ""
echo "🧹 Step 1: 清理多余文件..."
# 删除 .DS_Store
find "${APP_PATH}" -name ".DS_Store" -delete 2>/dev/null || true
find "${APP_PATH}" -name "*.bak" -delete 2>/dev/null || true
# 删除 Headers 目录和符号链接
find "${APP_PATH}/Contents/Frameworks" -type l -name "Headers" -delete 2>/dev/null || true
find "${APP_PATH}/Contents/Frameworks" -type d -name "Headers" -exec rm -rf {} + 2>/dev/null || true
# 删除 Modules 目录
find "${APP_PATH}/Contents/Frameworks" -type d -name "Modules" -exec rm -rf {} + 2>/dev/null || true
# 删除 PrivateHeaders
find "${APP_PATH}/Contents/Frameworks" -name "PrivateHeaders" -exec rm -rf {} + 2>/dev/null || true
echo " ✅ 清理完成"
# ======================== Step 2: 移除现有签名 ========================
echo ""
echo "🗑️ Step 2: 移除现有签名..."
# 移除所有签名(忽略错误)
find "${APP_PATH}" -name "*.dylib" -exec codesign --remove-signature {} \; 2>/dev/null || true
find "${APP_PATH}" -name "*.framework" -exec codesign --remove-signature {} \; 2>/dev/null || true
codesign --remove-signature "${APP_PATH}" 2>/dev/null || true
echo " ✅ 移除签名完成"
# ======================== Step 3: 签名 dylib 文件 ========================
echo ""
echo "🔐 Step 3: 签名 dylib 文件..."
find "${APP_PATH}" -name "*.dylib" -print0 | while IFS= read -r -d '' dylib; do
echo "$(basename "$dylib")"
codesign --force --sign "${SIGNING_IDENTITY}" \
--options runtime \
--timestamp \
"$dylib"
done
echo " ✅ dylib 签名完成"
# ======================== Step 4: 签名 Framework ========================
echo ""
echo "🔐 Step 4: 签名 Framework..."
# 签名所有 framework使用 --deep 确保内部资源被正确处理)
for fw in "${APP_PATH}"/Contents/Frameworks/*.framework; do
if [ -d "$fw" ]; then
fw_name=$(basename "$fw")
echo "${fw_name}"
# 使用 --deep 签名 framework这样会自动处理内部的资源
codesign --force --sign "${SIGNING_IDENTITY}" \
--options runtime \
--timestamp \
"$fw"
fi
done
echo " ✅ Framework 签名完成"
# ======================== Step 5: 签名主应用 ========================
echo ""
echo "🔐 Step 5: 签名主应用..."
codesign --force --sign "${SIGNING_IDENTITY}" \
--options runtime \
--entitlements "${ENTITLEMENTS}" \
--timestamp \
"${APP_PATH}"
echo " ✅ 主应用签名完成"
# ======================== Step 6: 验证签名 ========================
echo ""
echo "✅ Step 6: 验证签名..."
if codesign --verify --deep --strict --verbose=2 "${APP_PATH}" 2>&1; then
echo " ✅ 签名验证通过!"
else
echo " ❌ 签名验证失败!"
echo ""
echo "详细错误信息:"
codesign --verify --deep --strict --verbose=4 "${APP_PATH}" 2>&1
exit 1
fi
# ======================== Step 7: 创建 ZIP ========================
echo ""
echo "📦 Step 7: 创建 ZIP..."
ZIP_PATH="${OUTPUT_DIR}/HiFastVPN.zip"
rm -f "${ZIP_PATH}"
ditto -c -k --keepParent "${APP_PATH}" "${ZIP_PATH}"
echo " ✅ ZIP 创建完成: ${ZIP_PATH}"
# ======================== Step 8: 公证 ========================
echo ""
echo "📤 Step 8: 提交公证..."
echo " (这可能需要几分钟时间...)"
xcrun notarytool submit "${ZIP_PATH}" \
--apple-id "${APPLE_ID}" \
--password "${APP_PASSWORD}" \
--team-id "${TEAM_ID}" \
--wait
echo " ✅ 公证完成"
# ======================== Step 9: Staple ========================
echo ""
echo "📎 Step 9: Staple..."
xcrun stapler staple "${APP_PATH}"
echo " ✅ Staple 完成"
# ======================== Step 10: 最终验证 ========================
echo ""
echo "🔍 Step 10: 最终验证..."
echo ""
echo "--- codesign --verify ---"
codesign --verify --deep --strict "${APP_PATH}" && echo "✅ codesign 验证通过"
echo ""
echo "--- xcrun stapler validate ---"
xcrun stapler validate "${APP_PATH}"
echo ""
echo "--- spctl -a -t execute ---"
spctl -a -t execute -vv "${APP_PATH}"
# ======================== Step 11: 创建 DMG ========================
echo ""
echo "💿 Step 11: 创建 DMG..."
DMG_PATH="${OUTPUT_DIR}/HiFastVPN.dmg"
rm -f "${DMG_PATH}"
# 使用 hdiutil 创建简单的 DMG
hdiutil create -volname "HiFastVPN" -srcfolder "${APP_PATH}" -ov -format UDZO "${DMG_PATH}"
# 签名 DMG
# echo " 签名 DMG..."
# codesign --force --sign "${SIGNING_IDENTITY}" --timestamp "${DMG_PATH}"
# 公证 DMG
echo " 公证 DMG..."
xcrun notarytool submit "${DMG_PATH}" \
--apple-id "${APPLE_ID}" \
--password "${APP_PASSWORD}" \
--team-id "${TEAM_ID}" \
--wait
# Staple DMG
echo " Staple DMG..."
xcrun stapler staple "${DMG_PATH}"
echo " ✅ DMG 创建完成: ${DMG_PATH}"
# ======================== 完成 ========================
echo ""
echo "╔═══════════════════════════════════════════════════════════════════╗"
echo "║ 🎉 全部完成! ║"
echo "╚═══════════════════════════════════════════════════════════════════╝"
echo ""
echo "输出文件:"
echo " 📦 ${APP_PATH}"
echo " 📦 ${ZIP_PATH}"
echo " 💿 ${DMG_PATH}"
echo ""
echo "⚠️ 重要提示:"
echo " 发给用户的应该是 DMG 文件,不是 ZIP 或 .app"
echo " DMG 已经签名和公证,用户打开后不会被 Gatekeeper 拦截"
echo ""