跳转至

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