<# .SYNOPSIS Zentrales Entwicklungsskript für die Krisenvorrat Android-App. .DESCRIPTION Handhabt Build, Deploy und Emulator-Operationen. Behandelt bekannte Komplikationen (OneDrive-Locks, Boot-Delays, stderr-Warnungen). .PARAMETER Action Die auszuführende Aktion: build - Debug-APK bauen clean - Build-Verzeichnisse löschen clean-build - Clean + Build in einem Schritt emulator-start - Emulator starten und auf Boot warten emulator-stop - Emulator beenden install-emulator - APK auf Emulator installieren install-device - APK auf physisches Gerät installieren launch - App starten (auf dem aktiven Ziel) deploy-emulator - Build + Install + Launch auf Emulator deploy-device - Build + Install + Launch auf physisches Gerät logcat - App-Logcat anzeigen (Ctrl+C zum Beenden) devices - Verbundene Geräte auflisten screenshot - Screenshot vom aktiven Gerät speichern .PARAMETER Target Zielgerät: 'emulator' (Standard) oder 'device'. .EXAMPLE & ".github/skills/android-build/android-dev.ps1" -Action build & ".github/skills/android-build/android-dev.ps1" -Action deploy-emulator & ".github/skills/android-build/android-dev.ps1" -Action logcat -Target device #> param( [Parameter(Mandatory)] [ValidateSet( 'build', 'clean', 'clean-build', 'emulator-start', 'emulator-stop', 'install-emulator', 'install-device', 'launch', 'deploy-emulator', 'deploy-device', 'logcat', 'devices', 'screenshot' )] [string]$Action, [ValidateSet('emulator', 'device')] [string]$Target = 'emulator' ) $ErrorActionPreference = 'Stop' # --- Konfiguration --- $SDK_ROOT = "C:\Users\JensR\AppData\Local\Android\Sdk" $ADB = "$SDK_ROOT\platform-tools\adb.exe" $EMULATOR = "$SDK_ROOT\emulator\emulator.exe" $PROJECT_DIR = $PSScriptRoot | Split-Path | Split-Path | Split-Path # .github/skills/android-build → repo root $APK_PATH = "$PROJECT_DIR\app\build\outputs\apk\debug\app-debug.apk" $AVD_NAME = "S24Ultra_API35" $PACKAGE = "de.krisenvorrat.app" $ACTIVITY = "$PACKAGE/.MainActivity" $BOOT_TIMEOUT = 300 # Sekunden (erster Boot eines neuen AVD kann >2min dauern) $INSTALL_RETRY = 3 $env:ANDROID_HOME = $SDK_ROOT # --- Hilfsfunktionen --- function Write-Step { param([string]$msg) Write-Host ">> $msg" -ForegroundColor Cyan } function Write-Ok { param([string]$msg) Write-Host "OK $msg" -ForegroundColor Green } function Write-Err { param([string]$msg) Write-Host "ERR $msg" -ForegroundColor Red } function Write-Warn { param([string]$msg) Write-Host "WARN $msg" -ForegroundColor Yellow } function Get-AdbTarget { if ($Target -eq 'device') { return '-d' } return '-e' } function Test-DeviceConnected { param([string]$type) $flag = if ($type -eq 'device') { '-d' } else { '-e' } try { $result = & $ADB $flag get-state 2>&1 | Out-String return ($result.Trim() -eq 'device') } catch { return $false } } function Invoke-Gradle { param([string[]]$Tasks) Write-Step "Gradle: $($Tasks -join ' ')" Push-Location $PROJECT_DIR try { $output = & .\gradlew.bat @Tasks 2>&1 | Out-String $success = $output -match 'BUILD SUCCESSFUL' $failed = $output -match 'BUILD FAILED' if ($success) { $duration = if ($output -match 'in (\d+[ms]\s?\d*\w*)') { $Matches[0] } else { '' } Write-Ok "BUILD SUCCESSFUL $duration" return $true } elseif ($failed) { # Fehlerdetails extrahieren $errorBlock = ($output -split "`n" | Select-String -Pattern "What went wrong|ERROR:|FAILURE:" -Context 0, 5) -join "`n" Write-Err "BUILD FAILED" Write-Host $errorBlock -ForegroundColor Red return $false } else { Write-Warn "Build-Status unklar. Output prüfen:" Write-Host ($output | Select-Object -Last 20) return $false } } finally { Pop-Location } } function Remove-BuildDirs { Write-Step "Build-Verzeichnisse löschen" $dirs = @("$PROJECT_DIR\app\build", "$PROJECT_DIR\build") foreach ($d in $dirs) { if (Test-Path $d) { Remove-Item $d -Recurse -Force -ErrorAction SilentlyContinue if (Test-Path $d) { Write-Warn "Konnte $d nicht vollständig löschen (OneDrive-Lock?). Versuche erneut..." Start-Sleep -Seconds 2 Remove-Item $d -Recurse -Force -ErrorAction SilentlyContinue } } } Write-Ok "Build-Verzeichnisse bereinigt" } function Start-Emulator { # Prüfe ob Emulator bereits läuft if (Test-DeviceConnected 'emulator') { Write-Ok "Emulator läuft bereits" return $true } Write-Step "Emulator starten: $AVD_NAME" Start-Process -FilePath $EMULATOR -ArgumentList "-avd $AVD_NAME -gpu auto" -WindowStyle Normal Write-Step "Warte auf ADB-Verbindung..." & $ADB wait-for-device Write-Step "Warte auf Boot (max ${BOOT_TIMEOUT}s)..." $elapsed = 0 do { Start-Sleep -Seconds 5 $elapsed += 5 $boot = (& $ADB -e shell getprop sys.boot_completed 2>$null | Out-String).Trim() if ($elapsed % 15 -eq 0) { Write-Host " ... ${elapsed}s" -ForegroundColor DarkGray } } while ($boot -ne "1" -and $elapsed -lt $BOOT_TIMEOUT) if ($boot -ne "1") { Write-Err "Emulator-Boot Timeout nach ${BOOT_TIMEOUT}s" return $false } # Extra-Pause für PackageManager-Initialisierung Write-Step "Warte 5s auf PackageManager..." Start-Sleep -Seconds 5 Write-Ok "Emulator gebootet nach ${elapsed} Sekunden" return $true } function Install-Apk { param([string]$targetType) if (-not (Test-Path $APK_PATH)) { Write-Err "APK nicht gefunden: $APK_PATH" Write-Err "Bitte zuerst bauen: -Action build" return $false } $flags = Get-AdbTarget $apkSize = [math]::Round((Get-Item $APK_PATH).Length / 1MB, 1) Write-Step "APK installieren ${apkSize} MB auf $targetType" for ($attempt = 1; $attempt -le $INSTALL_RETRY; $attempt++) { $result = & $ADB $flags install -r $APK_PATH 2>&1 | Out-String if ($result -match 'Success') { Write-Ok "APK installiert" return $true } if ($attempt -lt $INSTALL_RETRY) { Write-Warn "Install fehlgeschlagen (Versuch $attempt/$INSTALL_RETRY). Warte 5s..." Start-Sleep -Seconds 5 } } Write-Err "APK-Installation fehlgeschlagen nach $INSTALL_RETRY Versuchen:" Write-Host $result -ForegroundColor Red return $false } function Start-App { $flags = Get-AdbTarget Write-Step "App starten: $ACTIVITY" $result = & $ADB $flags shell am start -n $ACTIVITY 2>&1 | Out-String if ($result -match 'Error|Exception') { Write-Err "App-Start fehlgeschlagen:" Write-Host $result -ForegroundColor Red return $false } Write-Ok "App gestartet" return $true } # --- Aktionen --- switch ($Action) { 'build' { $ok = Invoke-Gradle @('assembleDebug') if ($ok -and (Test-Path $APK_PATH)) { $size = [math]::Round((Get-Item $APK_PATH).Length / 1MB, 2) Write-Ok "APK: $APK_PATH - ${size} MB" } exit ([int](-not $ok)) } 'clean' { Remove-BuildDirs exit 0 } 'clean-build' { Remove-BuildDirs $ok = Invoke-Gradle @('assembleDebug') if ($ok -and (Test-Path $APK_PATH)) { $size = [math]::Round((Get-Item $APK_PATH).Length / 1MB, 2) Write-Ok "APK: $APK_PATH - ${size} MB" } exit ([int](-not $ok)) } 'emulator-start' { $ok = Start-Emulator exit ([int](-not $ok)) } 'emulator-stop' { Write-Step "Emulator beenden" & $ADB emu kill 2>$null Write-Ok "Emulator gestoppt" exit 0 } 'install-emulator' { $Target = 'emulator' if (-not (Test-DeviceConnected 'emulator')) { Write-Err "Kein Emulator verbunden. Starte mit: -Action emulator-start" exit 1 } $ok = Install-Apk 'emulator' exit ([int](-not $ok)) } 'install-device' { $Target = 'device' if (-not (Test-DeviceConnected 'device')) { Write-Err "Kein physisches Gerät verbunden. USB-Debugging prüfen." exit 1 } $ok = Install-Apk 'device' exit ([int](-not $ok)) } 'launch' { $ok = Start-App exit ([int](-not $ok)) } 'deploy-emulator' { $Target = 'emulator' $ok = Start-Emulator if (-not $ok) { exit 1 } $ok = Invoke-Gradle @('assembleDebug') if (-not $ok) { exit 1 } $ok = Install-Apk 'emulator' if (-not $ok) { exit 1 } $ok = Start-App exit ([int](-not $ok)) } 'deploy-device' { $Target = 'device' if (-not (Test-DeviceConnected 'device')) { Write-Err "Kein physisches Gerät verbunden." exit 1 } $ok = Invoke-Gradle @('assembleDebug') if (-not $ok) { exit 1 } $ok = Install-Apk 'device' if (-not $ok) { exit 1 } $ok = Start-App exit ([int](-not $ok)) } 'logcat' { $flags = Get-AdbTarget Write-Step "Logcat für $PACKAGE (Ctrl+C zum Beenden)" $pid = & $ADB $flags shell pidof $PACKAGE 2>$null if ($pid) { & $ADB $flags logcat --pid=$pid -v time } else { Write-Warn "App läuft nicht. Zeige alle Logs mit Tag-Filter..." & $ADB $flags logcat -v time *:W } } 'devices' { Write-Step "Verbundene Geräte" & $ADB devices -l } 'screenshot' { $flags = Get-AdbTarget $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $filename = "screenshot-$timestamp.png" Write-Step "Screenshot: $filename" $screenshotPath = "$PROJECT_DIR\$filename" & $ADB $flags shell screencap -p "/sdcard/$filename" $ErrorActionPreference = 'Continue' $pullResult = & $ADB $flags pull "/sdcard/$filename" $screenshotPath 2>&1 | Out-String & $ADB $flags shell rm "/sdcard/$filename" 2>&1 | Out-Null $ErrorActionPreference = 'Stop' if (Test-Path $screenshotPath) { Write-Ok "Gespeichert: $filename" } else { Write-Err "Screenshot fehlgeschlagen" } } }