#!/usr/bin/env bash # # run-ios-simulator.sh — install and launch VoiceCatiOS on an iPhone simulator. # # Picks a simulator in this order: # 1. Any already-booted iPhone simulator. # 2. The first available iPhone simulator (boots it, opens Simulator.app). # Pass --device or --udid to pin a specific device. # # Usage: # scripts/run-ios-simulator.sh # install + launch (Debug build) # scripts/run-ios-simulator.sh --config Release # scripts/run-ios-simulator.sh --device "iPhone 16 Pro" # scripts/run-ios-simulator.sh --udid # scripts/run-ios-simulator.sh --build # run build-ios-client.sh first # scripts/run-ios-simulator.sh --log # stream app logs after launch # scripts/run-ios-simulator.sh -h|--help # # The app is installed via `xcrun simctl install` and launched via # `xcrun simctl launch`. With --log, log lines stream to stdout until Ctrl+C # (this does not kill the app). # # Bundle ID: cat.voice.VoiceCatiOS # macOS only. Requires Xcode. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VC_SCRIPT_NAME="run-ios-simulator" source "$SCRIPT_DIR/common.sh" XCODE_CONFIG="Debug" DEVICE_FILTER="" DEVICE_UDID="" DO_BUILD=false DO_LOG=false while [[ $# -gt 0 ]]; do case "$1" in --config) XCODE_CONFIG="$2"; shift 2 ;; --device) DEVICE_FILTER="$2"; shift 2 ;; --udid) DEVICE_UDID="$2"; shift 2 ;; --build) DO_BUILD=true; shift ;; --log) DO_LOG=true; shift ;; -h|--help) vc_print_help "$0"; exit 0 ;; *) vc_die "unknown arg: $1 (try --help)" ;; esac done vc_require_macos # ── Optionally build first ───────────────────────────────────────────────────── if $DO_BUILD; then vc_step "building VoiceCatiOS" "$SCRIPT_DIR/build-ios-client.sh" --config "$XCODE_CONFIG" fi # ── Locate the .app ─────────────────────────────────────────────────────────── APP="$VC_REPO_ROOT/clients/apple/iOS/build/${XCODE_CONFIG}-iphonesimulator/VoiceCatiOS.app" if [[ ! -d "$APP" ]]; then vc_err "VoiceCatiOS.app not found at:" vc_err " $APP" vc_die "build it first with: scripts/build-ios-client.sh (or pass --build)" fi vc_log "app: $APP" # ── Find a simulator ────────────────────────────────────────────────────────── # Resolve: explicit UDID > explicit name filter > booted iPhone > any iPhone. find_sim() { # Each line from simctl looks like: # " iPhone 16 (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX) (Shutdown)" # The || true at the end prevents set -e from killing the script when no # matching device exists (grep -oE exits 1 on no match). local filter="${1:-}" state="${2:-}" local pattern="iPhone" [[ -n "$filter" ]] && pattern="$filter" xcrun simctl list devices available 2>/dev/null \ | grep -E "$pattern" \ | { [[ -n "$state" ]] && grep "$state" || cat; } \ | head -1 \ | grep -oE '[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}' \ | head -1 || true } sim_name() { xcrun simctl list devices available 2>/dev/null \ | grep "$1" | head -1 \ | sed 's/[[:space:]]*('"$1"').*//' | sed 's/^[[:space:]]*//' || true } if [[ -n "$DEVICE_UDID" ]]; then UDID="$DEVICE_UDID" elif [[ -n "$DEVICE_FILTER" ]]; then UDID="$(find_sim "$DEVICE_FILTER")" [[ -n "$UDID" ]] || vc_die "no available simulator matching '$DEVICE_FILTER'" else # Prefer a booted simulator; boot one if none is active. UDID="$(find_sim "" "Booted")" if [[ -z "$UDID" ]]; then UDID="$(find_sim "")" [[ -n "$UDID" ]] || vc_die "no iPhone simulator found. Install an iOS runtime: Xcode > Settings > Platforms > iOS." NAME="$(sim_name "$UDID")" vc_step "booting simulator: $NAME ($UDID)" xcrun simctl boot "$UDID" open -a Simulator # Wait for the simulator to finish booting before installing. vc_log "waiting for simulator to boot…" xcrun simctl bootstatus "$UDID" -b fi fi NAME="$(sim_name "$UDID")" vc_log "simulator: $NAME ($UDID)" # Bring Simulator.app to the foreground (no-op if already open). open -a Simulator # ── Install ─────────────────────────────────────────────────────────────────── vc_step "installing VoiceCatiOS" xcrun simctl install "$UDID" "$APP" vc_ok "installed -> $UDID" # ── Launch ──────────────────────────────────────────────────────────────────── BUNDLE_ID="cat.voice.VoiceCatiOS" vc_step "launching $BUNDLE_ID" xcrun simctl launch "$UDID" "$BUNDLE_ID" vc_ok "launched — VoiceCat is running on $NAME" # ── Optional log streaming ──────────────────────────────────────────────────── if $DO_LOG; then vc_log "streaming logs (Ctrl+C to stop — does not kill the app)" xcrun simctl spawn "$UDID" log stream --predicate "subsystem contains \"VoiceCat\"" fi