apps\smoke-install.ps1¶
源码路径:
apps\smoke-install.ps1· 121 行
# Install-and-launch smoke test for the five Android apps.
#
# ASCII only: Windows PowerShell 5.1 reads script files as the system ANSI
# codepage (GBK here), and non-ASCII text inside string literals breaks parsing.
#
# Error handling: deliberately NO $ErrorActionPreference = 'Stop'. adb/monkey write
# normal progress text to stderr, and under 'Stop' PowerShell turns that into a
# terminating error. Every step below checks its output instead.
#
# What it does:
# 1. waits for a device/emulator (adb wait-for-device)
# 2. installs all five APKs from dist-android-apps
# 3. force-stops, clears logcat, launches each app, waits N seconds
# 4. greps logcat for FATAL / AndroidRuntime / ANR and reports per app
#
# Why logcat and not "did it start": an app can show a window and still be
# crashing in a background coroutine. FATAL EXCEPTION is the only cheap,
# reliable signal that a launch is actually broken.
#
# Usage:
# powershell -ExecutionPolicy Bypass -File .\apps\smoke-install.ps1
# powershell -ExecutionPolicy Bypass -File .\apps\smoke-install.ps1 -SettleSec 6
# powershell -ExecutionPolicy Bypass -File .\apps\smoke-install.ps1 -Only hub,player
[CmdletBinding()]
param(
[int]$SettleSec = 5,
[string]$Only = '',
[string]$Adb = ''
)
$ws = Split-Path -Parent $PSScriptRoot
$apkDir = Join-Path $ws 'dist-android-apps'
if (-not $Adb) {
$sdk = $env:ANDROID_HOME
if (-not $sdk) { $sdk = "$env:LOCALAPPDATA\Android\Sdk" }
$Adb = Join-Path $sdk 'platform-tools\adb.exe'
}
if (-not (Test-Path $Adb)) { throw "adb not found: $Adb" }
$apps = @(
@{ key = 'player'; pkg = 'cn.nfarms.player'; apk = 'nfarms-player-0.1.0-debug.apk' },
@{ key = 'store'; pkg = 'cn.nfarms.store'; apk = 'nfarms-store-0.1.0-debug.apk' },
@{ key = 'hub'; pkg = 'cn.nfarms.hub'; apk = 'nfarms-hub-0.1.0-debug.apk' },
@{ key = 'iot'; pkg = 'cn.nfarms.iot'; apk = 'nfarms-iot-0.1.0-debug.apk' },
@{ key = 'online'; pkg = 'cn.nfarms.online'; apk = 'nfarms-online-0.1.0-debug.apk' }
)
if ($Only) {
$want = $Only.Split(',') | ForEach-Object { $_.Trim() }
$apps = $apps | Where-Object { $want -contains $_.key }
}
Write-Host 'waiting for device...' -ForegroundColor DarkGray
& $Adb wait-for-device | Out-Null
# sys.boot_completed=1 means the framework is up; install fails before that
$deadline = (Get-Date).AddMinutes(10)
while ((Get-Date) -lt $deadline) {
$booted = (& $Adb shell getprop sys.boot_completed 2>$null) -join ''
if ($booted.Trim() -eq '1') { break }
Start-Sleep -Seconds 3
}
if ($booted.Trim() -ne '1') { throw 'device did not finish booting' }
Write-Host 'device ready' -ForegroundColor DarkGray
$results = @()
foreach ($a in $apps) {
$apk = Join-Path $apkDir $a.apk
if (-not (Test-Path $apk)) { $results += [pscustomobject]@{ app = $a.key; verdict = 'APK MISSING'; detail = $apk }; continue }
$install = & $Adb install -r -g $apk 2>&1 | Out-String
if ($install -notmatch 'Success') {
$results += [pscustomobject]@{ app = $a.key; verdict = 'INSTALL FAILED'; detail = $install.Trim() }
continue
}
& $Adb shell am force-stop $a.pkg | Out-Null
& $Adb logcat -c | Out-Null
# native 工具的 stderr 在 $ErrorActionPreference='Stop' 下会被升级成**终止性**
# 异常,`2>&1` 也压不住(monkey/adb 都会往 stderr 写正常的提示)。
# 这一段统一放宽:成败靠输出内容判断,不靠异常。
# 见文件头:全程 Continue,成败靠输出内容判断
$launch = ''
$log = ''
# `monkey -p <pkg> 1` 拉起 launcher activity,不用知道类名
$launch = (& $Adb shell monkey -p $a.pkg -c android.intent.category.LAUNCHER 1 2>&1 | Out-String)
if ($launch -match 'No activities found|monkey aborted') {
$results += [pscustomobject]@{ app = $a.key; verdict = 'NO LAUNCHER'; detail = $launch.Trim() }
continue
}
Start-Sleep -Seconds $SettleSec
$log = (& $Adb logcat -d 2>&1 | Out-String)
$fatal = ($log -split "`r?`n") | Where-Object { $_ -match 'FATAL EXCEPTION|AndroidRuntime: Process: ' + [regex]::Escape($a.pkg) }
# ANR is also a failure: it means the main thread is stuck
$anr = ($log -split "`r?`n") | Where-Object { $_ -match 'ANR in ' + [regex]::Escape($a.pkg) }
if ($fatal -or $anr) {
$detail = (@($fatal) + @($anr) | Select-Object -First 4) -join "`n"
$results += [pscustomobject]@{ app = $a.key; verdict = 'CRASH'; detail = $detail }
} else {
# also verify the activity actually reached RESUMED
$resumed = $log -match "Displayed $([regex]::Escape($a.pkg))"
$results += [pscustomobject]@{
app = $a.key
verdict = 'OK'
detail = if ($resumed) { 'activity displayed' } else { 'no crash, but "Displayed" not seen (check manually)' }
}
}
& $Adb shell am force-stop $a.pkg | Out-Null
}
Write-Host ''
$results | ForEach-Object { "{0,-7} {1,-14} {2}" -f $_.app, $_.verdict, $_.detail }
$bad = $results | Where-Object { $_.verdict -ne 'OK' }
Write-Host ''
if ($bad) {
Write-Host ("[FAIL] {0} app(s) did not pass" -f $bad.Count) -ForegroundColor Red
exit 1
}
Write-Host ("[OK] {0} app(s) installed and launched without FATAL/ANR" -f $results.Count) -ForegroundColor Green