forked from trent_larson/crowd-funder-for-time-pwa
experiment: setting up emulators
This commit is contained in:
655
doc/android-emulator-deployment-guide.md
Normal file
655
doc/android-emulator-deployment-guide.md
Normal file
@@ -0,0 +1,655 @@
|
|||||||
|
# Android Emulator Deployment Guide (No Android Studio)
|
||||||
|
|
||||||
|
**Author**: Matthew Raymer
|
||||||
|
**Date**: 2025-01-27
|
||||||
|
**Status**: 🎯 **ACTIVE** - Complete guide for deploying TimeSafari to Android emulator using command-line tools
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide provides comprehensive instructions for building and deploying TimeSafari to Android emulators using only command-line tools, without requiring Android Studio. It leverages the existing build system and adds emulator-specific deployment workflows.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
### Required Tools
|
||||||
|
|
||||||
|
1. **Android SDK Command Line Tools**
|
||||||
|
```bash
|
||||||
|
# Install via package manager (Arch Linux)
|
||||||
|
sudo pacman -S android-sdk-cmdline-tools-latest
|
||||||
|
|
||||||
|
# Or download from Google
|
||||||
|
# https://developer.android.com/studio/command-line
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Android SDK Platform Tools**
|
||||||
|
```bash
|
||||||
|
# Install via package manager
|
||||||
|
sudo pacman -S android-sdk-platform-tools
|
||||||
|
|
||||||
|
# Or via Android SDK Manager
|
||||||
|
sdkmanager "platform-tools"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Android SDK Build Tools**
|
||||||
|
```bash
|
||||||
|
sdkmanager "build-tools;34.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Android Platform**
|
||||||
|
```bash
|
||||||
|
sdkmanager "platforms;android-34"
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Android Emulator**
|
||||||
|
```bash
|
||||||
|
sdkmanager "emulator"
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **System Images**
|
||||||
|
```bash
|
||||||
|
# For API 34 (Android 14)
|
||||||
|
sdkmanager "system-images;android-34;google_apis;x86_64"
|
||||||
|
|
||||||
|
# For API 33 (Android 13) - alternative
|
||||||
|
sdkmanager "system-images;android-33;google_apis;x86_64"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add to ~/.bashrc or ~/.zshrc
|
||||||
|
export ANDROID_HOME=$HOME/Android/Sdk
|
||||||
|
export ANDROID_AVD_HOME=$HOME/.android/avd # Important for AVD location
|
||||||
|
export PATH=$PATH:$ANDROID_HOME/emulator
|
||||||
|
export PATH=$PATH:$ANDROID_HOME/platform-tools
|
||||||
|
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
|
||||||
|
export PATH=$PATH:$ANDROID_HOME/build-tools/34.0.0
|
||||||
|
|
||||||
|
# Reload shell
|
||||||
|
source ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check all tools are available
|
||||||
|
adb version
|
||||||
|
emulator -version
|
||||||
|
avdmanager list
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resource-Aware Emulator Setup
|
||||||
|
|
||||||
|
### ⚡ **Quick Start Recommendation**
|
||||||
|
|
||||||
|
**For best results, always start with resource analysis:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Check your system capabilities
|
||||||
|
./scripts/avd-resource-checker.sh
|
||||||
|
|
||||||
|
# 2. Use the generated optimal startup script
|
||||||
|
/tmp/start-avd-TimeSafari_Emulator.sh
|
||||||
|
|
||||||
|
# 3. Deploy your app
|
||||||
|
npm run build:android:dev
|
||||||
|
adb install -r android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
This prevents system lockups and ensures optimal performance.
|
||||||
|
|
||||||
|
### AVD Resource Checker Script
|
||||||
|
|
||||||
|
**New Feature**: TimeSafari includes an intelligent resource checker that automatically detects your system capabilities and recommends optimal AVD configurations.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check system resources and get recommendations
|
||||||
|
./scripts/avd-resource-checker.sh
|
||||||
|
|
||||||
|
# Check resources for specific AVD
|
||||||
|
./scripts/avd-resource-checker.sh TimeSafari_Emulator
|
||||||
|
|
||||||
|
# Test AVD startup performance
|
||||||
|
./scripts/avd-resource-checker.sh TimeSafari_Emulator --test
|
||||||
|
|
||||||
|
# Create optimized AVD with recommended settings
|
||||||
|
./scripts/avd-resource-checker.sh TimeSafari_Emulator --create
|
||||||
|
```
|
||||||
|
|
||||||
|
**What the script analyzes:**
|
||||||
|
- **System Memory**: Total and available RAM
|
||||||
|
- **CPU Cores**: Available processing power
|
||||||
|
- **GPU Capabilities**: NVIDIA, AMD, Intel, or software rendering
|
||||||
|
- **Hardware Acceleration**: Optimal graphics settings
|
||||||
|
|
||||||
|
**What it generates:**
|
||||||
|
- **Optimal configuration**: Memory, cores, and GPU settings
|
||||||
|
- **Startup command**: Ready-to-use emulator command
|
||||||
|
- **Startup script**: Saved to `/tmp/start-avd-{name}.sh` for reuse
|
||||||
|
|
||||||
|
## Emulator Management
|
||||||
|
|
||||||
|
### Create Android Virtual Device (AVD)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List available system images
|
||||||
|
avdmanager list target
|
||||||
|
|
||||||
|
# Create AVD for API 34
|
||||||
|
avdmanager create avd \
|
||||||
|
--name "TimeSafari_Emulator" \
|
||||||
|
--package "system-images;android-34;google_apis;x86_64" \
|
||||||
|
--device "pixel_7"
|
||||||
|
|
||||||
|
# List created AVDs
|
||||||
|
avdmanager list avd
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start Emulator
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start emulator with hardware acceleration (recommended)
|
||||||
|
emulator -avd TimeSafari_Emulator -gpu host -no-audio &
|
||||||
|
|
||||||
|
# Start with reduced resources (if system has limited RAM)
|
||||||
|
emulator -avd TimeSafari_Emulator \
|
||||||
|
-no-audio \
|
||||||
|
-memory 2048 \
|
||||||
|
-cores 2 \
|
||||||
|
-gpu swiftshader_indirect &
|
||||||
|
|
||||||
|
# Start with minimal resources (safest for low-end systems)
|
||||||
|
emulator -avd TimeSafari_Emulator \
|
||||||
|
-no-audio \
|
||||||
|
-memory 1536 \
|
||||||
|
-cores 1 \
|
||||||
|
-gpu swiftshader_indirect &
|
||||||
|
|
||||||
|
# Check if emulator is running
|
||||||
|
adb devices
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource Management
|
||||||
|
|
||||||
|
**Important**: Android emulators can consume significant system resources. Choose the appropriate configuration based on your system:
|
||||||
|
|
||||||
|
- **High-end systems** (16GB+ RAM, dedicated GPU): Use `-gpu host`
|
||||||
|
- **Mid-range systems** (8-16GB RAM): Use `-memory 2048 -cores 2`
|
||||||
|
- **Low-end systems** (4-8GB RAM): Use `-memory 1536 -cores 1 -gpu swiftshader_indirect`
|
||||||
|
|
||||||
|
### Emulator Control
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stop emulator
|
||||||
|
adb emu kill
|
||||||
|
|
||||||
|
# Restart emulator
|
||||||
|
adb reboot
|
||||||
|
|
||||||
|
# Check emulator status
|
||||||
|
adb get-state
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build and Deploy Workflow
|
||||||
|
|
||||||
|
### Method 1: Using Existing Build Scripts
|
||||||
|
|
||||||
|
The TimeSafari project already has comprehensive Android build scripts that can be adapted for emulator deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development build with auto-run
|
||||||
|
npm run build:android:dev:run
|
||||||
|
|
||||||
|
# Test build with auto-run
|
||||||
|
npm run build:android:test:run
|
||||||
|
|
||||||
|
# Production build with auto-run
|
||||||
|
npm run build:android:prod:run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method 2: Custom Emulator Deployment Script
|
||||||
|
|
||||||
|
Create a new script specifically for emulator deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create emulator deployment script
|
||||||
|
cat > scripts/deploy-android-emulator.sh << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# deploy-android-emulator.sh
|
||||||
|
# Author: Matthew Raymer
|
||||||
|
# Date: 2025-01-27
|
||||||
|
# Description: Deploy TimeSafari to Android emulator without Android Studio
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Source common utilities
|
||||||
|
source "$(dirname "$0")/common.sh"
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
BUILD_MODE="development"
|
||||||
|
AVD_NAME="TimeSafari_Emulator"
|
||||||
|
START_EMULATOR=true
|
||||||
|
CLEAN_BUILD=true
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--dev|--development)
|
||||||
|
BUILD_MODE="development"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--test)
|
||||||
|
BUILD_MODE="test"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--prod|--production)
|
||||||
|
BUILD_MODE="production"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--avd)
|
||||||
|
AVD_NAME="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--no-start-emulator)
|
||||||
|
START_EMULATOR=false
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-clean)
|
||||||
|
CLEAN_BUILD=false
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
echo "Usage: $0 [options]"
|
||||||
|
echo "Options:"
|
||||||
|
echo " --dev, --development Build for development"
|
||||||
|
echo " --test Build for testing"
|
||||||
|
echo " --prod, --production Build for production"
|
||||||
|
echo " --avd NAME Use specific AVD name"
|
||||||
|
echo " --no-start-emulator Don't start emulator"
|
||||||
|
echo " --no-clean Skip clean build"
|
||||||
|
echo " -h, --help Show this help"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Unknown option: $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Function to check if emulator is running
|
||||||
|
check_emulator_running() {
|
||||||
|
if adb devices | grep -q "emulator.*device"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to start emulator
|
||||||
|
start_emulator() {
|
||||||
|
log_info "Starting Android emulator: $AVD_NAME"
|
||||||
|
|
||||||
|
# Check if AVD exists
|
||||||
|
if ! avdmanager list avd | grep -q "$AVD_NAME"; then
|
||||||
|
log_error "AVD '$AVD_NAME' not found. Please create it first."
|
||||||
|
log_info "Create AVD with: avdmanager create avd --name $AVD_NAME --package system-images;android-34;google_apis;x86_64"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start emulator in background
|
||||||
|
emulator -avd "$AVD_NAME" -no-audio -no-snapshot &
|
||||||
|
EMULATOR_PID=$!
|
||||||
|
|
||||||
|
# Wait for emulator to boot
|
||||||
|
log_info "Waiting for emulator to boot..."
|
||||||
|
adb wait-for-device
|
||||||
|
|
||||||
|
# Wait for boot to complete
|
||||||
|
log_info "Waiting for boot to complete..."
|
||||||
|
while [ "$(adb shell getprop sys.boot_completed)" != "1" ]; do
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
log_success "Emulator is ready!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to build and deploy
|
||||||
|
build_and_deploy() {
|
||||||
|
log_info "Building TimeSafari for $BUILD_MODE mode..."
|
||||||
|
|
||||||
|
# Clean build if requested
|
||||||
|
if [ "$CLEAN_BUILD" = true ]; then
|
||||||
|
log_info "Cleaning previous build..."
|
||||||
|
npm run clean:android
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build based on mode
|
||||||
|
case $BUILD_MODE in
|
||||||
|
"development")
|
||||||
|
npm run build:android:dev
|
||||||
|
;;
|
||||||
|
"test")
|
||||||
|
npm run build:android:test
|
||||||
|
;;
|
||||||
|
"production")
|
||||||
|
npm run build:android:prod
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Deploy to emulator
|
||||||
|
log_info "Deploying to emulator..."
|
||||||
|
adb install -r android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
|
||||||
|
# Launch app
|
||||||
|
log_info "Launching TimeSafari..."
|
||||||
|
adb shell am start -n app.timesafari/.MainActivity
|
||||||
|
|
||||||
|
log_success "TimeSafari deployed and launched successfully!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
main() {
|
||||||
|
log_info "TimeSafari Android Emulator Deployment"
|
||||||
|
log_info "Build Mode: $BUILD_MODE"
|
||||||
|
log_info "AVD Name: $AVD_NAME"
|
||||||
|
|
||||||
|
# Start emulator if requested and not running
|
||||||
|
if [ "$START_EMULATOR" = true ]; then
|
||||||
|
if ! check_emulator_running; then
|
||||||
|
start_emulator
|
||||||
|
else
|
||||||
|
log_info "Emulator already running"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build and deploy
|
||||||
|
build_and_deploy
|
||||||
|
|
||||||
|
log_success "Deployment completed successfully!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Make script executable
|
||||||
|
chmod +x scripts/deploy-android-emulator.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method 3: Direct Command Line Deployment
|
||||||
|
|
||||||
|
For quick deployments without scripts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Ensure emulator is running
|
||||||
|
adb devices
|
||||||
|
|
||||||
|
# 2. Build the app
|
||||||
|
npm run build:android:dev
|
||||||
|
|
||||||
|
# 3. Install APK
|
||||||
|
adb install -r android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
|
||||||
|
# 4. Launch app
|
||||||
|
adb shell am start -n app.timesafari/.MainActivity
|
||||||
|
|
||||||
|
# 5. View logs
|
||||||
|
adb logcat | grep -E "(TimeSafari|Capacitor|MainActivity)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Deployment Options
|
||||||
|
|
||||||
|
### Custom API Server Configuration
|
||||||
|
|
||||||
|
For development with custom API endpoints:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build with custom API IP
|
||||||
|
npm run build:android:dev:custom
|
||||||
|
|
||||||
|
# Or modify capacitor.config.ts for specific IP
|
||||||
|
# Then build normally
|
||||||
|
npm run build:android:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug vs Release Builds
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Debug build (default)
|
||||||
|
npm run build:android:debug
|
||||||
|
|
||||||
|
# Release build
|
||||||
|
npm run build:android:release
|
||||||
|
|
||||||
|
# Install specific build
|
||||||
|
adb install -r android/app/build/outputs/apk/release/app-release.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
### Asset Management
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Validate Android assets
|
||||||
|
npm run assets:validate:android
|
||||||
|
|
||||||
|
# Generate assets only
|
||||||
|
npm run build:android:assets
|
||||||
|
|
||||||
|
# Clean assets
|
||||||
|
npm run assets:clean
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Emulator Not Starting / AVD Not Found**
|
||||||
|
```bash
|
||||||
|
# Check available AVDs
|
||||||
|
avdmanager list avd
|
||||||
|
|
||||||
|
# If AVD exists but emulator can't find it, check AVD location
|
||||||
|
echo $ANDROID_AVD_HOME
|
||||||
|
ls -la ~/.android/avd/
|
||||||
|
|
||||||
|
# Fix AVD path issue (common on Arch Linux)
|
||||||
|
export ANDROID_AVD_HOME=/home/$USER/.config/.android/avd
|
||||||
|
|
||||||
|
# Or create symlinks if AVDs are in different location
|
||||||
|
mkdir -p ~/.android/avd
|
||||||
|
ln -s /home/$USER/.config/.android/avd/* ~/.android/avd/
|
||||||
|
|
||||||
|
# Create new AVD if needed
|
||||||
|
avdmanager create avd --name "TimeSafari_Emulator" --package "system-images;android-34;google_apis;x86_64"
|
||||||
|
|
||||||
|
# Check emulator logs
|
||||||
|
emulator -avd TimeSafari_Emulator -verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **System Lockup / High Resource Usage**
|
||||||
|
```bash
|
||||||
|
# Kill any stuck emulator processes
|
||||||
|
pkill -f emulator
|
||||||
|
|
||||||
|
# Check system resources
|
||||||
|
free -h
|
||||||
|
nvidia-smi # if using NVIDIA GPU
|
||||||
|
|
||||||
|
# Start with minimal resources
|
||||||
|
emulator -avd TimeSafari_Emulator \
|
||||||
|
-no-audio \
|
||||||
|
-memory 1536 \
|
||||||
|
-cores 1 \
|
||||||
|
-gpu swiftshader_indirect &
|
||||||
|
|
||||||
|
# Monitor resource usage
|
||||||
|
htop
|
||||||
|
|
||||||
|
# If still having issues, try software rendering only
|
||||||
|
emulator -avd TimeSafari_Emulator \
|
||||||
|
-no-audio \
|
||||||
|
-no-snapshot \
|
||||||
|
-memory 1024 \
|
||||||
|
-cores 1 \
|
||||||
|
-gpu off &
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **ADB Device Not Found**
|
||||||
|
```bash
|
||||||
|
# Restart ADB server
|
||||||
|
adb kill-server
|
||||||
|
adb start-server
|
||||||
|
|
||||||
|
# Check devices
|
||||||
|
adb devices
|
||||||
|
|
||||||
|
# Check emulator status
|
||||||
|
adb get-state
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Build Failures**
|
||||||
|
```bash
|
||||||
|
# Clean everything
|
||||||
|
npm run clean:android
|
||||||
|
|
||||||
|
# Rebuild
|
||||||
|
npm run build:android:dev
|
||||||
|
|
||||||
|
# Check Gradle logs
|
||||||
|
cd android && ./gradlew clean --stacktrace
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Installation Failures**
|
||||||
|
```bash
|
||||||
|
# Uninstall existing app
|
||||||
|
adb uninstall app.timesafari
|
||||||
|
|
||||||
|
# Reinstall
|
||||||
|
adb install android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
|
||||||
|
# Check package info
|
||||||
|
adb shell pm list packages | grep timesafari
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
|
||||||
|
1. **Emulator Performance**
|
||||||
|
```bash
|
||||||
|
# Start with hardware acceleration
|
||||||
|
emulator -avd TimeSafari_Emulator -gpu host
|
||||||
|
|
||||||
|
# Use snapshot for faster startup
|
||||||
|
emulator -avd TimeSafari_Emulator -snapshot default
|
||||||
|
|
||||||
|
# Allocate more RAM
|
||||||
|
emulator -avd TimeSafari_Emulator -memory 4096
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Build Performance**
|
||||||
|
```bash
|
||||||
|
# Use Gradle daemon
|
||||||
|
echo "org.gradle.daemon=true" >> android/gradle.properties
|
||||||
|
|
||||||
|
# Increase heap size
|
||||||
|
echo "org.gradle.jvmargs=-Xmx4g" >> android/gradle.properties
|
||||||
|
|
||||||
|
# Enable parallel builds
|
||||||
|
echo "org.gradle.parallel=true" >> android/gradle.properties
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with Existing Build System
|
||||||
|
|
||||||
|
### NPM Scripts Integration
|
||||||
|
|
||||||
|
Add emulator-specific scripts to `package.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"emulator:check": "./scripts/avd-resource-checker.sh",
|
||||||
|
"emulator:check:test": "./scripts/avd-resource-checker.sh TimeSafari_Emulator --test",
|
||||||
|
"emulator:check:create": "./scripts/avd-resource-checker.sh TimeSafari_Emulator --create",
|
||||||
|
"emulator:start": "emulator -avd TimeSafari_Emulator -no-audio &",
|
||||||
|
"emulator:start:optimized": "/tmp/start-avd-TimeSafari_Emulator.sh",
|
||||||
|
"emulator:stop": "adb emu kill",
|
||||||
|
"emulator:deploy": "./scripts/deploy-android-emulator.sh",
|
||||||
|
"emulator:deploy:dev": "./scripts/deploy-android-emulator.sh --dev",
|
||||||
|
"emulator:deploy:test": "./scripts/deploy-android-emulator.sh --test",
|
||||||
|
"emulator:deploy:prod": "./scripts/deploy-android-emulator.sh --prod",
|
||||||
|
"emulator:logs": "adb logcat | grep -E '(TimeSafari|Capacitor|MainActivity)'",
|
||||||
|
"emulator:shell": "adb shell"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### CI/CD Integration
|
||||||
|
|
||||||
|
For automated testing and deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# GitHub Actions example
|
||||||
|
- name: Start Android Emulator
|
||||||
|
run: |
|
||||||
|
emulator -avd TimeSafari_Emulator -no-audio -no-snapshot &
|
||||||
|
adb wait-for-device
|
||||||
|
adb shell getprop sys.boot_completed
|
||||||
|
|
||||||
|
- name: Build and Deploy
|
||||||
|
run: |
|
||||||
|
npm run build:android:test
|
||||||
|
adb install -r android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
adb shell am start -n app.timesafari/.MainActivity
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
run: |
|
||||||
|
npm run test:android
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
|
||||||
|
1. **Start emulator once per session**
|
||||||
|
```bash
|
||||||
|
emulator -avd TimeSafari_Emulator -no-audio &
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Use incremental builds**
|
||||||
|
```bash
|
||||||
|
# For rapid iteration
|
||||||
|
npm run build:android:sync
|
||||||
|
adb install -r android/app/build/outputs/apk/debug/app-debug.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Monitor logs continuously**
|
||||||
|
```bash
|
||||||
|
adb logcat | grep -E "(TimeSafari|Capacitor|MainActivity)" --color=always
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Tips
|
||||||
|
|
||||||
|
1. **Use snapshots for faster startup**
|
||||||
|
2. **Enable hardware acceleration**
|
||||||
|
3. **Allocate sufficient RAM (4GB+)**
|
||||||
|
4. **Use SSD storage for AVDs**
|
||||||
|
5. **Close unnecessary applications**
|
||||||
|
|
||||||
|
### Security Considerations
|
||||||
|
|
||||||
|
1. **Use debug builds for development only**
|
||||||
|
2. **Never commit debug keystores**
|
||||||
|
3. **Use release builds for testing**
|
||||||
|
4. **Validate API endpoints in production builds**
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
This guide provides a complete solution for deploying TimeSafari to Android emulators without Android Studio. The approach leverages the existing build system while adding emulator-specific deployment capabilities.
|
||||||
|
|
||||||
|
The key benefits:
|
||||||
|
- ✅ **No Android Studio required**
|
||||||
|
- ✅ **Command-line only workflow**
|
||||||
|
- ✅ **Integration with existing build scripts**
|
||||||
|
- ✅ **Automated deployment options**
|
||||||
|
- ✅ **Comprehensive troubleshooting guide**
|
||||||
|
|
||||||
|
For questions or issues, refer to the troubleshooting section or check the existing build documentation in `BUILDING.md`.
|
||||||
389
scripts/avd-resource-checker.sh
Executable file
389
scripts/avd-resource-checker.sh
Executable file
@@ -0,0 +1,389 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# avd-resource-checker.sh
|
||||||
|
# Author: Matthew Raymer
|
||||||
|
# Date: 2025-01-27
|
||||||
|
# Description: Check system resources and recommend optimal AVD configuration
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Source common utilities
|
||||||
|
source "$(dirname "$0")/common.sh"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED_COLOR='\033[0;31m'
|
||||||
|
GREEN_COLOR='\033[0;32m'
|
||||||
|
YELLOW_COLOR='\033[1;33m'
|
||||||
|
BLUE_COLOR='\033[0;34m'
|
||||||
|
NC_COLOR='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_status() {
|
||||||
|
local color=$1
|
||||||
|
local message=$2
|
||||||
|
echo -e "${color}${message}${NC_COLOR}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get system memory in MB
|
||||||
|
get_system_memory() {
|
||||||
|
if command -v free >/dev/null 2>&1; then
|
||||||
|
free -m | awk 'NR==2{print $2}'
|
||||||
|
else
|
||||||
|
echo "0"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get available memory in MB
|
||||||
|
get_available_memory() {
|
||||||
|
if command -v free >/dev/null 2>&1; then
|
||||||
|
free -m | awk 'NR==2{print $7}'
|
||||||
|
else
|
||||||
|
echo "0"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get CPU core count
|
||||||
|
get_cpu_cores() {
|
||||||
|
if command -v nproc >/dev/null 2>&1; then
|
||||||
|
nproc
|
||||||
|
elif [ -f /proc/cpuinfo ]; then
|
||||||
|
grep -c ^processor /proc/cpuinfo
|
||||||
|
else
|
||||||
|
echo "1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check GPU capabilities
|
||||||
|
check_gpu_capabilities() {
|
||||||
|
local gpu_type="unknown"
|
||||||
|
local gpu_memory="0"
|
||||||
|
|
||||||
|
# Check for NVIDIA GPU
|
||||||
|
if command -v nvidia-smi >/dev/null 2>&1; then
|
||||||
|
gpu_type="nvidia"
|
||||||
|
gpu_memory=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>/dev/null | head -1 || echo "0")
|
||||||
|
print_status $GREEN_COLOR "✓ NVIDIA GPU detected (${gpu_memory}MB VRAM)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for AMD GPU
|
||||||
|
if command -v rocm-smi >/dev/null 2>&1; then
|
||||||
|
gpu_type="amd"
|
||||||
|
print_status $GREEN_COLOR "✓ AMD GPU detected"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for Intel GPU
|
||||||
|
if lspci 2>/dev/null | grep -i "vga.*intel" >/dev/null; then
|
||||||
|
gpu_type="intel"
|
||||||
|
print_status $YELLOW_COLOR "✓ Intel integrated GPU detected"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for generic GPU
|
||||||
|
if lspci 2>/dev/null | grep -i "vga" >/dev/null; then
|
||||||
|
gpu_type="generic"
|
||||||
|
print_status $YELLOW_COLOR "✓ Generic GPU detected"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status $RED_COLOR "✗ No GPU detected"
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if hardware acceleration is available
|
||||||
|
check_hardware_acceleration() {
|
||||||
|
local gpu_capable=$1
|
||||||
|
|
||||||
|
if [ $gpu_capable -eq 0 ]; then
|
||||||
|
print_status $GREEN_COLOR "✓ Hardware acceleration recommended"
|
||||||
|
return 0
|
||||||
|
elif [ $gpu_capable -eq 1 ]; then
|
||||||
|
print_status $YELLOW_COLOR "⚠ Limited hardware acceleration"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
print_status $RED_COLOR "✗ No hardware acceleration available"
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to recommend AVD configuration
|
||||||
|
recommend_avd_config() {
|
||||||
|
local total_memory=$1
|
||||||
|
local available_memory=$2
|
||||||
|
local cpu_cores=$3
|
||||||
|
local gpu_capable=$4
|
||||||
|
|
||||||
|
print_status $BLUE_COLOR "\n=== AVD Configuration Recommendation ==="
|
||||||
|
|
||||||
|
# Calculate recommended memory (leave 2GB for system)
|
||||||
|
local system_reserve=2048
|
||||||
|
local recommended_memory=$((available_memory - system_reserve))
|
||||||
|
|
||||||
|
# Cap memory at reasonable limits
|
||||||
|
if [ $recommended_memory -gt 4096 ]; then
|
||||||
|
recommended_memory=4096
|
||||||
|
elif [ $recommended_memory -lt 1024 ]; then
|
||||||
|
recommended_memory=1024
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Calculate recommended cores (leave 2 cores for system)
|
||||||
|
local recommended_cores=$((cpu_cores - 2))
|
||||||
|
if [ $recommended_cores -lt 1 ]; then
|
||||||
|
recommended_cores=1
|
||||||
|
elif [ $recommended_cores -gt 4 ]; then
|
||||||
|
recommended_cores=4
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine GPU setting
|
||||||
|
local gpu_setting=""
|
||||||
|
case $gpu_capable in
|
||||||
|
0) gpu_setting="-gpu host" ;;
|
||||||
|
1) gpu_setting="-gpu swiftshader_indirect" ;;
|
||||||
|
2) gpu_setting="-gpu swiftshader_indirect" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Generate recommendation
|
||||||
|
print_status $GREEN_COLOR "Recommended AVD Configuration:"
|
||||||
|
echo " Memory: ${recommended_memory}MB"
|
||||||
|
echo " Cores: ${recommended_cores}"
|
||||||
|
echo " GPU: ${gpu_setting}"
|
||||||
|
|
||||||
|
# Get AVD name from function parameter (passed from main)
|
||||||
|
local avd_name=$5
|
||||||
|
local command="emulator -avd ${avd_name} -no-audio -memory ${recommended_memory} -cores ${recommended_cores} ${gpu_setting} &"
|
||||||
|
|
||||||
|
print_status $BLUE_COLOR "\nGenerated Command:"
|
||||||
|
echo " ${command}"
|
||||||
|
|
||||||
|
# Save to file for easy execution
|
||||||
|
local script_file="/tmp/start-avd-${avd_name}.sh"
|
||||||
|
cat > "$script_file" << EOF
|
||||||
|
#!/bin/bash
|
||||||
|
# Auto-generated AVD startup script
|
||||||
|
# Generated by avd-resource-checker.sh on $(date)
|
||||||
|
|
||||||
|
echo "Starting AVD: ${avd_name}"
|
||||||
|
echo "Memory: ${recommended_memory}MB"
|
||||||
|
echo "Cores: ${recommended_cores}"
|
||||||
|
echo "GPU: ${gpu_setting}"
|
||||||
|
|
||||||
|
${command}
|
||||||
|
|
||||||
|
echo "AVD started in background"
|
||||||
|
echo "Check status with: adb devices"
|
||||||
|
echo "View logs with: adb logcat"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x "$script_file"
|
||||||
|
print_status $GREEN_COLOR "\n✓ Startup script saved to: ${script_file}"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to test AVD startup
|
||||||
|
test_avd_startup() {
|
||||||
|
local avd_name=$1
|
||||||
|
local test_duration=${2:-30}
|
||||||
|
|
||||||
|
print_status $BLUE_COLOR "\n=== Testing AVD Startup ==="
|
||||||
|
|
||||||
|
# Check if AVD exists
|
||||||
|
if ! avdmanager list avd | grep -q "$avd_name"; then
|
||||||
|
print_status $RED_COLOR "✗ AVD '$avd_name' not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status $YELLOW_COLOR "Testing AVD startup for ${test_duration} seconds..."
|
||||||
|
|
||||||
|
# Start emulator in test mode
|
||||||
|
emulator -avd "$avd_name" -no-audio -no-window -no-snapshot -memory 1024 -cores 1 -gpu swiftshader_indirect &
|
||||||
|
local emulator_pid=$!
|
||||||
|
|
||||||
|
# Wait for boot
|
||||||
|
local boot_time=0
|
||||||
|
local max_wait=$test_duration
|
||||||
|
|
||||||
|
while [ $boot_time -lt $max_wait ]; do
|
||||||
|
if adb devices | grep -q "emulator.*device"; then
|
||||||
|
print_status $GREEN_COLOR "✓ AVD booted successfully in ${boot_time} seconds"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
boot_time=$((boot_time + 2))
|
||||||
|
done
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
kill $emulator_pid 2>/dev/null || true
|
||||||
|
adb emu kill 2>/dev/null || true
|
||||||
|
|
||||||
|
if [ $boot_time -ge $max_wait ]; then
|
||||||
|
print_status $RED_COLOR "✗ AVD failed to boot within ${test_duration} seconds"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to list available AVDs
|
||||||
|
list_available_avds() {
|
||||||
|
print_status $BLUE_COLOR "\n=== Available AVDs ==="
|
||||||
|
|
||||||
|
if ! command -v avdmanager >/dev/null 2>&1; then
|
||||||
|
print_status $RED_COLOR "✗ avdmanager not found. Please install Android SDK command line tools."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local avd_list=$(avdmanager list avd 2>/dev/null)
|
||||||
|
if [ -z "$avd_list" ]; then
|
||||||
|
print_status $YELLOW_COLOR "⚠ No AVDs found. Create one with:"
|
||||||
|
echo " avdmanager create avd --name TimeSafari_Emulator --package system-images;android-34;google_apis;x86_64"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$avd_list"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to create optimized AVD
|
||||||
|
create_optimized_avd() {
|
||||||
|
local avd_name=$1
|
||||||
|
local memory=$2
|
||||||
|
local cores=$3
|
||||||
|
|
||||||
|
print_status $BLUE_COLOR "\n=== Creating Optimized AVD ==="
|
||||||
|
|
||||||
|
# Check if system image is available
|
||||||
|
local system_image="system-images;android-34;google_apis;x86_64"
|
||||||
|
if ! sdkmanager --list | grep -q "$system_image"; then
|
||||||
|
print_status $YELLOW_COLOR "Installing system image: $system_image"
|
||||||
|
sdkmanager "$system_image"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create AVD
|
||||||
|
print_status $YELLOW_COLOR "Creating AVD: $avd_name"
|
||||||
|
avdmanager create avd \
|
||||||
|
--name "$avd_name" \
|
||||||
|
--package "$system_image" \
|
||||||
|
--device "pixel_7" \
|
||||||
|
--force
|
||||||
|
|
||||||
|
# Configure AVD
|
||||||
|
local avd_config_file="$HOME/.android/avd/${avd_name}.avd/config.ini"
|
||||||
|
if [ -f "$avd_config_file" ]; then
|
||||||
|
print_status $YELLOW_COLOR "Configuring AVD settings..."
|
||||||
|
|
||||||
|
# Set memory
|
||||||
|
sed -i "s/vm.heapSize=.*/vm.heapSize=${memory}/" "$avd_config_file"
|
||||||
|
|
||||||
|
# Set cores
|
||||||
|
sed -i "s/hw.cpu.ncore=.*/hw.cpu.ncore=${cores}/" "$avd_config_file"
|
||||||
|
|
||||||
|
# Disable unnecessary features
|
||||||
|
echo "hw.audioInput=no" >> "$avd_config_file"
|
||||||
|
echo "hw.audioOutput=no" >> "$avd_config_file"
|
||||||
|
echo "hw.camera.back=none" >> "$avd_config_file"
|
||||||
|
echo "hw.camera.front=none" >> "$avd_config_file"
|
||||||
|
echo "hw.gps=no" >> "$avd_config_file"
|
||||||
|
echo "hw.sensors.orientation=no" >> "$avd_config_file"
|
||||||
|
echo "hw.sensors.proximity=no" >> "$avd_config_file"
|
||||||
|
|
||||||
|
print_status $GREEN_COLOR "✓ AVD configured successfully"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main function
|
||||||
|
main() {
|
||||||
|
print_status $BLUE_COLOR "=== TimeSafari AVD Resource Checker ==="
|
||||||
|
print_status $BLUE_COLOR "Checking system resources and recommending optimal AVD configuration\n"
|
||||||
|
|
||||||
|
# Get system information
|
||||||
|
local total_memory=$(get_system_memory)
|
||||||
|
local available_memory=$(get_available_memory)
|
||||||
|
local cpu_cores=$(get_cpu_cores)
|
||||||
|
|
||||||
|
print_status $BLUE_COLOR "=== System Information ==="
|
||||||
|
echo "Total Memory: ${total_memory}MB"
|
||||||
|
echo "Available Memory: ${available_memory}MB"
|
||||||
|
echo "CPU Cores: ${cpu_cores}"
|
||||||
|
|
||||||
|
# Check GPU capabilities
|
||||||
|
print_status $BLUE_COLOR "\n=== GPU Analysis ==="
|
||||||
|
check_gpu_capabilities
|
||||||
|
local gpu_capable=$?
|
||||||
|
|
||||||
|
# Check hardware acceleration
|
||||||
|
check_hardware_acceleration $gpu_capable
|
||||||
|
local hw_accel=$?
|
||||||
|
|
||||||
|
# List available AVDs
|
||||||
|
list_available_avds
|
||||||
|
|
||||||
|
# Get AVD name from user or use default
|
||||||
|
local avd_name="TimeSafari_Emulator"
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
avd_name="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Recommend configuration
|
||||||
|
recommend_avd_config $total_memory $available_memory $cpu_cores $gpu_capable "$avd_name"
|
||||||
|
|
||||||
|
# Test AVD if requested
|
||||||
|
if [ "$2" = "--test" ]; then
|
||||||
|
test_avd_startup "$avd_name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create optimized AVD if requested
|
||||||
|
if [ "$2" = "--create" ]; then
|
||||||
|
local recommended_memory=$((available_memory - 2048))
|
||||||
|
if [ $recommended_memory -gt 4096 ]; then
|
||||||
|
recommended_memory=4096
|
||||||
|
elif [ $recommended_memory -lt 1024 ]; then
|
||||||
|
recommended_memory=1024
|
||||||
|
fi
|
||||||
|
|
||||||
|
local recommended_cores=$((cpu_cores - 2))
|
||||||
|
if [ $recommended_cores -lt 1 ]; then
|
||||||
|
recommended_cores=1
|
||||||
|
elif [ $recommended_cores -gt 4 ]; then
|
||||||
|
recommended_cores=4
|
||||||
|
fi
|
||||||
|
|
||||||
|
create_optimized_avd "$avd_name" $recommended_memory $recommended_cores
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status $GREEN_COLOR "\n=== Resource Check Complete ==="
|
||||||
|
print_status $YELLOW_COLOR "Tip: Use the generated startup script for consistent AVD launches"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show help
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: $0 [AVD_NAME] [OPTIONS]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --test Test AVD startup (30 second test)"
|
||||||
|
echo " --create Create optimized AVD with recommended settings"
|
||||||
|
echo " --help Show this help message"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 # Check resources and recommend config"
|
||||||
|
echo " $0 TimeSafari_Emulator # Check resources for specific AVD"
|
||||||
|
echo " $0 TimeSafari_Emulator --test # Test AVD startup"
|
||||||
|
echo " $0 TimeSafari_Emulator --create # Create optimized AVD"
|
||||||
|
echo ""
|
||||||
|
echo "The script will:"
|
||||||
|
echo " - Analyze system resources (RAM, CPU, GPU)"
|
||||||
|
echo " - Recommend optimal AVD configuration"
|
||||||
|
echo " - Generate startup command and script"
|
||||||
|
echo " - Optionally test or create AVD"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user