docs+scripts: add iOS build and simulator run commands
scripts/build-ios-client.sh: builds VoiceCatiOS.app for iOS simulator
- calls build-xcframework.sh --all (all 3 slices required for iOS sim slice)
- xcodebuild -target VoiceCatiOS with SYMROOT=OBJROOT to co-locate SPM
and app build products (fixes "unable to resolve module dependency" error)
- stages result to dist/ios-client/
scripts/run-ios-simulator.sh: installs and launches on an iPhone simulator
- finds a booted simulator or boots the first available iPhone sim
- opens Simulator.app, installs via simctl install, launches via simctl launch
- --build flag to build first; --log to stream app logs; --device / --udid to
pin a specific simulator
scripts/build-all.sh: add --ios-client opt-in flag (macOS only)
docs/building.md:
- add iOS entry to quick-nav table
- update §6 (apple platform): remove "scaffolding" caveat now that iOS slices
are validated; trim to essentials + pointer to build-xcframework.sh
- add §9 (iOS client SwiftUI): XCFramework, xcodebuild command with rationale
for -target/-SYMROOT flags, run script usage, full simctl commands, Xcode UI
This commit is contained in:
156
docs/building.md
156
docs/building.md
@@ -14,7 +14,9 @@ and *how to drive the binaries by hand*.
|
||||
| Server + `vccli` + tests (all platforms) | [§3](#3-build--test-the-loop-youll-run-constantly) | `cmake --preset dev && cmake --build --preset dev && ctest --preset dev` |
|
||||
| Production server (stripped, no tests) | [§5](#5-server-release-production-shaped-build) | `cmake --preset server-release && cmake --build --preset server-release` |
|
||||
| Windows client (C# / WinForms) | [§7](#7-windows-client-c--winforms) | `dotnet build clients/windows/VoiceCat.slnx` |
|
||||
| macOS client (AppKit) | [§8](#8-macos-client-appkit) | `xcodebuild -project clients/apple/macOS/VoiceCatMac.xcodeproj -scheme VoiceCatMac build` |
|
||||
| macOS client (AppKit) | [§8](#8-macos-client-appkit) | `scripts/build-macos-client.sh` |
|
||||
| iOS client (SwiftUI / simulator) | [§9](#9-ios-client-swiftui) | `scripts/build-ios-client.sh` |
|
||||
| Launch iOS app on simulator | [§9](#9-ios-client-swiftui) | `scripts/run-ios-simulator.sh` |
|
||||
| Swift core + tests | [§8](#8-macos-client-appkit) | `cd clients/apple && swift test` |
|
||||
|
||||
## 1. What each preset is for
|
||||
@@ -214,13 +216,11 @@ Use this to sanity-check release-mode behavior (e.g. perf, optimized codepaths)
|
||||
day-to-day development, since it has no test target wired up. The `-s` linker flag strips
|
||||
symbol tables from the binaries, producing smaller executables suitable for distribution.
|
||||
|
||||
## 6. Apple platform builds (scaffolding)
|
||||
## 6. Apple platform builds
|
||||
|
||||
The `apple-dev`, `apple-ios`, and `apple-ios-sim` presets produce static `libvoicecat.a`
|
||||
slices for the Swift Package / XCFramework. The `apple-dev` preset (macOS slice) is
|
||||
**validated** — it builds green on macOS 26.5 / Apple Silicon and produces a valid arm64
|
||||
`.a` + XCFramework. The iOS cross-compile presets (`apple-ios`, `apple-ios-sim`) are still
|
||||
**scaffolding** — not yet CI-validated. Build on macOS:
|
||||
slices for the Swift Package / XCFramework. All three are validated on macOS 26.5 / Apple
|
||||
Silicon. Build on macOS:
|
||||
|
||||
```bash
|
||||
# macOS slice (arm64-osx on Apple Silicon, x64-osx on Intel)
|
||||
@@ -228,22 +228,31 @@ cmake --preset apple-dev
|
||||
cmake --build --preset apple-dev
|
||||
# → build/apple-dev/lib/libvoicecat.a
|
||||
|
||||
# iOS device slice
|
||||
# iOS device slice (arm64-ios)
|
||||
cmake --preset apple-ios
|
||||
cmake --build --preset apple-ios
|
||||
# → build/apple-ios/lib/libvoicecat.a
|
||||
|
||||
# iOS simulator slice
|
||||
# iOS simulator slice (arm64-ios-simulator)
|
||||
cmake --preset apple-ios-sim
|
||||
cmake --build --preset apple-ios-sim
|
||||
# → build/apple-ios-sim/lib/libvoicecat.a
|
||||
```
|
||||
|
||||
The three `.a` files are then stitched into an XCFramework via `xcodebuild
|
||||
-create-xcframework` (see [clients/apple/README.md](../clients/apple/README.md) for the
|
||||
planned workflow). Actual XCFramework stitching, `AVAudioSession` integration, and iOS
|
||||
UI work are tracked as follow-up tasks — the presets exist so the build entry point is ready
|
||||
when that work starts.
|
||||
You rarely need to run these CMake commands directly. The
|
||||
`clients/apple/scripts/build-xcframework.sh` script drives them internally and stitches
|
||||
the result into a self-contained `VoiceCatCore.xcframework`:
|
||||
|
||||
```bash
|
||||
# macOS slice only (default — used by macOS AppKit client)
|
||||
clients/apple/scripts/build-xcframework.sh
|
||||
|
||||
# All 3 slices (macOS + iOS device + iOS sim — required for iOS client)
|
||||
clients/apple/scripts/build-xcframework.sh --all
|
||||
```
|
||||
|
||||
See [clients/apple/README.md](../clients/apple/README.md) for the XCFramework internals
|
||||
(fat static lib merge, module map staging).
|
||||
|
||||
## 7. Windows client (C# / WinForms)
|
||||
|
||||
@@ -347,3 +356,124 @@ open clients/apple/macOS/VoiceCatMac.xcodeproj
|
||||
# Terminal 2 — launch the client
|
||||
open ~/Library/Developer/Xcode/DerivedData/VoiceCatMac-*/Build/Products/Debug/VoiceCatMac.app
|
||||
```
|
||||
|
||||
Or use the per-artifact script which builds and stages to `dist/macos-client/`:
|
||||
|
||||
```bash
|
||||
scripts/build-macos-client.sh
|
||||
```
|
||||
|
||||
## 9. iOS client (SwiftUI)
|
||||
|
||||
The iOS client is an Xcode project (`clients/apple/iOS/VoiceCatiOS.xcodeproj`) that
|
||||
links `libvoicecat` via the same `VoiceCatCore` Swift Package as the macOS client.
|
||||
Full details in [`clients/apple/README.md`](../clients/apple/README.md).
|
||||
|
||||
**Prerequisites:** Xcode, vcpkg (`VCPKG_ROOT` set), iOS Simulator runtime installed
|
||||
(Xcode > Settings > Platforms > iOS). iOS deployment target: 17.0.
|
||||
|
||||
### Build the XCFramework (all slices)
|
||||
|
||||
The iOS build requires the `ios-arm64-simulator` slice in the XCFramework — not just the
|
||||
macOS slice. Use the `--all` flag to produce all three slices:
|
||||
|
||||
```bash
|
||||
clients/apple/scripts/build-xcframework.sh --all
|
||||
# → clients/apple/VoiceCatCore.xcframework/
|
||||
# ├── macos-arm64/
|
||||
# ├── ios-arm64/
|
||||
# └── ios-arm64-simulator/
|
||||
```
|
||||
|
||||
### Build the iOS simulator app
|
||||
|
||||
```bash
|
||||
# Via the convenience script (recommended):
|
||||
scripts/build-ios-client.sh
|
||||
# → clients/apple/iOS/build/Debug-iphonesimulator/VoiceCatiOS.app
|
||||
# → dist/ios-client/VoiceCatiOS.app
|
||||
|
||||
# Or as a single command (what the script does under the hood):
|
||||
SIM_SDK="iphonesimulator$(xcrun --sdk iphonesimulator --show-sdk-version)"
|
||||
BUILD_DIR="$(pwd)/clients/apple/iOS/build"
|
||||
xcodebuild \
|
||||
-project clients/apple/iOS/VoiceCatiOS.xcodeproj \
|
||||
-target VoiceCatiOS \
|
||||
-sdk "$SIM_SDK" \
|
||||
-configuration Debug \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
ARCHS=arm64 \
|
||||
ONLY_ACTIVE_ARCH=YES \
|
||||
SYMROOT="$BUILD_DIR" \
|
||||
OBJROOT="$BUILD_DIR" \
|
||||
build
|
||||
```
|
||||
|
||||
**Why `-target` instead of `-scheme -destination`?** Using `-scheme VoiceCatiOS
|
||||
-destination 'platform=iOS Simulator,OS=latest'` requires a simulator runtime whose iOS
|
||||
version exactly matches the SDK version (`iphonesimulatorX.Y`). If you have an older
|
||||
runtime installed (common when the SDK ships ahead of runtime availability in Xcode), the
|
||||
build fails with "Unable to find a destination matching the provided destination specifier."
|
||||
Using `-target` bypasses destination matching and builds against the SDK directly.
|
||||
|
||||
**Why `SYMROOT=OBJROOT=clients/apple/iOS/build`?** When building with `-target` (not
|
||||
`-scheme`), the local Swift Package (`VoiceCatCore`) resolves its build products relative
|
||||
to `OBJROOT`. By default, SPM resolves into `clients/apple/build/`, while the app target
|
||||
looks in `clients/apple/iOS/build/`. Pointing both to the same directory fixes the
|
||||
"unable to resolve module dependency: 'VoiceCatCore'" error.
|
||||
|
||||
### Run on the iOS Simulator
|
||||
|
||||
```bash
|
||||
# Via the script (finds or boots an iPhone simulator, installs, launches):
|
||||
scripts/run-ios-simulator.sh
|
||||
|
||||
# Build and run in one step:
|
||||
scripts/run-ios-simulator.sh --build
|
||||
|
||||
# Stream app logs after launch:
|
||||
scripts/run-ios-simulator.sh --log
|
||||
|
||||
# Target a specific device by name or UDID:
|
||||
scripts/run-ios-simulator.sh --device "iPhone 16 Pro"
|
||||
scripts/run-ios-simulator.sh --udid XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
||||
```
|
||||
|
||||
Under the hood the script uses `xcrun simctl` commands:
|
||||
|
||||
```bash
|
||||
# Boot a simulator (if not already running):
|
||||
xcrun simctl boot <UDID>
|
||||
open -a Simulator
|
||||
|
||||
# Install the built .app:
|
||||
xcrun simctl install <UDID> clients/apple/iOS/build/Debug-iphonesimulator/VoiceCatiOS.app
|
||||
|
||||
# Launch the app:
|
||||
xcrun simctl launch <UDID> cat.voice.VoiceCatiOS
|
||||
|
||||
# Stream logs (Ctrl+C to stop — does not kill the app):
|
||||
xcrun simctl spawn <UDID> log stream --predicate 'subsystem contains "VoiceCat"'
|
||||
```
|
||||
|
||||
### Run the full stack (server + iOS simulator)
|
||||
|
||||
```bash
|
||||
# Terminal 1 — start the server
|
||||
./build/dev/bin/voicecat-server --name "My Server"
|
||||
|
||||
# Terminal 2 — build + launch iOS client on simulator
|
||||
scripts/run-ios-simulator.sh --build
|
||||
```
|
||||
|
||||
On first connect the app will show a TOFU identity sheet — accept it, then join a channel.
|
||||
|
||||
### Open in Xcode
|
||||
|
||||
```bash
|
||||
open clients/apple/iOS/VoiceCatiOS.xcodeproj
|
||||
```
|
||||
|
||||
Xcode can build and run on the simulator directly. The XCFramework must already exist
|
||||
(`clients/apple/VoiceCatCore.xcframework/`) — run `build-xcframework.sh --all` once
|
||||
before opening Xcode.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# dist/. Convenience wrapper over the per-artifact scripts in scripts/.
|
||||
#
|
||||
# On macOS: server + libs (macOS slice + xcframework) + macos-client (.app)
|
||||
# optionally: iOS client for simulator (pass --ios-client)
|
||||
# On Windows: server + libs (windows DLL) + windows-client (.exe folder)
|
||||
# On Linux: server only (no native client presets target Linux)
|
||||
#
|
||||
@@ -14,6 +15,7 @@
|
||||
# scripts/build-all.sh --skip-client # skip the GUI client(s)
|
||||
# scripts/build-all.sh --skip-libs # skip the library artifacts
|
||||
# scripts/build-all.sh --skip-server # skip the server
|
||||
# scripts/build-all.sh --ios-client # also build iOS simulator client (macOS only)
|
||||
# scripts/build-all.sh -h|--help
|
||||
set -euo pipefail
|
||||
|
||||
@@ -25,6 +27,7 @@ PASS_ARGS=()
|
||||
SKIP_CLIENT=false
|
||||
SKIP_LIBS=false
|
||||
SKIP_SERVER=false
|
||||
BUILD_IOS_CLIENT=false
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dist) PASS_ARGS+=( --dist "$2" ); vc_set_dist "$2"; shift 2 ;;
|
||||
@@ -32,6 +35,7 @@ while [[ $# -gt 0 ]]; do
|
||||
--skip-client) SKIP_CLIENT=true; shift ;;
|
||||
--skip-libs) SKIP_LIBS=true; shift ;;
|
||||
--skip-server) SKIP_SERVER=true; shift ;;
|
||||
--ios-client) BUILD_IOS_CLIENT=true; shift ;;
|
||||
-h|--help) vc_print_help "$0"; exit 0 ;;
|
||||
*) vc_die "unknown arg: $1 (try --help)" ;;
|
||||
esac
|
||||
@@ -61,6 +65,7 @@ fi
|
||||
if ! $SKIP_CLIENT; then
|
||||
if [[ "$HOST" == "macos" ]]; then
|
||||
run build-macos-client.sh
|
||||
$BUILD_IOS_CLIENT && run build-ios-client.sh
|
||||
elif [[ "$HOST" == "windows" ]]; then
|
||||
run build-windows-client.sh
|
||||
fi
|
||||
|
||||
101
scripts/build-ios-client.sh
Executable file
101
scripts/build-ios-client.sh
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# build-ios-client.sh — build the iOS SwiftUI client (VoiceCatiOS.app) for the
|
||||
# iOS simulator and stage it into dist/ios-client/.
|
||||
#
|
||||
# Two steps:
|
||||
# 1. Build VoiceCatCore.xcframework with all 3 slices (macOS + iOS device +
|
||||
# iOS simulator) via clients/apple/scripts/build-xcframework.sh --all.
|
||||
# The XCFramework must include the ios-arm64-simulator slice so the Swift
|
||||
# Package binary target resolves when xcodebuild compiles the iOS app.
|
||||
# 2. xcodebuild the VoiceCatiOS target against the iOS Simulator SDK, with
|
||||
# SYMROOT and OBJROOT pointed at the same directory so the Swift Package
|
||||
# and the app target find each other's build products.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/build-ios-client.sh # Debug sim build into ./dist
|
||||
# scripts/build-ios-client.sh --dist /out
|
||||
# scripts/build-ios-client.sh --no-configure # skip cmake configure (xcframework step)
|
||||
# scripts/build-ios-client.sh --config Debug # Xcode config (default Debug)
|
||||
# scripts/build-ios-client.sh -h|--help
|
||||
#
|
||||
# Output:
|
||||
# clients/apple/iOS/build/Debug-iphonesimulator/VoiceCatiOS.app
|
||||
# dist/ios-client/VoiceCatiOS.app
|
||||
#
|
||||
# To install and launch on a simulator after building, use:
|
||||
# scripts/run-ios-simulator.sh
|
||||
#
|
||||
# macOS only. Requires VCPKG_ROOT and Xcode (with iOS Simulator runtime installed).
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
VC_SCRIPT_NAME="build-ios-client"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
DO_CONFIGURE=true
|
||||
XCODE_CONFIG="Debug"
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dist) vc_set_dist "$2"; shift 2 ;;
|
||||
--no-configure) DO_CONFIGURE=false; shift ;;
|
||||
--config) XCODE_CONFIG="$2"; shift 2 ;;
|
||||
-h|--help) vc_print_help "$0"; exit 0 ;;
|
||||
*) vc_die "unknown arg: $1 (try --help)" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
vc_require_macos
|
||||
vc_log "dist dir: $VC_DIST_DIR config: $XCODE_CONFIG"
|
||||
|
||||
# ── Step 1: XCFramework (all slices) ──────────────────────────────────────────
|
||||
# The iOS simulator build requires the ios-arm64-simulator slice, so we always
|
||||
# build all three slices. --no-configure skips cmake configure but still runs
|
||||
# cmake --build (which is fast with a warm build cache).
|
||||
vc_step "build VoiceCatCore.xcframework (all slices: macOS + iOS device + iOS sim)"
|
||||
XCFW_ARGS=( --all )
|
||||
$DO_CONFIGURE || XCFW_ARGS+=( --no-configure )
|
||||
"$VC_REPO_ROOT/clients/apple/scripts/build-xcframework.sh" "${XCFW_ARGS[@]}"
|
||||
XCFW="$VC_REPO_ROOT/clients/apple/VoiceCatCore.xcframework"
|
||||
[[ -d "$XCFW" ]] || vc_die "xcframework not found at $XCFW"
|
||||
vc_ok "xcframework ready -> $XCFW"
|
||||
|
||||
# ── Step 2: xcodebuild for iOS Simulator ──────────────────────────────────────
|
||||
# We use -target (not -scheme + -destination) to avoid the requirement of a
|
||||
# matching simulator runtime in xcrun simctl. When using -target, xcodebuild
|
||||
# skips destination resolution and builds directly against the requested SDK.
|
||||
#
|
||||
# SYMROOT and OBJROOT are both pinned to the same directory so the Swift Package
|
||||
# (VoiceCatCore) and the app target (VoiceCatiOS) resolve each other's products.
|
||||
# Without this, the package builds to clients/apple/build/ while the app target
|
||||
# looks in clients/apple/iOS/build/ — the module import fails with "unable to
|
||||
# resolve module dependency: 'VoiceCatCore'".
|
||||
#
|
||||
# CODE_SIGNING_ALLOWED=NO avoids provisioning-profile errors for local sim builds.
|
||||
XCODEPROJ="$VC_REPO_ROOT/clients/apple/iOS/VoiceCatiOS.xcodeproj"
|
||||
BUILD_DIR="$VC_REPO_ROOT/clients/apple/iOS/build"
|
||||
SIM_SDK_VER="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null)"
|
||||
SIM_SDK="iphonesimulator${SIM_SDK_VER}"
|
||||
vc_step "xcodebuild VoiceCatiOS ($XCODE_CONFIG / $SIM_SDK)"
|
||||
xcodebuild \
|
||||
-project "$XCODEPROJ" \
|
||||
-target VoiceCatiOS \
|
||||
-sdk "$SIM_SDK" \
|
||||
-configuration "$XCODE_CONFIG" \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
ARCHS=arm64 \
|
||||
ONLY_ACTIVE_ARCH=YES \
|
||||
SYMROOT="$BUILD_DIR" \
|
||||
OBJROOT="$BUILD_DIR" \
|
||||
build
|
||||
|
||||
APP="$BUILD_DIR/${XCODE_CONFIG}-iphonesimulator/VoiceCatiOS.app"
|
||||
[[ -d "$APP" ]] || vc_die "VoiceCatiOS.app not found at $APP"
|
||||
vc_ok "built -> $APP"
|
||||
|
||||
# ── Stage ─────────────────────────────────────────────────────────────────────
|
||||
vc_step "stage -> $VC_DIST_DIR/ios-client"
|
||||
STAGE="$(vc_dist_subdir ios-client)"
|
||||
cp -R "$APP" "$STAGE/"
|
||||
vc_ok "VoiceCatiOS.app -> $STAGE/ ($(du -sh "$APP" | cut -f1))"
|
||||
vc_ok "done -> $STAGE"
|
||||
129
scripts/run-ios-simulator.sh
Executable file
129
scripts/run-ios-simulator.sh
Executable file
@@ -0,0 +1,129 @@
|
||||
#!/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 <UUID>
|
||||
# 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)"
|
||||
local filter="${1:-}" state="${2:-}"
|
||||
local pattern="iPhone"
|
||||
[[ -n "$filter" ]] && pattern="$filter"
|
||||
xcrun simctl list devices available 2>/dev/null \
|
||||
| grep -E "[[:space:]]$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
|
||||
}
|
||||
|
||||
sim_name() {
|
||||
xcrun simctl list devices available 2>/dev/null \
|
||||
| grep "$1" | head -1 \
|
||||
| sed 's/[[:space:]]*('"$1"').*//' | sed 's/^[[:space:]]*//'
|
||||
}
|
||||
|
||||
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
|
||||
# Give Simulator.app a moment to display the device.
|
||||
sleep 2
|
||||
fi
|
||||
fi
|
||||
|
||||
NAME="$(sim_name "$UDID")"
|
||||
vc_log "simulator: $NAME ($UDID)"
|
||||
|
||||
# If the simulator exists but Simulator.app isn't open, open it.
|
||||
open -a Simulator &>/dev/null || true
|
||||
|
||||
# ── 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
|
||||
Reference in New Issue
Block a user