Skip to content

Commit 2e69290

Browse files
chore: Add documentation formatting fixes and device management scripts
- Fix markdown formatting in LOCAL_BUILD_TROUBLESHOOTING.md • Add blank lines before code blocks for better readability • Normalize yaml indentation for consistency • Improve section spacing - Add ADB + Expo device management scripts • scripts/adb-connect.sh - Full-featured device/emulator selector - Handles USB devices and Android Virtual Devices - Cleans up offline emulators automatically - Launches Expo targeting selected device • scripts/adb-connect2.sh - Simplified WSL-safe version - Lighter implementation without complex pipes - Better bash compatibility - Easier to debug and modify These scripts simplify the workflow of selecting a device and running Expo dev client, especially useful with the new local build setup.
1 parent ba31637 commit 2e69290

3 files changed

Lines changed: 532 additions & 3 deletions

File tree

LOCAL_BUILD_TROUBLESHOOTING.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
sudo systemctl status actions.runner.*
1414

1515
# If not running, start it
16-
sudo systemctl start actions.runner.*
16+
sudo systemctl start actions.runner.*
1717

1818
# Check runner logs
1919
tail -50 ~/.github-runner/_diag/Runner_*.log
@@ -60,6 +60,7 @@ ls $ANDROID_HOME/platforms # Should list Android API levels
6060
**Symptom:** Build fails with Java errors or Java incompatibility
6161

6262
**Verify Java:**
63+
6364
```bash
6465
java -version
6566
# Should show Java 17 or higher
@@ -73,6 +74,7 @@ cd android
7374
**Install Java 17+:**
7475

7576
Linux (Ubuntu/Debian):
77+
7678
```bash
7779
sudo apt update
7880
sudo apt install openjdk-17-jdk
@@ -82,6 +84,7 @@ java -version
8284
```
8385

8486
macOS (Homebrew):
87+
8588
```bash
8689
brew install openjdk@17
8790
sudo ln -sfn /usr/local/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk
@@ -287,6 +290,7 @@ sudo ./svc.sh restart
287290
**Likely cause:** Build is really just slow (normal for cold builds)
288291

289292
**Monitor progress:**
293+
290294
```bash
291295
# SSH into build machine
292296
# Check gradle processes
@@ -303,6 +307,7 @@ iftop
303307
```
304308

305309
**Optimization:**
310+
306311
- First build: 20-30 minutes is normal
307312
- Incremental: 5-10 minutes
308313
- Close heavy applications
@@ -313,6 +318,7 @@ iftop
313318
**Symptom:** `jq -r '.version' version.json` fails
314319

315320
**Verify:**
321+
316322
```bash
317323
# Check file exists
318324
ls -la version.json
@@ -419,8 +425,8 @@ If stuck:
419425
```yaml
420426
# Add to workflow for verbose output:
421427
env:
422-
GRADLE_OPTS: "-Dorg.gradle.logging.level=debug"
423-
DEBUG: "true"
428+
GRADLE_OPTS: '-Dorg.gradle.logging.level=debug'
429+
DEBUG: 'true'
424430
```
425431
426432
Then check logs for detailed build information.

scripts/adb-connect.sh

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# ─────────────────────────────────────────────
5+
# 📟 ADB + Expo Device Manager (WSL Safe)
6+
# by digitalnomad91
7+
# ─────────────────────────────────────────────
8+
9+
# 🖍️ Color codes
10+
RED='\033[0;31m'
11+
GREEN='\033[0;32m'
12+
BLUE='\033[1;34m'
13+
CYAN='\033[1;36m'
14+
YELLOW='\033[1;33m'
15+
BOLD='\033[1m'
16+
RESET='\033[0m'
17+
18+
divider() { echo -e "${BLUE}────────────────────────────────────────────${RESET}"; }
19+
log() { echo -e "${CYAN}ℹ️ $1${RESET}"; }
20+
warn() { echo -e "${YELLOW}⚠️ $1${RESET}"; }
21+
success() { echo -e "${GREEN}$1${RESET}"; }
22+
error() { echo -e "${RED}$1${RESET}" >&2; }
23+
24+
ADB_BIN="${ADB_BIN:-adb}"
25+
EMULATOR_BIN="${EMULATOR_BIN:-emulator}"
26+
27+
require_cmd() {
28+
command -v "$1" >/dev/null 2>&1 || {
29+
error "Missing required command: $1"
30+
exit 1
31+
}
32+
}
33+
34+
require_cmd "$ADB_BIN"
35+
36+
list_all_devices() {
37+
"$ADB_BIN" devices -l | tr -d '\r' | awk 'NR>1 && NF'
38+
}
39+
40+
normalize_state() {
41+
echo -n "$1" | tr -d '\r\n'
42+
}
43+
44+
device_state_for_serial() {
45+
local serial="$1"
46+
"$ADB_BIN" devices | awk -v s="$serial" '$1==s {print $2}' | tr -d '\r\n'
47+
}
48+
49+
get_avd_name_for_emulator_serial() {
50+
local serial="$1"
51+
# Output is typically:
52+
# <AVD_NAME>
53+
# OK
54+
# We only want the first non-empty line.
55+
"$ADB_BIN" -s "$serial" emu avd name 2>/dev/null | tr -d '\r' | awk 'NF{print; exit}'
56+
}
57+
58+
list_avds() {
59+
if command -v "$EMULATOR_BIN" >/dev/null 2>&1; then
60+
"$EMULATOR_BIN" -list-avds 2>/dev/null || true
61+
fi
62+
}
63+
64+
is_expo_device_supported() {
65+
npx expo run:android --help 2>/dev/null | grep -q -- '--device'
66+
}
67+
68+
divider
69+
echo -e "${BOLD}📟 ADB + Expo Device Manager (WSL Safe)${RESET}"
70+
divider
71+
72+
# 🔌 Start ADB server if not running
73+
log "Checking ADB server..."
74+
if "$ADB_BIN" start-server >/dev/null 2>&1; then
75+
success "ADB server ready."
76+
else
77+
warn "ADB server check failed; attempting to continue."
78+
fi
79+
80+
divider
81+
log "Detecting connected devices..."
82+
83+
ALL_SERIALS=()
84+
ALL_NAMES=()
85+
ALL_STATES=()
86+
ALL_DEVICES_RAW=()
87+
88+
for _ in {1..5}; do
89+
sleep 0.5
90+
mapfile -t ALL_DEVICES_RAW < <(list_all_devices)
91+
(( ${#ALL_DEVICES_RAW[@]} > 0 )) && break
92+
done
93+
94+
for line in "${ALL_DEVICES_RAW[@]}"; do
95+
serial=$(echo "$line" | awk '{print $1}')
96+
state=$(echo "$line" | awk '{print $2}')
97+
description=$(echo "$line" | cut -d' ' -f3-)
98+
99+
# skip any unexpected blank lines
100+
[[ -z "${serial:-}" ]] && continue
101+
102+
name="$serial"
103+
if [[ "$serial" =~ ^emulator- ]]; then
104+
avd_name="$(get_avd_name_for_emulator_serial "$serial" || true)"
105+
[[ -n "${avd_name:-}" ]] && name="$avd_name"
106+
else
107+
model=$(echo "$description" | sed -n 's/.*model:\([^ ]*\).*/\1/p')
108+
[[ -n "$model" ]] && name="$model"
109+
fi
110+
111+
ALL_SERIALS+=("$serial")
112+
ALL_NAMES+=("$name")
113+
ALL_STATES+=("$state")
114+
done
115+
116+
# Expo CLI currently probes all emulator serials (even offline) via `adb -s emulator-XXXX emu avd name`.
117+
# If an emulator is stuck in `offline`, that probe fails and aborts the run.
118+
# Workaround: best-effort kill offline emulator entries so they don't break device discovery.
119+
OFFLINE_EMULATORS=()
120+
for i in "${!ALL_SERIALS[@]}"; do
121+
serial="${ALL_SERIALS[$i]}"
122+
state="${ALL_STATES[$i]:-}"
123+
if [[ "$serial" =~ ^emulator- ]] && [[ "$state" == "offline" ]]; then
124+
OFFLINE_EMULATORS+=("$serial")
125+
fi
126+
done
127+
128+
if (( ${#OFFLINE_EMULATORS[@]} > 0 )); then
129+
warn "Found offline emulator(s) that can break Expo: ${OFFLINE_EMULATORS[*]}"
130+
warn "Attempting to remove them from adb (best effort)..."
131+
for serial in "${OFFLINE_EMULATORS[@]}"; do
132+
("$ADB_BIN" -s "$serial" emu kill >/dev/null 2>&1 || true)
133+
done
134+
135+
warn "Restarting adb server to clear stale devices..."
136+
("$ADB_BIN" kill-server >/dev/null 2>&1 || true)
137+
("$ADB_BIN" start-server >/dev/null 2>&1 || true)
138+
139+
# Re-enumerate devices after cleanup so later logic doesn't see the stale offline entries.
140+
ALL_SERIALS=()
141+
ALL_NAMES=()
142+
ALL_STATES=()
143+
ALL_DEVICES_RAW=()
144+
145+
for _ in {1..5}; do
146+
sleep 0.5
147+
mapfile -t ALL_DEVICES_RAW < <(list_all_devices)
148+
(( ${#ALL_DEVICES_RAW[@]} > 0 )) && break
149+
done
150+
151+
for line in "${ALL_DEVICES_RAW[@]}"; do
152+
serial=$(echo "$line" | awk '{print $1}')
153+
state=$(echo "$line" | awk '{print $2}')
154+
description=$(echo "$line" | cut -d' ' -f3-)
155+
156+
[[ -z "${serial:-}" ]] && continue
157+
158+
name="$serial"
159+
if [[ "$serial" =~ ^emulator- ]]; then
160+
avd_name="$(get_avd_name_for_emulator_serial "$serial" || true)"
161+
[[ -n "${avd_name:-}" ]] && name="$avd_name"
162+
else
163+
model=$(echo "$description" | sed -n 's/.*model:\([^ ]*\).*/\1/p')
164+
[[ -n "$model" ]] && name="$model"
165+
fi
166+
167+
ALL_SERIALS+=("$serial")
168+
ALL_NAMES+=("$name")
169+
ALL_STATES+=("$state")
170+
done
171+
fi
172+
173+
divider
174+
log "Devices detected (any state):"
175+
if (( ${#ALL_SERIALS[@]} > 0 )); then
176+
for i in "${!ALL_SERIALS[@]}"; do
177+
serial="${ALL_SERIALS[$i]}"
178+
state="${ALL_STATES[$i]:-unknown}"
179+
name="${ALL_NAMES[$i]:-$serial}"
180+
prefix="📱"
181+
[[ "$serial" =~ ^emulator- ]] && prefix="🖥️ "
182+
if [[ "$state" == "device" ]]; then
183+
echo -e " $prefix ${GREEN}${serial}${RESET} (${BOLD}${name}${RESET}, ${state})"
184+
else
185+
echo -e " $prefix ${YELLOW}${serial}${RESET} (${BOLD}${name}${RESET}, ${state})"
186+
fi
187+
done
188+
else
189+
warn "No devices detected."
190+
fi
191+
192+
# Optional: start an AVD (always offer)
193+
AVD_LIST=()
194+
mapfile -t AVD_LIST < <(list_avds)
195+
196+
if (( ${#ALL_SERIALS[@]} == 0 )) && (( ${#AVD_LIST[@]} == 0 )); then
197+
error "No devices/emulators found."
198+
exit 1
199+
fi
200+
201+
divider
202+
log "Select a device to launch Expo:"
203+
for i in "${!ALL_SERIALS[@]}"; do
204+
serial="${ALL_SERIALS[$i]}"
205+
name="${ALL_NAMES[$i]}"
206+
st="${ALL_STATES[$i]:-unknown}"
207+
prefix="📱"
208+
[[ "$serial" =~ ^emulator- ]] && prefix="🖥️ "
209+
if [[ "$st" == "device" ]]; then
210+
echo -e " $((i + 1))) $prefix ${serial} (${name})"
211+
else
212+
echo -e " $((i + 1))) $prefix ${serial} (${name}) ${YELLOW}[${st}]${RESET}"
213+
fi
214+
done
215+
216+
if (( ${#AVD_LIST[@]} > 0 )); then
217+
echo -e " $(( ${#ALL_SERIALS[@]} + 1 ))) 🧩 Start an AVD..."
218+
fi
219+
220+
MAX_CHOICE=${#ALL_SERIALS[@]}
221+
(( ${#AVD_LIST[@]} > 0 )) && MAX_CHOICE=$((MAX_CHOICE + 1))
222+
223+
read -rp "🚀 Enter choice [1-${MAX_CHOICE}]: " CHOICE
224+
((CHOICE >= 1 && CHOICE <= MAX_CHOICE)) || {
225+
error "Invalid choice. Exiting."
226+
exit 1
227+
}
228+
229+
if (( ${#AVD_LIST[@]} > 0 )) && (( CHOICE == MAX_CHOICE )) && (( ${#ALL_SERIALS[@]} < MAX_CHOICE )); then
230+
divider
231+
log "Available AVDs (can be started):"
232+
for i in "${!AVD_LIST[@]}"; do
233+
echo -e " $((i + 1))) 🧩 ${AVD_LIST[$i]}"
234+
done
235+
read -rp "🧩 Enter AVD number to start: " AVD_CHOICE
236+
((AVD_CHOICE >= 1 && AVD_CHOICE <= ${#AVD_LIST[@]})) || {
237+
error "Invalid AVD choice. Exiting."
238+
exit 1
239+
}
240+
require_cmd "$EMULATOR_BIN"
241+
AVD_NAME="${AVD_LIST[$((AVD_CHOICE - 1))]}"
242+
log "Starting AVD: ${AVD_NAME}"
243+
#nohup emulator -avd "${AVD_NAME}" -no-snapshot -no-boot-anim -no-audio -no-metrics
244+
nohup "${EMULATOR_BIN}" -avd "${AVD_NAME}" -no-snapshot -no-boot-anim -no-audio -no-metrics >/tmp/avd-start.log 2>&1 &
245+
echo "EMULATOR_BIN: ${EMULATOR_BIN}"
246+
echo "AVD_NAME: ${AVD_NAME}"
247+
248+
249+
log "Waiting for emulator to show up in adb..."
250+
for _ in {1..60}; do
251+
sleep 1
252+
if "$ADB_BIN" devices | awk 'NR>1 {print $1, $2}' | grep -q '^emulator-.* device$'; then
253+
break
254+
fi
255+
done
256+
257+
# Pick the emulator that corresponds to the AVD we just started.
258+
SELECTED_SERIAL=""
259+
for _ in {1..60}; do
260+
mapfile -t ALL_DEVICES_RAW < <(list_all_devices)
261+
for line in "${ALL_DEVICES_RAW[@]}"; do
262+
serial=$(echo "$line" | awk '{print $1}')
263+
st=$(echo "$line" | awk '{print $2}')
264+
if [[ "$serial" =~ ^emulator- ]] && [[ "$st" == "device" ]]; then
265+
running_avd="$(get_avd_name_for_emulator_serial "$serial" || true)"
266+
if [[ "$running_avd" == "$AVD_NAME" ]]; then
267+
SELECTED_SERIAL="$serial"
268+
break
269+
fi
270+
fi
271+
done
272+
[[ -n "$SELECTED_SERIAL" ]] && break
273+
sleep 1
274+
done
275+
276+
if [[ -z "$SELECTED_SERIAL" ]]; then
277+
error "Started AVD '${AVD_NAME}', but could not find its running emulator via adb."
278+
warn "Check: $ADB_BIN devices -l"
279+
exit 1
280+
fi
281+
282+
SELECTED_NAME="$AVD_NAME"
283+
else
284+
SELECTED_SERIAL="${ALL_SERIALS[$((CHOICE - 1))]}"
285+
SELECTED_NAME="${ALL_NAMES[$((CHOICE - 1))]}"
286+
fi
287+
288+
divider
289+
echo -e "🎯 Selected: ${GREEN}${SELECTED_SERIAL}${RESET} (${BOLD}${SELECTED_NAME}${RESET})"
290+
291+
# ⏳ Wait for device to be online
292+
divider
293+
echo -e "⏳ Waiting for ${SELECTED_SERIAL} to be online..."
294+
"$ADB_BIN" -s "$SELECTED_SERIAL" wait-for-device
295+
296+
STATE=$("$ADB_BIN" -s "$SELECTED_SERIAL" get-state 2>/dev/null | tr -d '\r\n' || true)
297+
if [[ "$STATE" != "device" ]]; then
298+
error "Selected target is not ready (state: ${STATE:-unknown})."
299+
warn "If this is USB: unlock phone and accept USB debugging prompt."
300+
exit 1
301+
fi
302+
303+
# 🚀 Launch Expo
304+
divider
305+
echo -e "📲 Launching ${BOLD}Expo${RESET} on ${GREEN}${SELECTED_NAME}${RESET}"
306+
307+
# Force Android tooling to the chosen serial.
308+
export ANDROID_SERIAL="${SELECTED_SERIAL}"
309+
310+
# Expo chooses by "device name"; for USB we pass the model, for emulators the serial.
311+
EXPO_DEVICE_ARG="${SELECTED_NAME}"
312+
if [[ "$SELECTED_SERIAL" =~ ^emulator- ]]; then
313+
AVD_NAME="$(get_avd_name_for_emulator_serial "$SELECTED_SERIAL" || true)"
314+
if [[ -n "${AVD_NAME:-}" ]]; then
315+
EXPO_DEVICE_ARG="$AVD_NAME"
316+
else
317+
error "Could not resolve AVD name for ${SELECTED_SERIAL}."
318+
warn "Try: $ADB_BIN -s ${SELECTED_SERIAL} emu avd name"
319+
exit 1
320+
fi
321+
fi
322+
323+
npx expo run:android --device "$EXPO_DEVICE_ARG"

0 commit comments

Comments
 (0)