diff --git a/ushadow/frontend/src/wizards/MobileAppWizard.tsx b/ushadow/frontend/src/wizards/MobileAppWizard.tsx
index bee7911d..5b42536a 100644
--- a/ushadow/frontend/src/wizards/MobileAppWizard.tsx
+++ b/ushadow/frontend/src/wizards/MobileAppWizard.tsx
@@ -216,16 +216,19 @@ export default function MobileAppWizard() {
- Full features including Bluetooth OMI device support. Requires a Mac for iOS or Android Studio for Android.
+ Full features including Bluetooth OMI device support. The build scripts automatically check prerequisites and provide helpful error messages.
# Install dependencies
cd ushadow/mobile && npm install
-
# Build and run on device
-
npx expo run:ios
-
# or
-
npx expo run:android
+
# iOS (Mac only - auto-boots simulator)
+
npm run ios
+
# Android (any platform)
+
npm run android
+
+ Scripts auto-check for required tools and will guide you if anything is missing.
+
{/* Option 2: Android APK */}
@@ -291,10 +294,28 @@ export default function MobileAppWizard() {
{/* Prerequisites Note */}
-
-
- Prerequisites: Node.js 18+, and for development builds: Xcode (iOS) or Android Studio (Android).
- See ushadow/mobile/README.md for detailed setup.
+
+
Prerequisites for Development Builds:
+
+
+
iOS (Mac only)
+
+ - Xcode (from App Store)
+ - iOS Simulator runtime
+ - Xcode Command Line Tools
+
+
+
+
Android (any platform)
+
+ - Java JDK 17 (
brew install openjdk@17)
+ - Android Studio + SDK
+ - Emulator or USB device
+
+
+
+
+ Run npm run ios or npm run android to see exactly what's missing.
diff --git a/ushadow/mobile/README.md b/ushadow/mobile/README.md
index b1ed8e86..c3a035d7 100644
--- a/ushadow/mobile/README.md
+++ b/ushadow/mobile/README.md
@@ -83,15 +83,45 @@ eas build --profile preview --platform android
#### Development (Recommended)
```bash
-# Connect your iOS device via USB
-# Trust your computer on the device
-
npm install
npx expo prebuild --platform ios
cd ios && pod install && cd ..
npx expo run:ios --device
```
+#### Running on Physical iPhone
+
+To run on a physical iPhone instead of the simulator, use the `--device` flag:
+
+```bash
+npx expo run:ios --device
+```
+
+This will show a list of connected devices. You can also specify the device name directly:
+
+```bash
+npx expo run:ios --device "iPhone Air"
+```
+
+**Prerequisites for physical device:**
+
+1. **Connect via USB** - Connect your iPhone to your Mac with a cable
+
+2. **Trust the computer** - On your iPhone, tap "Trust" when prompted with "Trust This Computer?"
+
+3. **Enable Developer Mode** (iOS 16+) - Go to **Settings → Privacy & Security → Developer Mode** and enable it. Your device will restart.
+
+4. **Apple Developer account** - Sign into Xcode with your Apple ID:
+ - Open Xcode → Settings → Accounts → Add your Apple ID
+
+5. **Code signing** - First build requires signing setup:
+ ```bash
+ open ios/*.xcworkspace
+ ```
+ In Xcode: Select your project → Signing & Capabilities → Select your Team
+
+After initial setup, subsequent builds with `npx expo run:ios --device` will work automatically.
+
#### Distribution via TestFlight (Easiest for iOS)
1. Apple Developer account ($99/year required)
2. Build with EAS:
@@ -163,6 +193,36 @@ eas device:create
- Verify URLs don't have trailing slashes
- Try both `ws://` and `wss://` for stream URL
+### Android: "SDK location not found"
+When running `npx expo run:android`, you may see:
+```
+SDK location not found. Define a valid SDK location with an ANDROID_HOME
+environment variable or by setting the sdk.dir path in your project's
+local.properties file
+```
+
+**Cause:** The Android build system (Gradle) can't find your Android SDK installation.
+
+**Fix:** Create `android/local.properties` with your SDK path:
+```bash
+# On macOS (typical Android Studio installation):
+echo "sdk.dir=$HOME/Library/Android/sdk" > android/local.properties
+
+# On Linux:
+echo "sdk.dir=$HOME/Android/Sdk" > android/local.properties
+
+# On Windows (Git Bash):
+echo "sdk.dir=C:\\Users\\YourUsername\\AppData\\Local\\Android\\Sdk" > android/local.properties
+```
+
+**Permanent fix:** Add to your shell profile (`~/.zshrc` or `~/.bashrc`):
+```bash
+export ANDROID_HOME=$HOME/Library/Android/sdk # macOS
+export PATH=$PATH:$ANDROID_HOME/platform-tools
+```
+
+**Note:** `local.properties` is gitignored because it contains machine-specific paths.
+
### Build fails
```bash
# Clean and rebuild
diff --git a/ushadow/mobile/package-lock.json b/ushadow/mobile/package-lock.json
index 3585ac2a..3f79d816 100644
--- a/ushadow/mobile/package-lock.json
+++ b/ushadow/mobile/package-lock.json
@@ -7,6 +7,7 @@
"": {
"name": "ushadow",
"version": "1.0.0",
+ "hasInstallScript": true,
"dependencies": {
"@expo/vector-icons": "^15.0.3",
"@react-native-async-storage/async-storage": "^2.2.0",
diff --git a/ushadow/mobile/package.json b/ushadow/mobile/package.json
index 0d41a338..9ab312c2 100644
--- a/ushadow/mobile/package.json
+++ b/ushadow/mobile/package.json
@@ -5,8 +5,10 @@
"scripts": {
"start": "expo start",
"reset-project": "node ./scripts/reset-project.js",
- "android": "expo run:android",
- "ios": "expo run:ios",
+ "android": "./scripts/preflight-android.sh && expo run:android",
+ "android:skip-preflight": "expo run:android",
+ "ios": "./scripts/preflight-ios.sh && expo run:ios",
+ "ios:skip-preflight": "expo run:ios",
"web": "expo start --web",
"lint": "expo lint",
"postinstall": "patch-package"
diff --git a/ushadow/mobile/scripts/preflight-android.sh b/ushadow/mobile/scripts/preflight-android.sh
new file mode 100755
index 00000000..6830c5bc
--- /dev/null
+++ b/ushadow/mobile/scripts/preflight-android.sh
@@ -0,0 +1,220 @@
+#!/bin/bash
+# Android Preflight Check Script
+# Ensures Android development environment is ready before running expo run:android
+# Note: We don't use 'set -e' here to ensure error messages are displayed properly
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}"
+echo -e "${BLUE}║ Android Development Environment Check ║${NC}"
+echo -e "${BLUE}║ Tip: Always use 'npm run android' to get these checks ║${NC}"
+echo -e "${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}"
+echo ""
+
+# Check for Java - need to verify it actually works, not just that the command exists
+# Android builds require Java because the Android build system (Gradle) runs on the JVM
+JAVA_CHECK=$(java -version 2>&1)
+if echo "$JAVA_CHECK" | grep -qi "Unable to locate\|not found\|No Java\|error"; then
+ echo -e "${RED}╔════════════════════════════════════════════════════════════════╗${NC}"
+ echo -e "${RED}║ ERROR: Java JDK is not installed ║${NC}"
+ echo -e "${RED}╚════════════════════════════════════════════════════════════════╝${NC}"
+ echo ""
+ echo -e "${YELLOW}Why is Java needed?${NC}"
+ echo " Android apps are built using Gradle, which requires Java to run."
+ echo " React Native/Expo uses Gradle under the hood to compile your app."
+ echo ""
+ echo -e "${YELLOW}How to fix:${NC}"
+ echo ""
+ if [[ "$OSTYPE" == "darwin"* ]]; then
+ echo -e "${GREEN}Option 1 - Homebrew (recommended):${NC}"
+ echo ""
+ echo " Step 1: Install OpenJDK 17"
+ echo -e " ${BLUE}brew install openjdk@17${NC}"
+ echo ""
+ echo " Step 2: Link it so the system can find it"
+ echo -e " ${BLUE}sudo ln -sfn \$(brew --prefix)/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk${NC}"
+ echo ""
+ echo " Step 3: Restart your terminal, then run:"
+ echo -e " ${BLUE}npm run android${NC}"
+ echo ""
+ echo -e "${GREEN}Option 2 - Download installer:${NC}"
+ echo " https://adoptium.net/temurin/releases/?version=17"
+ echo " Download the .pkg file for macOS and run the installer."
+ else
+ echo -e "${GREEN}Ubuntu/Debian:${NC}"
+ echo -e " ${BLUE}sudo apt install openjdk-17-jdk${NC}"
+ echo ""
+ echo -e "${GREEN}Or download from:${NC}"
+ echo " https://adoptium.net/temurin/releases/?version=17"
+ fi
+ echo ""
+ echo -e "${YELLOW}After installing Java, restart your terminal and run: npm run android${NC}"
+ echo ""
+ exit 1
+fi
+
+# Check Java version
+JAVA_VERSION=$(echo "$JAVA_CHECK" | head -1 | cut -d'"' -f2 | cut -d'.' -f1 2>/dev/null || echo "0")
+echo -e "${GREEN}Java found: $(echo "$JAVA_CHECK" | head -1)${NC}"
+
+if [ "$JAVA_VERSION" -lt 11 ] 2>/dev/null; then
+ echo -e "${YELLOW}Warning: Java version $JAVA_VERSION detected. Java 17 is recommended for React Native.${NC}"
+fi
+
+# Check for ANDROID_HOME or ANDROID_SDK_ROOT
+if [ -z "$ANDROID_HOME" ] && [ -z "$ANDROID_SDK_ROOT" ]; then
+ # Try common locations
+ if [ -d "$HOME/Library/Android/sdk" ]; then
+ export ANDROID_HOME="$HOME/Library/Android/sdk"
+ echo -e "${YELLOW}ANDROID_HOME not set, using: $ANDROID_HOME${NC}"
+ elif [ -d "$HOME/Android/Sdk" ]; then
+ export ANDROID_HOME="$HOME/Android/Sdk"
+ echo -e "${YELLOW}ANDROID_HOME not set, using: $ANDROID_HOME${NC}"
+ else
+ echo -e "${RED}╔════════════════════════════════════════════════════════════════╗${NC}"
+ echo -e "${RED}║ ERROR: Android SDK not found ║${NC}"
+ echo -e "${RED}╚════════════════════════════════════════════════════════════════╝${NC}"
+ echo ""
+ echo -e "${YELLOW}Why is the Android SDK needed?${NC}"
+ echo " The Android SDK contains tools to compile and package your app"
+ echo " for Android devices. It's installed alongside Android Studio."
+ echo ""
+ echo -e "${YELLOW}How to fix:${NC}"
+ echo ""
+ echo -e "${GREEN}Step 1: Install Android Studio${NC}"
+ echo " Download from: https://developer.android.com/studio"
+ echo " Run the installer and complete the setup wizard."
+ echo ""
+ echo -e "${GREEN}Step 2: Add environment variables${NC}"
+ echo " Add these lines to your shell profile (~/.zshrc or ~/.bashrc):"
+ echo ""
+ if [[ "$OSTYPE" == "darwin"* ]]; then
+ echo -e " ${BLUE}export ANDROID_HOME=\$HOME/Library/Android/sdk${NC}"
+ else
+ echo -e " ${BLUE}export ANDROID_HOME=\$HOME/Android/Sdk${NC}"
+ fi
+ echo -e " ${BLUE}export PATH=\$PATH:\$ANDROID_HOME/emulator${NC}"
+ echo -e " ${BLUE}export PATH=\$PATH:\$ANDROID_HOME/platform-tools${NC}"
+ echo ""
+ echo -e "${GREEN}Step 3: Reload your shell${NC}"
+ echo -e " ${BLUE}source ~/.zshrc${NC} (or restart your terminal)"
+ echo ""
+ echo -e "${YELLOW}Then run: npm run android${NC}"
+ echo ""
+ exit 1
+ fi
+else
+ ANDROID_HOME="${ANDROID_HOME:-$ANDROID_SDK_ROOT}"
+fi
+
+echo -e "${GREEN}Android SDK: $ANDROID_HOME${NC}"
+
+# Check for platform-tools (adb)
+if [ ! -f "$ANDROID_HOME/platform-tools/adb" ]; then
+ echo -e "${RED}╔════════════════════════════════════════════════════════════════╗${NC}"
+ echo -e "${RED}║ ERROR: Android platform-tools (adb) not found ║${NC}"
+ echo -e "${RED}╚════════════════════════════════════════════════════════════════╝${NC}"
+ echo ""
+ echo -e "${YELLOW}Why are platform-tools needed?${NC}"
+ echo " Platform-tools include 'adb' (Android Debug Bridge), which is used"
+ echo " to communicate with your Android device or emulator."
+ echo ""
+ echo -e "${YELLOW}How to fix:${NC}"
+ echo " 1. Open Android Studio"
+ echo " 2. Go to Tools > SDK Manager > SDK Tools tab"
+ echo " 3. Check 'Android SDK Platform-Tools' and click Apply"
+ echo ""
+ exit 1
+fi
+
+# Add platform-tools to PATH if not already there
+export PATH="$PATH:$ANDROID_HOME/platform-tools"
+
+# Check for connected devices or running emulators
+echo ""
+echo "Checking for Android devices..."
+
+DEVICES=$("$ANDROID_HOME/platform-tools/adb" devices 2>/dev/null | grep -v "List" | grep -v "^$" || echo "")
+
+if [ -z "$DEVICES" ]; then
+ echo -e "${YELLOW}No Android devices connected${NC}"
+ echo ""
+
+ # Check if any emulator is available
+ if [ -d "$ANDROID_HOME/emulator" ] && [ -f "$ANDROID_HOME/emulator/emulator" ]; then
+ AVDS=$("$ANDROID_HOME/emulator/emulator" -list-avds 2>/dev/null || echo "")
+
+ if [ -n "$AVDS" ]; then
+ echo "Available emulators:"
+ echo "$AVDS" | while read avd; do echo " - $avd"; done
+ echo ""
+
+ # Try to start the first available emulator
+ FIRST_AVD=$(echo "$AVDS" | head -1)
+ echo -e "${BLUE}Starting emulator: $FIRST_AVD${NC}"
+ "$ANDROID_HOME/emulator/emulator" -avd "$FIRST_AVD" -no-snapshot-load &
+
+ echo "Waiting for emulator to boot..."
+ # Wait for device to be ready (max 60 seconds)
+ for i in {1..30}; do
+ sleep 2
+ BOOT_STATUS=$("$ANDROID_HOME/platform-tools/adb" shell getprop sys.boot_completed 2>/dev/null || echo "")
+ if [ "$BOOT_STATUS" = "1" ]; then
+ echo -e "${GREEN}Emulator is ready!${NC}"
+ break
+ fi
+ echo " Still booting... ($i/30)"
+ done
+ else
+ echo -e "${RED}╔════════════════════════════════════════════════════════════════╗${NC}"
+ echo -e "${RED}║ ERROR: No Android emulators configured ║${NC}"
+ echo -e "${RED}╚════════════════════════════════════════════════════════════════╝${NC}"
+ echo ""
+ echo -e "${YELLOW}You need either an emulator or a physical device to run the app.${NC}"
+ echo ""
+ echo -e "${GREEN}Option 1 - Create an emulator:${NC}"
+ echo " 1. Open Android Studio"
+ echo " 2. Go to Tools > Device Manager"
+ echo " 3. Click 'Create Device' and follow the wizard"
+ echo " 4. Download a system image when prompted (e.g., API 34)"
+ echo ""
+ echo -e "${GREEN}Option 2 - Connect a physical device via USB:${NC}"
+ echo " 1. On your phone: Settings > About Phone"
+ echo " Tap 'Build Number' 7 times to enable Developer Options"
+ echo " 2. Go to Settings > Developer Options"
+ echo " Enable 'USB Debugging'"
+ echo " 3. Connect your phone via USB cable"
+ echo " 4. Accept the debugging prompt on your phone"
+ echo ""
+ exit 1
+ fi
+ else
+ echo -e "${RED}╔════════════════════════════════════════════════════════════════╗${NC}"
+ echo -e "${RED}║ ERROR: Android Emulator not installed ║${NC}"
+ echo -e "${RED}╚════════════════════════════════════════════════════════════════╝${NC}"
+ echo ""
+ echo -e "${YELLOW}How to fix:${NC}"
+ echo " 1. Open Android Studio"
+ echo " 2. Go to Tools > SDK Manager > SDK Tools tab"
+ echo " 3. Check 'Android Emulator' and click Apply"
+ echo " 4. Then go to Tools > Device Manager to create a virtual device"
+ echo ""
+ echo "Or connect a physical Android device via USB (see above)"
+ exit 1
+ fi
+else
+ echo -e "${GREEN}Connected devices:${NC}"
+ echo "$DEVICES" | while read device; do
+ if [ -n "$device" ]; then
+ echo " - $device"
+ fi
+ done
+fi
+
+echo ""
+echo -e "${GREEN}=== Android environment ready! ===${NC}"
+echo ""