#!/bin/bash # iOS 앱 빌드 스크립트 (디버그 및 릴리즈 버전) # 사용법: ./build-ios.sh # 색상 정의 GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' # No Color # 프로젝트 디렉토리로 이동 cd "$(dirname "$0")" # 프로젝트 파일 경로 XCODEPROJ_FILE="ios/App/App.xcodeproj/project.pbxproj" # 현재 버전 및 빌드 번호 가져오기 if [ -f "$XCODEPROJ_FILE" ]; then MARKETING_VERSION=$(grep -A 1 "MARKETING_VERSION" "$XCODEPROJ_FILE" | grep -o 'MARKETING_VERSION = [0-9]\+\.[0-9]\+\(\.[0-9]\+\)*' | sed 's/MARKETING_VERSION = //' | head -1) CURRENT_PROJECT_VERSION=$(grep -A 1 "CURRENT_PROJECT_VERSION" "$XCODEPROJ_FILE" | grep -o '[0-9]\+' | head -1) echo -e "${YELLOW}현재 버전 정보:${NC}" echo -e "마케팅 버전: ${GREEN}$MARKETING_VERSION${NC}" echo -e "빌드 번호: ${GREEN}$CURRENT_PROJECT_VERSION${NC}" # 설정 파일 확인 및 로드 CONFIG_FILE="$HOME/.zellyy_ios_build.conf" if [ -f "$CONFIG_FILE" ]; then source "$CONFIG_FILE" fi # 버전 수정 여부 확인 echo -e "\n${YELLOW}버전 정보를 수정하시겠습니까? (y/n) [${LAST_VERSION_CHOICE:-n}]:${NC}" read -r UPDATE_VERSION UPDATE_VERSION=${UPDATE_VERSION:-${LAST_VERSION_CHOICE:-n}} if [[ "$UPDATE_VERSION" == "y" || "$UPDATE_VERSION" == "Y" ]]; then echo -e "\n${YELLOW}새 마케팅 버전을 입력하세요 (현재: $MARKETING_VERSION) [${LAST_MARKETING_VERSION:-$MARKETING_VERSION}]:${NC}" read -r NEW_MARKETING_VERSION NEW_MARKETING_VERSION=${NEW_MARKETING_VERSION:-${LAST_MARKETING_VERSION:-$MARKETING_VERSION}} if [ -z "$NEW_MARKETING_VERSION" ]; then NEW_MARKETING_VERSION=$MARKETING_VERSION fi echo -e "${YELLOW}새 빌드 번호를 입력하세요 (현재: $CURRENT_PROJECT_VERSION) [${LAST_BUILD_NUMBER:-$CURRENT_PROJECT_VERSION}]:${NC}" read -r NEW_PROJECT_VERSION NEW_PROJECT_VERSION=${NEW_PROJECT_VERSION:-${LAST_BUILD_NUMBER:-$CURRENT_PROJECT_VERSION}} if [ -z "$NEW_PROJECT_VERSION" ]; then NEW_PROJECT_VERSION=$CURRENT_PROJECT_VERSION fi # 버전 정보 업데이트 # macOS에서는 sed -i에 백업 확장자를 지정해야 함 sed -i '' "s/MARKETING_VERSION = [0-9][0-9]*\.[0-9][0-9]*\(\.[0-9][0-9]*\)*/MARKETING_VERSION = $NEW_MARKETING_VERSION/g" "$XCODEPROJ_FILE" sed -i '' "s/CURRENT_PROJECT_VERSION = $CURRENT_PROJECT_VERSION;/CURRENT_PROJECT_VERSION = $NEW_PROJECT_VERSION;/g" "$XCODEPROJ_FILE" echo -e "\n${GREEN}버전 정보가 업데이트되었습니다:${NC}" echo -e "마케팅 버전: ${GREEN}$NEW_MARKETING_VERSION${NC}" echo -e "빌드 번호: ${GREEN}$NEW_PROJECT_VERSION${NC}" # 설정 저장 echo "LAST_VERSION_CHOICE=y" > "$CONFIG_FILE" echo "LAST_MARKETING_VERSION=$NEW_MARKETING_VERSION" >> "$CONFIG_FILE" echo "LAST_BUILD_NUMBER=$NEW_PROJECT_VERSION" >> "$CONFIG_FILE" else echo -e "${YELLOW}현재 버전 정보를 유지합니다.${NC}" # 설정 저장 echo "LAST_VERSION_CHOICE=n" > "$CONFIG_FILE" fi else echo -e "${RED}프로젝트 파일을 찾을 수 없습니다: $XCODEPROJ_FILE${NC}" exit 1 fi # 빌드 타입 선택 메뉴 echo -e "\n${YELLOW}Zellyy Finance iOS 앱 빌드 스크립트${NC}" echo -e "${YELLOW}=============================${NC}" echo -e "빌드 타입을 선택하세요:" echo -e "1) 디버그 빌드 (개발 및 테스트용)" echo -e "2) 릴리즈 빌드 (App Store 배포용)" echo -e "3) 종료" echo -n "선택 (1-3) [${LAST_BUILD_TYPE:-1}]: " read -r CHOICE CHOICE=${CHOICE:-${LAST_BUILD_TYPE:-1}} case $CHOICE in 1) BUILD_TYPE="debug" CONFIGURATION="Debug" echo "LAST_BUILD_TYPE=1" >> "$CONFIG_FILE" ;; 2) BUILD_TYPE="release" CONFIGURATION="Release" echo "LAST_BUILD_TYPE=2" >> "$CONFIG_FILE" ;; 3) echo -e "${YELLOW}빌드를 취소합니다.${NC}" exit 0 ;; *) echo -e "${RED}잘못된 선택입니다. 빌드를 취소합니다.${NC}" exit 1 ;; esac echo -e "${YELLOW}Zellyy Finance iOS 앱 빌드 시작 (${BUILD_TYPE}, 마케팅 버전: ${MARKETING_VERSION}, 빌드 번호: ${NEW_PROJECT_VERSION}): $(date)${NC}" # 빌드 디렉토리 문제 해결 echo -e "${YELLOW}빌드 디렉토리 준비 중...${NC}" BUILD_DIR="ios/App/build" if [ -d "$BUILD_DIR" ]; then echo -e "${YELLOW}기존 빌드 디렉토리에 Xcode 빌드 시스템 속성 추가 중...${NC}" xattr -w com.apple.xcode.CreatedByBuildSystem true "$BUILD_DIR" else echo -e "${YELLOW}빌드 디렉토리 생성 중...${NC}" mkdir -p "$BUILD_DIR" xattr -w com.apple.xcode.CreatedByBuildSystem true "$BUILD_DIR" fi # 캐시 정리 echo -e "${YELLOW}캐시 정리 중...${NC}" if [ -d "node_modules/.cache" ]; then rm -rf node_modules/.cache fi if [ -d "ios/App/App/public" ]; then rm -rf ios/App/App/public fi # 1. 웹 앱 빌드 echo -e "${YELLOW}1. 웹 앱 빌드 중...${NC}" npm run build if [ $? -ne 0 ]; then echo -e "${RED}웹 앱 빌드 실패. 빌드 프로세스를 중단합니다.${NC}" exit 1 fi echo -e "${GREEN}웹 앱 빌드 완료${NC}" # 2. Capacitor에 웹 코드 복사 및 동기화 echo -e "${YELLOW}2. Capacitor에 웹 코드 동기화 중...${NC}" npx cap sync ios if [ $? -ne 0 ]; then echo -e "${RED}Capacitor 동기화 실패. 빌드 프로세스를 중단합니다.${NC}" exit 1 fi echo -e "${GREEN}Capacitor 동기화 완료${NC}" # 3. iOS 앱 빌드 echo -e "${YELLOW}3. iOS 빌드 시작 (${BUILD_TYPE})...${NC}" # 빌드 타입에 따라 다른 명령어 실행 cd ios/App if [ "$BUILD_TYPE" = "debug" ]; then # 디버그 빌드 echo -e "${YELLOW}빌드 대상을 선택하세요:${NC}" echo -e "1) 시뮬레이터용 빌드" echo -e "2) 실제 기기용 빌드" echo -n "선택 (1-2): " read -r TARGET_CHOICE case $TARGET_CHOICE in 1) # 시뮬레이터용 빌드 echo -e "${YELLOW}시뮬레이터용 빌드 시작...${NC}" xcodebuild -workspace App.xcworkspace -scheme App -configuration Debug -sdk iphonesimulator -derivedDataPath build if [ $? -ne 0 ]; then echo -e "${RED}디버그 빌드 실패. 오류를 확인하세요.${NC}" exit 1 fi echo -e "${GREEN}시뮬레이터용 빌드 성공!${NC}" echo -e "앱 파일 위치: $(pwd)/build/Build/Products/Debug-iphonesimulator/App.app" # 시뮬레이터 실행 여부 확인 echo -e "${YELLOW}iOS 시뮬레이터에서 앱을 실행하시겠습니까? (y/n)${NC}" read -r RUN_SIMULATOR if [ "$RUN_SIMULATOR" = "y" ] || [ "$RUN_SIMULATOR" = "Y" ]; then # 사용 가능한 시뮬레이터 목록 표시 echo -e "${YELLOW}사용 가능한 시뮬레이터:${NC}" xcrun simctl list devices available | grep -v "unavailable" | grep "^ " echo -e "${YELLOW}시뮬레이터 이름을 입력하세요 (예: iPhone 15):${NC}" read -r SIMULATOR_NAME # 시뮬레이터 UDID 가져오기 SIMULATOR_UDID=$(xcrun simctl list devices available | grep "$SIMULATOR_NAME" | grep -o -E '[A-Za-z0-9\-]{36}' | head -1) if [ -z "$SIMULATOR_UDID" ]; then echo -e "${RED}시뮬레이터를 찾을 수 없습니다. 정확한 이름을 입력하세요.${NC}" exit 1 fi # 시뮬레이터 실행 echo -e "${YELLOW}시뮬레이터 실행 중...${NC}" open -a Simulator --args -CurrentDeviceUDID "$SIMULATOR_UDID" # 앱 설치 및 실행 xcrun simctl install "$SIMULATOR_UDID" "$(pwd)/build/Build/Products/Debug-iphonesimulator/App.app" xcrun simctl launch "$SIMULATOR_UDID" "io.ionic.starter" echo -e "${GREEN}앱이 시뮬레이터에서 실행 중입니다.${NC}" fi ;; 2) # 실제 기기용 빌드 echo -e "${YELLOW}실제 기기용 빌드 시작...${NC}" # 개발자 계정 정보 입력 echo -e "${YELLOW}Apple 개발자 계정 이메일을 입력하세요 [${LAST_APPLE_ID:-}]:${NC}" read -r APPLE_ID APPLE_ID=${APPLE_ID:-${LAST_APPLE_ID:-}} # 설정 저장 echo "LAST_APPLE_ID=$APPLE_ID" >> "$CONFIG_FILE" # 연결된 기기 확인 echo -e "${YELLOW}연결된 iOS 기기 확인 중...${NC}" DEVICE_LIST=$(xcrun xctrace list devices | grep -v "^==" | sed '/^$/d') # 실제 기기와 시뮬레이터 분리 REAL_DEVICES=$(echo "$DEVICE_LIST" | grep -v "Simulator" | grep -v "MacBook" | grep -v "Mac") SIMULATORS=$(echo "$DEVICE_LIST" | grep "Simulator" || echo "") # 기기 목록 표시 echo -e "${YELLOW}연결된 실제 기기:${NC}" if [ -z "$REAL_DEVICES" ]; then echo "연결된 실제 기기가 없습니다." echo "USB 케이블로 iOS 기기를 연결하고 다시 시도하세요." echo "또는 시뮬레이터를 사용하려면 시뮬레이터용 빌드를 선택하세요." exit 1 fi # 실제 기기 목록 표시 (번호 부여) DEVICE_COUNTER=1 DEVICE_ARRAY=() DEVICE_ID_ARRAY=() while IFS= read -r line; do DEVICE_NAME=$(echo "$line" | sed -E 's/^(.*) \(([0-9\.]+)\) \((.*)\)$/\1/') DEVICE_OS=$(echo "$line" | sed -E 's/^(.*) \(([0-9\.]+)\) \((.*)\)$/\2/') DEVICE_ID=$(echo "$line" | sed -E 's/^(.*) \(([0-9\.]+)\) \((.*)\)$/\3/') echo "$DEVICE_COUNTER) $DEVICE_NAME (iOS $DEVICE_OS)" DEVICE_ARRAY+=("$DEVICE_NAME") DEVICE_ID_ARRAY+=("$DEVICE_ID") ((DEVICE_COUNTER++)) done <<< "$REAL_DEVICES" # 기기 선택 echo -e "${YELLOW}빌드 및 설치할 기기 번호를 선택하세요 [${LAST_DEVICE_INDEX:-1}]:${NC}" read -r DEVICE_INDEX DEVICE_INDEX=${DEVICE_INDEX:-${LAST_DEVICE_INDEX:-1}} # 인덱스 범위 검증 if ! [[ "$DEVICE_INDEX" =~ ^[0-9]+$ ]] || [ "$DEVICE_INDEX" -lt 1 ] || [ "$DEVICE_INDEX" -gt ${#DEVICE_ARRAY[@]} ]; then echo -e "${RED}잘못된 기기 번호입니다. 1부터 ${#DEVICE_ARRAY[@]} 사이의 숫자를 입력하세요.${NC}" exit 1 fi # 선택된 기기 정보 SELECTED_INDEX=$((DEVICE_INDEX-1)) DEVICE_NAME="${DEVICE_ARRAY[$SELECTED_INDEX]}" DEVICE_ID="${DEVICE_ID_ARRAY[$SELECTED_INDEX]}" echo -e "${YELLOW}선택된 기기: $DEVICE_NAME (ID: $DEVICE_ID)${NC}" # 설정 저장 echo "LAST_DEVICE_INDEX=$DEVICE_INDEX" >> "$CONFIG_FILE" # 디버그 빌드 및 기기 설치 echo -e "${YELLOW}디버그 빌드 및 기기 설치 중...${NC}" # 프로비저닝 프로파일 자동 관리 옵션으로 빌드 xcodebuild -workspace App.xcworkspace -scheme App -configuration Debug -destination "id=$DEVICE_ID" -allowProvisioningUpdates -derivedDataPath build if [ $? -ne 0 ]; then echo -e "${RED}디버그 빌드 실패. 오류를 확인하세요.${NC}" echo -e "${YELLOW}가능한 원인:${NC}" echo "1. 개발자 계정이 유효하지 않거나 로그인되지 않음" echo "2. 프로비저닝 프로파일이 없거나 유효하지 않음" echo "3. 기기가 개발자 모드로 설정되지 않음" exit 1 fi echo -e "${GREEN}디버그 빌드 및 기기 설치 성공!${NC}" # IPA 파일 생성 여부 확인 echo -e "${YELLOW}IPA 파일을 생성하시겠습니까? (y/n)${NC}" read -r CREATE_IPA if [ "$CREATE_IPA" = "y" ] || [ "$CREATE_IPA" = "Y" ]; then echo -e "${YELLOW}디버그용 IPA 파일 생성 중...${NC}" # 아카이브 생성 xcodebuild -workspace App.xcworkspace -scheme App -configuration Debug -destination "generic/platform=iOS" clean archive -archivePath "build/App.xcarchive" -allowProvisioningUpdates if [ $? -ne 0 ]; then echo -e "${RED}아카이브 생성 실패. 오류를 확인하세요.${NC}" exit 1 fi # 익스포트 옵션 파일 생성 cat > build/ExportOptions.plist << EOF method development teamID 54RZTAU6NX compileBitcode provisioningProfiles com.lovable.zellyfinance iOS Team Provisioning Profile: com.lovable.zellyfinance EOF # IPA 생성 xcodebuild -exportArchive -archivePath "build/App.xcarchive" -exportPath "build/export" -exportOptionsPlist "build/ExportOptions.plist" -allowProvisioningUpdates if [ $? -ne 0 ]; then echo -e "${RED}IPA 생성 실패. 오류를 확인하세요.${NC}" exit 1 fi # IPA 파일 이동 DEBUG_IPA_PATH="build/export/App.ipa" DEBUG_DEST_PATH="$HOME/Dev/zellyy-debug.ipa" if [ -f "$DEBUG_IPA_PATH" ]; then echo -e "${GREEN}디버그용 IPA 파일 생성 성공!${NC}" echo -e "IPA 파일 위치: $(pwd)/$DEBUG_IPA_PATH" # Dev 디렉토리로 IPA 복사 cp "$DEBUG_IPA_PATH" "$DEBUG_DEST_PATH" echo -e "${GREEN}IPA를 Dev 디렉토리에 복사했습니다: $DEBUG_DEST_PATH${NC}" echo -e "${YELLOW}다음 방법으로 다른 기기에 설치할 수 있습니다:${NC}" echo "1. Apple Configurator 2 앱 사용" echo "2. iTunes를 통한 설치" echo "3. 무선 설치 서비스 사용" else echo -e "${RED}IPA 파일을 찾을 수 없습니다.${NC}" fi fi ;; *) echo -e "${RED}잘못된 선택입니다. 빌드를 취소합니다.${NC}" exit 1 ;; esac elif [ "$BUILD_TYPE" = "release" ]; then # 릴리즈 빌드 echo -e "${YELLOW}릴리즈 빌드 시작...${NC}" # 개발자 계정 정보 입력 echo -e "${YELLOW}Apple 개발자 계정 이메일을 입력하세요 [${LAST_APPLE_ID:-}]:${NC}" read -r APPLE_ID APPLE_ID=${APPLE_ID:-${LAST_APPLE_ID:-}} # 설정 저장 echo "LAST_APPLE_ID=$APPLE_ID" >> "$CONFIG_FILE" # 연결된 기기 확인 echo -e "${YELLOW}연결된 iOS 기기 확인 중...${NC}" DEVICE_LIST=$(xcrun xctrace list devices | grep -v "^==" | sed '/^$/d') # 실제 기기와 시뮬레이터 분리 REAL_DEVICES=$(echo "$DEVICE_LIST" | grep -v "Simulator" | grep -v "MacBook" | grep -v "Mac") SIMULATORS=$(echo "$DEVICE_LIST" | grep "Simulator" || echo "") # 기기 목록 표시 echo -e "${YELLOW}연결된 실제 기기:${NC}" if [ -z "$REAL_DEVICES" ]; then echo "연결된 실제 기기가 없습니다." echo "USB 케이블로 iOS 기기를 연결하고 다시 시도하세요." exit 1 fi # 실제 기기 목록 표시 (번호 부여) DEVICE_COUNTER=1 DEVICE_ARRAY=() DEVICE_ID_ARRAY=() while IFS= read -r line; do DEVICE_NAME=$(echo "$line" | sed -E 's/^(.*) \(([0-9\.]+)\) \((.*)\)$/\1/') DEVICE_OS=$(echo "$line" | sed -E 's/^(.*) \(([0-9\.]+)\) \((.*)\)$/\2/') DEVICE_ID=$(echo "$line" | sed -E 's/^(.*) \(([0-9\.]+)\) \((.*)\)$/\3/') echo "$DEVICE_COUNTER) $DEVICE_NAME (iOS $DEVICE_OS)" DEVICE_ARRAY+=("$DEVICE_NAME") DEVICE_ID_ARRAY+=("$DEVICE_ID") ((DEVICE_COUNTER++)) done <<< "$REAL_DEVICES" # 기기 선택 echo -e "${YELLOW}빌드 및 설치할 기기 번호를 선택하세요 [${LAST_DEVICE_INDEX:-1}]:${NC}" read -r DEVICE_INDEX DEVICE_INDEX=${DEVICE_INDEX:-${LAST_DEVICE_INDEX:-1}} # 인덱스 범위 검증 if ! [[ "$DEVICE_INDEX" =~ ^[0-9]+$ ]] || [ "$DEVICE_INDEX" -lt 1 ] || [ "$DEVICE_INDEX" -gt ${#DEVICE_ARRAY[@]} ]; then echo -e "${RED}잘못된 기기 번호입니다. 1부터 ${#DEVICE_ARRAY[@]} 사이의 숫자를 입력하세요.${NC}" exit 1 fi # 선택된 기기 정보 SELECTED_INDEX=$((DEVICE_INDEX-1)) DEVICE_NAME="${DEVICE_ARRAY[$SELECTED_INDEX]}" DEVICE_ID="${DEVICE_ID_ARRAY[$SELECTED_INDEX]}" echo -e "${YELLOW}선택된 기기: $DEVICE_NAME (ID: $DEVICE_ID)${NC}" # 설정 저장 echo "LAST_DEVICE_INDEX=$DEVICE_INDEX" >> "$CONFIG_FILE" # 아카이브 생성 echo -e "${YELLOW}App Store 배포용 아카이브 생성 중...${NC}" xcodebuild -workspace App.xcworkspace -scheme App -configuration Release -destination "id=$DEVICE_ID" clean archive -archivePath "build/App.xcarchive" -allowProvisioningUpdates if [ $? -ne 0 ]; then echo -e "${RED}아카이브 생성 실패. 오류를 확인하세요.${NC}" exit 1 fi # 익스포트 옵션 파일 생성 cat > build/ExportOptions.plist << EOF method app-store teamID 54RZTAU6NX uploadSymbols uploadBitcode provisioningProfiles com.lovable.zellyfinance Zellyy Finance Distribution EOF # IPA 생성 echo -e "${YELLOW}App Store 제출용 IPA 파일 생성 중...${NC}" xcodebuild -exportArchive -archivePath "build/App.xcarchive" -exportPath "build/export" -exportOptionsPlist "build/ExportOptions.plist" -allowProvisioningUpdates if [ $? -ne 0 ]; then echo -e "${RED}IPA 생성 실패. 오류를 확인하세요.${NC}" exit 1 fi IPA_PATH="build/export/App.ipa" DEST_PATH="$HOME/Dev/zellyy-release/zellyy-ios.ipa" if [ -f "$IPA_PATH" ]; then echo -e "${GREEN}IPA 파일 생성 성공!${NC}" echo -e "IPA 파일 위치: $(pwd)/$IPA_PATH" # 저장 디렉토리 확인 및 생성 RELEASE_DIR="$HOME/Dev/zellyy-release" if [ ! -d "$RELEASE_DIR" ]; then mkdir -p "$RELEASE_DIR" fi # Dev 디렉토리로 IPA 복사 cp "$IPA_PATH" "$DEST_PATH" echo -e "${GREEN}IPA를 저장했습니다: $DEST_PATH${NC}" echo -e "${YELLOW}다음 단계:${NC}" echo "1. App Store Connect에 로그인: https://appstoreconnect.apple.com" echo "2. 앱 업로드 도구(Application Loader)를 사용하여 IPA 파일 업로드" echo "3. 또는 다음 명령어로 직접 업로드: xcrun altool --upload-app -f \"$DEST_PATH\" -t ios -u \"$APPLE_ID\" -p \"앱 전용 비밀번호\"" else echo -e "${RED}IPA 파일을 찾을 수 없습니다.${NC}" fi else echo -e "${RED}알 수 없는 빌드 타입입니다: $BUILD_TYPE${NC}" exit 1 fi echo -e "\n${GREEN}빌드 프로세스가 완료되었습니다.${NC}" echo -e "빌드 종료 시간: $(date)" exit 0