#!/bin/bash # iOS 自动化构建脚本 # 支持开发版本和分发版本的构建 set -e # 颜色输出 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_environment() { log_info "检查构建环境..." # 检查 Flutter if ! command -v flutter &> /dev/null; then log_error "Flutter 未安装或不在 PATH 中" exit 1 fi # 检查 Xcode if ! command -v xcodebuild &> /dev/null; then log_error "Xcode 未安装或不在 PATH 中" exit 1 fi # 检查必要的环境变量 if [ -z "$APPLE_ID" ] || [ -z "$TEAM_ID" ] || [ -z "$BUNDLE_ID" ]; then log_error "请先运行: source ios_signing_config.sh" exit 1 fi log_success "环境检查通过" } # 检查证书 check_certificates() { log_info "检查开发者证书..." # 检查开发证书 if ! security find-identity -v -p codesigning | grep -q "iPhone Developer\|Apple Development"; then log_error "未找到有效的开发证书" log_info "请确保已安装开发者证书" exit 1 fi log_success "找到有效的开发证书" } # 清理构建 clean_build() { log_info "清理之前的构建..." flutter clean rm -rf build/ios rm -rf ios/build log_success "清理完成" } # 获取依赖 get_dependencies() { log_info "获取 Flutter 依赖..." flutter pub get log_success "依赖获取完成" } # 构建 iOS 应用 build_ios_app() { local build_type=$1 local configuration=$2 log_info "开始构建 iOS 应用 (${build_type})..." # 设置构建参数 local build_args="--release" if [ "$build_type" = "debug" ]; then build_args="--debug" fi # 构建 Flutter 应用 flutter build ios $build_args --no-codesign # 检查构建结果 local app_path="build/ios/iphoneos/Runner.app" if [ ! -d "$app_path" ]; then log_error "iOS 应用构建失败: $app_path 不存在" exit 1 fi log_success "iOS 应用构建完成: $app_path" } # 签名应用 sign_app() { local app_path=$1 local identity=$2 local provisioning_profile=$3 log_info "开始签名应用..." # 移除旧的签名 codesign --remove-signature "$app_path" # 签名应用 codesign --force --sign "$identity" \ --entitlements ios/Runner/Runner.entitlements \ "$app_path" # 验证签名 codesign --verify --verbose "$app_path" if [ $? -eq 0 ]; then log_success "应用签名成功" else log_error "应用签名失败" exit 1 fi } # 创建 IPA 文件 create_ipa() { local app_path=$1 local ipa_path=$2 log_info "创建 IPA 文件..." # 创建 Payload 目录 local payload_dir="build/ios/Payload" mkdir -p "$payload_dir" # 复制应用 cp -R "$app_path" "$payload_dir/" # 创建 IPA cd build/ios zip -r "${ipa_path##*/}" Payload/ cd ../.. # 清理 Payload 目录 rm -rf "$payload_dir" if [ -f "$ipa_path" ]; then log_success "IPA 文件创建成功: $ipa_path" else log_error "IPA 文件创建失败" exit 1 fi } # 创建 DMG 文件 create_dmg() { local ipa_path=$1 local dmg_path=$2 log_info "创建 DMG 文件..." # 创建临时目录 local temp_dir="build/ios/temp_dmg" mkdir -p "$temp_dir" # 复制 IPA 到临时目录 cp "$ipa_path" "$temp_dir/" # 创建 DMG hdiutil create -srcfolder "$temp_dir" \ -volname "BearVPN iOS" \ -fs HFS+ \ -format UDZO \ -imagekey zlib-level=9 \ "$dmg_path" # 清理临时目录 rm -rf "$temp_dir" if [ -f "$dmg_path" ]; then log_success "DMG 文件创建成功: $dmg_path" else log_error "DMG 文件创建失败" exit 1 fi } # 验证构建结果 verify_build() { local ipa_path=$1 local dmg_path=$2 log_info "验证构建结果..." # 检查文件大小 local ipa_size=$(du -h "$ipa_path" | cut -f1) local dmg_size=$(du -h "$dmg_path" | cut -f1) log_info "IPA 大小: $ipa_size" log_info "DMG 大小: $dmg_size" # 验证 IPA 内容 unzip -l "$ipa_path" | grep -q "Payload/Runner.app" if [ $? -eq 0 ]; then log_success "IPA 内容验证通过" else log_error "IPA 内容验证失败" exit 1 fi } # 显示构建结果 show_result() { local ipa_path=$1 local dmg_path=$2 log_success "==========================================" log_success "iOS 构建完成!" log_success "==========================================" log_info "应用名称: $APP_NAME" log_info "版本: $VERSION" log_info "Bundle ID: $BUNDLE_ID" log_info "IPA 文件: $ipa_path" log_info "DMG 文件: $dmg_path" log_info "开发者: $SIGNING_IDENTITY" log_success "==========================================" log_info "现在可以安装到设备或上传到 App Store" log_success "==========================================" } # 主函数 main() { local build_type=${1:-"release"} log_info "开始 iOS 构建流程..." log_info "构建类型: $build_type" log_info "==========================================" check_environment check_certificates clean_build get_dependencies build_ios_app "$build_type" # 设置路径 local app_path="build/ios/iphoneos/Runner.app" local ipa_path="$IPA_PATH" local dmg_path="$DMG_PATH" # 创建输出目录 mkdir -p "$(dirname "$ipa_path")" mkdir -p "$(dirname "$dmg_path")" # 签名应用 sign_app "$app_path" "$SIGNING_IDENTITY" "" # 创建 IPA create_ipa "$app_path" "$ipa_path" # 创建 DMG create_dmg "$ipa_path" "$dmg_path" # 验证结果 verify_build "$ipa_path" "$dmg_path" # 显示结果 show_result "$ipa_path" "$dmg_path" log_success "所有操作完成!" } # 显示帮助信息 show_help() { echo "iOS 自动化构建脚本" echo "" echo "用法: $0 [选项]" echo "" echo "选项:" echo " debug 构建调试版本" echo " release 构建发布版本 (默认)" echo " help 显示此帮助信息" echo "" echo "示例:" echo " $0 # 构建发布版本" echo " $0 debug # 构建调试版本" echo " $0 release # 构建发布版本" echo "" echo "注意: 请先运行 'source ios_signing_config.sh' 配置签名信息" } # 处理命令行参数 case "${1:-}" in "help"|"-h"|"--help") show_help exit 0 ;; "debug"|"release") main "$1" ;; "") main "release" ;; *) log_error "未知选项: $1" show_help exit 1 ;; esac