#!/bin/bash # build-ios.sh # Author: Matthew Raymer # Description: iOS build script for TimeSafari application # This script handles the complete iOS build process including cleanup, # web build, Capacitor build, asset generation, version management, and Xcode launch. # # Prerequisites: # - macOS with Xcode installed # - iOS development certificates configured # - Capacitor dependencies installed # # Usage: # ./scripts/build-ios.sh # Standard build and open Xcode # ./scripts/build-ios.sh --version 1.0.3 # Build with specific version # ./scripts/build-ios.sh --build-number 35 # Build with specific build number # ./scripts/build-ios.sh --no-xcode # Build without opening Xcode # ./scripts/build-ios.sh --help # Show help # ./scripts/build-ios.sh --verbose # Enable verbose logging # # NPM Script Equivalents: # npm run build:ios # Standard iOS build # npm run build:ios:release # Release build with version bump # # Exit Codes: # 1 - iOS cleanup failed # 2 - Web build failed # 3 - Capacitor build failed # 4 - Capacitor sync failed # 5 - Asset generation failed # 6 - Version update failed # 7 - Xcode project opening failed # 8 - Ruby/Gem environment setup failed # 9 - iOS directory structure validation failed # Exit on any error set -e # Source common utilities source "$(dirname "$0")/common.sh" # Default values VERSION="" BUILD_NUMBER="" OPEN_XCODE=true MARKETING_VERSION="" # Function to show usage show_usage() { cat << EOF Usage: $0 [OPTIONS] OPTIONS: --version VERSION Set marketing version (e.g., 1.0.3) --build-number NUMBER Set build number (e.g., 35) --marketing-version VER Set marketing version explicitly --no-xcode Skip opening Xcode after build --help Show this help message --verbose Enable verbose logging --debug Enable debug mode EXAMPLES: $0 # Standard build $0 --version 1.0.3 --build-number 35 # Build with specific version $0 --no-xcode # Build without opening Xcode $0 --verbose # Build with verbose output EOF } # Parse command line arguments parse_ios_args() { while [[ $# -gt 0 ]]; do case $1 in --version) VERSION="$2" MARKETING_VERSION="$2" shift 2 ;; --build-number) BUILD_NUMBER="$2" shift 2 ;; --marketing-version) MARKETING_VERSION="$2" shift 2 ;; --no-xcode) OPEN_XCODE=false shift ;; --help) show_usage exit 0 ;; --verbose) VERBOSE=true shift ;; --debug) DEBUG=true set -x shift ;; *) log_warn "Unknown option: $1" shift ;; esac done } # Function to validate iOS build environment validate_ios_environment() { log_info "Validating iOS build environment..." # Check if running on macOS if [[ "$(uname)" != "Darwin" ]]; then log_error "iOS builds require macOS" exit 9 fi # Check if Xcode is installed if ! command -v xcodebuild &> /dev/null; then log_error "Xcode is not installed or not in PATH" exit 9 fi # Check if iOS directory exists if [ ! -d "ios" ]; then log_error "iOS directory not found. Run 'npx cap add ios' first." exit 9 fi log_success "iOS build environment validated" } # Function to setup Ruby/Gem environment for Capacitor setup_ruby_environment() { log_info "Setting up Ruby/Gem environment..." # Check if we're in a pkgx environment and setup gem paths if command -v gem &> /dev/null; then gem_path=$(which gem) if [[ "$gem_path" == *"pkgx"* ]]; then log_info "Detected pkgx environment, setting up gem paths..." shortened_path="${gem_path%/*/*}" export GEM_HOME="$shortened_path" export GEM_PATH="$shortened_path" log_info "GEM_HOME set to: $GEM_HOME" fi else log_error "Ruby gem command not found" exit 8 fi log_success "Ruby/Gem environment configured" } # Function to setup iOS asset directories setup_ios_asset_directories() { log_info "Setting up iOS asset directories..." # Create required asset directories that capacitor-assets expects mkdir -p "ios/App/App/Assets.xcassets/AppIcon.appiconset" echo '{"images":[]}' > "ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json" mkdir -p "ios/App/App/Assets.xcassets/Splash.imageset" echo '{"images":[]}' > "ios/App/App/Assets.xcassets/Splash.imageset/Contents.json" log_success "iOS asset directories prepared" } # Function to update iOS version numbers update_ios_version() { if [ -n "$BUILD_NUMBER" ] || [ -n "$MARKETING_VERSION" ]; then log_info "Updating iOS version information..." cd ios/App # Update build number if provided if [ -n "$BUILD_NUMBER" ]; then log_info "Setting build number to: $BUILD_NUMBER" safe_execute "Updating build number" "xcrun agvtool new-version $BUILD_NUMBER" || exit 6 fi # Update marketing version if provided if [ -n "$MARKETING_VERSION" ]; then log_info "Setting marketing version to: $MARKETING_VERSION" safe_execute "Updating marketing version" "perl -p -i -e 's/MARKETING_VERSION = .*/MARKETING_VERSION = $MARKETING_VERSION;/g' App.xcodeproj/project.pbxproj" || exit 6 fi cd ../.. log_success "iOS version information updated" else log_info "No version updates requested" fi } # Parse command line arguments parse_ios_args "$@" # Print build header print_header "TimeSafari iOS Build Process" log_info "Starting iOS build process at $(date)" # Validate iOS build environment validate_ios_environment # 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" # Setup Ruby/Gem environment setup_ruby_environment # Step 1: Clean iOS app safe_execute "Cleaning iOS app" "npm run clean:ios || true" || exit 1 # Step 2: Clean dist directory log_info "Cleaning dist directory..." clean_build_artifacts "dist" # Step 3: Build web assets safe_execute "Building web assets" "npm run build:web" || exit 2 # Step 4: Build Capacitor version safe_execute "Building Capacitor version" "npm run build:capacitor" || exit 3 # Step 5: Sync with Capacitor safe_execute "Syncing with Capacitor" "npx cap sync ios" || exit 4 # Step 6: Setup iOS asset directories setup_ios_asset_directories # Step 7: Generate iOS assets safe_execute "Generating iOS assets" "npx capacitor-assets generate --ios" || exit 5 # Step 8: Update version information update_ios_version # Step 9: Open Xcode (if requested) if [ "$OPEN_XCODE" = true ]; then safe_execute "Opening Xcode" "npx cap open ios" || exit 7 log_info "Xcode opened. You can now build and run on simulator or device." log_info "Next steps in Xcode:" log_info " 1. Select Product -> Destination with a Simulator version" log_info " 2. Click the run arrow to build and test" log_info " 3. For release: Choose Product -> Destination -> Any iOS Device" log_info " 4. For release: Choose Product -> Archive" else log_info "Skipping Xcode opening as requested" fi # Print build summary log_success "iOS build completed successfully!" if [ -n "$BUILD_NUMBER" ] || [ -n "$MARKETING_VERSION" ]; then log_info "Version Information:" [ -n "$BUILD_NUMBER" ] && log_info " Build Number: $BUILD_NUMBER" [ -n "$MARKETING_VERSION" ] && log_info " Marketing Version: $MARKETING_VERSION" fi log_info "iOS project ready at: ios/App/" print_footer "iOS Build" # Exit with success exit 0