#!/bin/bash # build-ios.sh # Author: Matthew Raymer # Description: iOS build script for TimeSafari application # Date: 2025-07-11 # Exit on any error set -e # Source common utilities source "$(dirname "$0")/common.sh" # Default values BUILD_MODE="development" BUILD_TYPE="debug" OPEN_STUDIO=false BUILD_IPA=false BUILD_APP=false CLEAN_ONLY=false SYNC_ONLY=false ASSETS_ONLY=false DEPLOY_APP=false AUTO_RUN=false # Function to print iOS-specific usage print_ios_usage() { echo "Usage: $0 [options]" echo "" echo "iOS Build Options:" echo " --dev, --development Build for development environment" echo " --test Build for testing environment" echo " --prod, --production Build for production environment" echo " --debug Build debug app (default)" echo " --release Build release app" echo " --studio Open Xcode after build" echo " --ipa Build IPA file" echo " --app Build app bundle" echo " --clean Clean build artifacts only" echo " --sync Sync Capacitor only" echo " --assets Generate assets only" echo " --deploy Deploy app to connected device" echo " --auto-run Auto-run app after build" echo "" echo "Common Options:" echo " -h, --help Show this help message" echo " -v, --verbose Enable verbose logging" echo "" echo "Examples:" echo " $0 --dev --studio # Development build + open Xcode" echo " $0 --prod --ipa # Production IPA build" echo " $0 --test --app # Testing app build" echo " $0 --test --auto-run # Test build + auto-run" echo " $0 --clean # Clean only" echo " $0 --sync # Sync only" echo " $0 --deploy # Build and deploy to device" echo "" } # Function to parse iOS-specific arguments parse_ios_args() { for arg in "$@"; do case $arg in --dev|--development) BUILD_MODE="development" ;; --test) BUILD_MODE="test" ;; --prod|--production) BUILD_MODE="production" ;; --debug) BUILD_TYPE="debug" ;; --release) BUILD_TYPE="release" ;; --studio) OPEN_STUDIO=true ;; --ipa) BUILD_IPA=true ;; --app) BUILD_APP=true ;; --clean) CLEAN_ONLY=true ;; --sync) SYNC_ONLY=true ;; --assets) ASSETS_ONLY=true ;; --deploy) DEPLOY_APP=true ;; --auto-run) AUTO_RUN=true ;; -h|--help) print_ios_usage exit 0 ;; -v|--verbose) set -x ;; *) log_warn "Unknown argument: $arg" ;; esac done } # Function to validate iOS environment validate_ios_environment() { log_info "Validating iOS build environment..." # Check for Xcode if ! command -v xcodebuild &> /dev/null; then log_error "Xcode not found. Please install Xcode and command line tools." exit 1 fi # Check for iOS Simulator if ! command -v xcrun &> /dev/null; then log_error "Xcode command line tools not found. Please install with: xcode-select --install" exit 1 fi # Check for Capacitor if ! command -v npx &> /dev/null; then log_error "npx not found. Please install Node.js and npm." exit 1 fi # Check for iOS platform if [ ! -d "ios" ]; then log_error "iOS platform not found. Please run: npx cap add ios" exit 1 fi log_success "iOS build environment validated" } # Function to check iOS resources check_ios_resources() { log_info "Checking iOS resources..." # Check for required assets if [ ! -f "assets/icon.png" ]; then log_warning "App icon not found at assets/icon.png" fi if [ ! -f "assets/splash.png" ]; then log_warning "Splash screen not found at assets/splash.png" fi # Check for iOS-specific files if [ ! -f "ios/App/App/Info.plist" ]; then log_warning "Info.plist not found" fi if [ ! -f "ios/App/App/AppDelegate.swift" ]; then log_warning "AppDelegate.swift not found" fi log_success "iOS resource check completed" } # Function to clean iOS build clean_ios_build() { log_info "Cleaning iOS build artifacts..." # Clean Xcode build (temporary output directory) if [ -d "ios/App/build" ]; then rm -rf ios/App/build/ log_debug "Cleaned ios/App/build/" fi # Clean DerivedData if [ -d "ios/App/DerivedData" ]; then rm -rf ios/App/DerivedData/ log_debug "Cleaned ios/App/DerivedData/" fi # Clean Capacitor npx cap clean ios || true log_success "iOS build cleaned" } # Function to build iOS app build_ios_app() { local build_config="" local scheme="App" local destination="" if [ "$BUILD_TYPE" = "debug" ]; then build_config="Debug" destination="platform=iOS Simulator,name=iPhone 15 Pro" else build_config="Release" destination="platform=iOS,id=auto" fi log_info "Building iOS app (${build_config})..." cd ios/App # Build the app xcodebuild -workspace App.xcworkspace \ -scheme "$scheme" \ -configuration "$build_config" \ -destination "$destination" \ build \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO cd ../.. log_success "iOS app built successfully" } # Function to deploy to device deploy_ios_app() { log_info "Deploy-app mode: building app and deploying to device" # Check for connected device local devices=$(xcrun devicectl list devices --json | grep -c '"state":"booted"' || echo "0") if [ "$devices" -eq 0 ]; then log_error "No iOS device connected. Please connect a device and try again." exit 1 fi # Build app for device BUILD_TYPE="debug" build_ios_app # Get device ID local device_id=$(xcrun devicectl list devices --json | grep -o '"identifier":"[^"]*"' | head -1 | cut -d'"' -f4) if [ -z "$device_id" ]; then log_error "Could not find device ID. Please ensure device is connected and unlocked." exit 1 fi # Install app on device log_info "Installing app on device..." xcrun devicectl device install app --device "$device_id" ios/App/build/Debug-iphoneos/App.app log_success "iOS app deployed successfully to device!" log_info "You can now run the app with: npx cap run ios" } # Function to auto-run iOS app auto_run_ios_app() { log_step "Auto-running iOS app..." # Check if we're in debug mode (simulator) or release mode (device) if [ "$BUILD_TYPE" = "debug" ]; then log_info "Launching iOS Simulator and installing app" safe_execute "Launching app" "npx cap run ios" || { log_error "Failed to launch iOS app on simulator" return 1 } else log_info "Building and installing on real device" # For release builds, we need to use a different approach # since npx cap run ios is primarily for simulators log_warn "Auto-run for release builds requires manual device setup" log_info "Please use Xcode to run the app on your device" return 1 fi log_success "iOS app launched successfully!" } # Parse command line arguments parse_ios_args "$@" # Print build header print_header "TimeSafari iOS Build Process" log_info "Starting iOS build process at $(date)" log_info "Build mode: $BUILD_MODE" log_info "Build type: $BUILD_TYPE" # Setup environment for Capacitor build setup_build_env "capacitor" # Setup application directories setup_app_directories # Load environment from .env file if it exists load_env_file ".env" # Validate iOS environment validate_ios_environment # Handle clean-only mode if [ "$CLEAN_ONLY" = true ]; then log_info "Clean-only mode: cleaning build artifacts" clean_ios_build safe_execute "Cleaning dist directory" "clean_build_artifacts dist" || exit 1 log_success "Clean completed successfully!" exit 0 fi # Handle sync-only mode if [ "$SYNC_ONLY" = true ]; then log_info "Sync-only mode: syncing with Capacitor" safe_execute "Syncing with Capacitor" "npx cap sync ios" || exit 6 log_success "Sync completed successfully!" exit 0 fi # Handle assets-only mode if [ "$ASSETS_ONLY" = true ]; then log_info "Assets-only mode: generating assets" safe_execute "Generating assets" "npx capacitor-assets generate --ios" || exit 7 log_success "Assets generation completed successfully!" exit 0 fi # Handle deploy-app mode if [ "$DEPLOY_APP" = true ]; then deploy_ios_app exit 0 fi # Step 1: Check iOS resources check_ios_resources # Step 2: Clean iOS build safe_execute "Cleaning iOS build" "clean_ios_build" || exit 1 # Step 3: Clean dist directory log_info "Cleaning dist directory..." clean_build_artifacts "dist" # Step 4: Build Capacitor version with mode if [ "$BUILD_MODE" = "development" ]; then safe_execute "Building Capacitor version (development)" "npm run build:capacitor" || exit 3 elif [ "$BUILD_MODE" = "test" ]; then safe_execute "Building Capacitor version (test)" "npm run build:capacitor -- --mode test" || exit 3 elif [ "$BUILD_MODE" = "production" ]; then safe_execute "Building Capacitor version (production)" "npm run build:capacitor -- --mode production" || exit 3 fi # Step 5: Sync with Capacitor safe_execute "Syncing with Capacitor" "npx cap sync ios" || exit 6 # Step 6: Generate assets safe_execute "Generating assets" "npx capacitor-assets generate --ios" || exit 7 # Step 7: Build iOS app safe_execute "Building iOS app" "build_ios_app" || exit 5 # Step 8: Build IPA/App if requested if [ "$BUILD_IPA" = true ]; then log_info "Building IPA package..." cd ios/App xcodebuild -workspace App.xcworkspace \ -scheme App \ -configuration Release \ -archivePath build/App.xcarchive \ archive \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO xcodebuild -exportArchive \ -archivePath build/App.xcarchive \ -exportPath build/ \ -exportOptionsPlist exportOptions.plist cd ../.. log_success "IPA package built successfully" fi if [ "$BUILD_APP" = true ]; then log_info "Building app bundle..." # App bundle is already built in step 7 log_success "App bundle built successfully" fi # Step 9: Auto-run app if requested if [ "$AUTO_RUN" = true ]; then safe_execute "Auto-running iOS app" "auto_run_ios_app" || exit 9 fi # Step 10: Open Xcode if requested if [ "$OPEN_STUDIO" = true ]; then safe_execute "Opening Xcode" "npx cap open ios" || exit 8 fi # Print build summary log_success "iOS build completed successfully!" log_info "Build mode: $BUILD_MODE" log_info "Build type: $BUILD_TYPE" if [ "$BUILD_IPA" = true ]; then log_info "IPA build: completed" fi if [ "$BUILD_APP" = true ]; then log_info "App build: completed" fi if [ "$AUTO_RUN" = true ]; then log_info "Auto-run: completed" fi if [ "$OPEN_STUDIO" = true ]; then log_info "Xcode: opened" fi print_footer "iOS Build" # Exit with success exit 0