| .. | .. |
|---|
| 1 | 1 | #!/bin/bash |
|---|
| 2 | 2 | # PAILot iOS Deploy Script |
|---|
| 3 | +# |
|---|
| 4 | +# Installs a personal (Pro-unlocked) PAILot build onto one or more iOS devices. |
|---|
| 5 | +# |
|---|
| 6 | +# ── Remote / "fully remote" targets ──────────────────────────────────────── |
|---|
| 7 | +# Installation uses `xcrun devicectl device install`, which reaches the device |
|---|
| 8 | +# over Apple's CoreDevice tunnel — USB, local network, OR any routable network |
|---|
| 9 | +# path where the device is paired (e.g. across Tailscale). There is NO special |
|---|
| 10 | +# remote logic to add: once a device has been paired, `--device <id>` works |
|---|
| 11 | +# whether it sits on your desk or across the world, as long as it is awake and |
|---|
| 12 | +# reachable. That is exactly how the iPad here installs — it is a `localNetwork` |
|---|
| 13 | +# device, never plugged in. (First-time discovery of a NEW device uses .local / |
|---|
| 14 | +# mDNS, which does not cross networks, so a device must be paired at least once |
|---|
| 15 | +# on the local network before it can be driven fully remotely.) |
|---|
| 16 | +# Check reachability any time with: bash tools/deploy.sh --check |
|---|
| 17 | +# |
|---|
| 18 | +# ── Usage ────────────────────────────────────────────────────────────────── |
|---|
| 19 | +# bash tools/deploy.sh # Matthias' iPhone (default) |
|---|
| 20 | +# bash tools/deploy.sh -a # Amelie's iPhone |
|---|
| 21 | +# bash tools/deploy.sh -i # Matthias' iPad |
|---|
| 22 | +# bash tools/deploy.sh --all # every known device (continues on failure) |
|---|
| 23 | +# bash tools/deploy.sh --device ID # explicit CoreDevice identifier (any remote device) |
|---|
| 24 | +# bash tools/deploy.sh --build # force a fresh Pro-unlocked build first |
|---|
| 25 | +# bash tools/deploy.sh --check # list devices devicectl can currently reach |
|---|
| 3 | 26 | set -euo pipefail |
|---|
| 4 | 27 | |
|---|
| 5 | 28 | SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
|---|
| 6 | 29 | APP_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" |
|---|
| 7 | | - |
|---|
| 8 | 30 | cd "$APP_DIR" |
|---|
| 9 | 31 | |
|---|
| 10 | | -# Device UDIDs |
|---|
| 11 | | -MATTHIAS="8708CADC-3330-50B6-AA0A-1655526A573A" |
|---|
| 12 | | -DEVICE="$MATTHIAS" |
|---|
| 32 | +IPA="build/ios/ipa/pailot.ipa" |
|---|
| 33 | + |
|---|
| 34 | +# Known devices — CoreDevice identifiers from `xcrun devicectl list devices`. |
|---|
| 35 | +IPHONE_MATTHIAS="8708CADC-3330-50B6-AA0A-1655526A573A" |
|---|
| 36 | +IPHONE_AMELIE="E3F823F4-8DC8-5C88-948E-C7FA2B4C4C72" |
|---|
| 37 | +IPAD_MATTHIAS="8037E780-6BC0-5B9D-9ED4-D8F28DEEFD3F" |
|---|
| 38 | + |
|---|
| 39 | +TARGETS=() # entries: "identifier|label" |
|---|
| 40 | +FORCE_BUILD=false |
|---|
| 13 | 41 | |
|---|
| 14 | 42 | while [[ $# -gt 0 ]]; do |
|---|
| 15 | 43 | case "$1" in |
|---|
| 16 | | - -a) DEVICE="$AMELIE"; shift ;; |
|---|
| 17 | | - *) shift ;; |
|---|
| 44 | + -a|--amelie) TARGETS+=("$IPHONE_AMELIE|Amelie's iPhone"); shift ;; |
|---|
| 45 | + -i|--ipad) TARGETS+=("$IPAD_MATTHIAS|Matthias' iPad"); shift ;; |
|---|
| 46 | + --iphone) TARGETS+=("$IPHONE_MATTHIAS|Matthias' iPhone"); shift ;; |
|---|
| 47 | + --all) |
|---|
| 48 | + TARGETS+=("$IPHONE_MATTHIAS|Matthias' iPhone" \ |
|---|
| 49 | + "$IPAD_MATTHIAS|Matthias' iPad" \ |
|---|
| 50 | + "$IPHONE_AMELIE|Amelie's iPhone") |
|---|
| 51 | + shift ;; |
|---|
| 52 | + --device) TARGETS+=("$2|device $2"); shift 2 ;; |
|---|
| 53 | + --build) FORCE_BUILD=true; shift ;; |
|---|
| 54 | + --check) echo "=== Devices devicectl can reach ==="; xcrun devicectl list devices; exit 0 ;; |
|---|
| 55 | + -h|--help) sed -n '2,30p' "$0"; exit 0 ;; |
|---|
| 56 | + *) echo "Unknown option: $1" >&2; exit 2 ;; |
|---|
| 18 | 57 | esac |
|---|
| 19 | 58 | done |
|---|
| 20 | 59 | |
|---|
| 21 | | -# Build first if no IPA exists |
|---|
| 22 | | -if [[ ! -f build/ios/ipa/pailot.ipa ]]; then |
|---|
| 23 | | - echo "=== No IPA found, building first ===" |
|---|
| 24 | | - bash tools/build.sh |
|---|
| 60 | +# Default target: Matthias' iPhone. |
|---|
| 61 | +if [[ ${#TARGETS[@]} -eq 0 ]]; then |
|---|
| 62 | + TARGETS+=("$IPHONE_MATTHIAS|Matthias' iPhone") |
|---|
| 25 | 63 | fi |
|---|
| 26 | 64 | |
|---|
| 27 | | -echo "=== Installing on device $DEVICE ===" |
|---|
| 28 | | -xcrun devicectl device install app --device "$DEVICE" build/ios/ipa/pailot.ipa |
|---|
| 65 | +# ── Build a Pro-unlocked personal IPA when needed ────────────────────────── |
|---|
| 66 | +# PAILOT_PRO unlocks Pro for personal / sideloaded installs ONLY. App Store |
|---|
| 67 | +# builds go through tools/build-appstore.sh / tools/release.sh, which do NOT |
|---|
| 68 | +# pass this define — paying users still see the paywall. |
|---|
| 69 | +if [[ "$FORCE_BUILD" == true || ! -f "$IPA" ]]; then |
|---|
| 70 | + echo "=== Building Pro-unlocked IPA (PAILOT_PRO=true) ===" |
|---|
| 71 | + flutter build ipa --release --no-pub --export-method development \ |
|---|
| 72 | + --no-tree-shake-icons --dart-define=PAILOT_PRO=true |
|---|
| 73 | + ARCHIVE="build/ios/archive/Runner.xcarchive/Info.plist" |
|---|
| 74 | + if [ -f "$ARCHIVE" ]; then |
|---|
| 75 | + plutil -replace Name -string "PAILot" "$ARCHIVE" 2>/dev/null || true |
|---|
| 76 | + plutil -replace SchemeName -string "PAILot" "$ARCHIVE" 2>/dev/null || true |
|---|
| 77 | + fi |
|---|
| 78 | +else |
|---|
| 79 | + echo "=== Using existing IPA: $IPA ===" |
|---|
| 80 | + echo " (Pro status depends on how it was built — use --build to force a fresh Pro build)" |
|---|
| 81 | +fi |
|---|
| 82 | + |
|---|
| 83 | +install_one() { |
|---|
| 84 | + local id="$1" label="$2" |
|---|
| 85 | + echo "" |
|---|
| 86 | + echo "=== Installing on $label ($id) ===" |
|---|
| 87 | + if xcrun devicectl device install app --device "$id" "$IPA"; then |
|---|
| 88 | + echo " OK: $label" |
|---|
| 89 | + else |
|---|
| 90 | + echo " WARNING: install on $label failed — is it awake & reachable?" |
|---|
| 91 | + echo " Try: bash tools/deploy.sh --check" |
|---|
| 92 | + return 1 |
|---|
| 93 | + fi |
|---|
| 94 | +} |
|---|
| 95 | + |
|---|
| 96 | +fail=0 |
|---|
| 97 | +for t in "${TARGETS[@]}"; do |
|---|
| 98 | + install_one "${t%%|*}" "${t#*|}" || fail=1 |
|---|
| 99 | +done |
|---|
| 29 | 100 | |
|---|
| 30 | 101 | echo "" |
|---|
| 31 | | -echo "=== Done ===" |
|---|
| 32 | | -echo "Force-quit and reopen PAILot on your phone." |
|---|
| 102 | +if [[ $fail -eq 0 ]]; then |
|---|
| 103 | + echo "=== Done — force-quit and reopen PAILot on the device(s). ===" |
|---|
| 104 | +else |
|---|
| 105 | + echo "=== Done, with failures (see WARNINGs above). ===" |
|---|
| 106 | + exit 1 |
|---|
| 107 | +fi |
|---|