flutter-device-smoke-test

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Flutter device smoke test

Flutter 设备冒烟测试

Verify a Flutter app works on a real Android device, producing an evidence line for each claim — a command whose output proves the step happened (a pid, a file, a clean logcat). No assertion without its evidence line.
验证Flutter应用在真实Android设备上可正常运行,每个验证步骤都需提供证据行——即能证明该步骤完成的命令输出(如进程ID、文件、无异常的logcat内容)。无证据则不做断言。

Steps

步骤

  1. Connect.
    adb devices -l
    to list; for a wireless device use
    adb connect <ip>:<port>
    . Completion: your device serial appears and
    adb -s <serial> get-state
    prints
    device
    .
  2. Install the APK.
    adb -s <serial> install -r build/app/outputs/flutter-apk/app-debug.apk
    . Completion: output contains
    Success
    . A 150MB debug APK over wifi takes minutes — give the command a 300s timeout.
  3. Launch.
    adb -s <serial> shell am start -n <packageId>/.MainActivity
    , wait ~5s. Completion:
    adb -s <serial> shell pidof <packageId>
    returns a pid.
  4. Check for crashes.
    adb -s <serial> logcat -d | grep -E 'E/flutter|FATAL|AndroidRuntime|Unhandled|LateInitialization|sqlite' | tail -20
    . Completion: no
    FATAL
    /
    AndroidRuntime
    /
    E/flutter
    lines from your app (ignore other apps' sqlite logs — scope by package or filter them out).
  5. Verify the UI rendered. Screenshot:
    adb -s <serial> exec-out screencap -p > /tmp/app.png
    ; confirm
    file /tmp/app.png
    reports a PNG with device resolution. Note:
    uiautomator dump
    shows no text for Flutter apps unless accessibility is enabled — the screenshot, not uiautomator, is the evidence.
  6. Verify storage was created. Inspect the app's private dir:
    adb -s <serial> shell run-as <packageId> ls -la app_flutter/
    then
    find app_flutter/<wikiRoot> -type f
    . Completion: expected files exist (e.g.
    index.sqlite
    ,
    wiki.yaml
    ). Quoting trap:
    run-as pkg sh -c '...'
    mangles nested quotes through adb — pass one simple command at a time, and inspect
    app_flutter/
    (path_provider's documents dir) not
    files/
    .
  1. 连接设备。执行
    adb devices -l
    列出设备;若为无线设备,使用
    adb connect <ip>:<port>
    连接。 完成标志:设备序列号出现在列表中,且执行
    adb -s <serial> get-state
    输出
    device
  2. 安装APK。执行
    adb -s <serial> install -r build/app/outputs/flutter-apk/app-debug.apk
    。 完成标志:输出包含
    Success
    。通过WiFi安装150MB的调试APK需耗时数分钟——给该命令设置300秒超时。
  3. 启动应用。执行
    adb -s <serial> shell am start -n <packageId>/.MainActivity
    ,等待约5秒。 完成标志:执行
    adb -s <serial> shell pidof <packageId>
    返回进程ID(pid)。
  4. 检查崩溃情况。执行
    adb -s <serial> logcat -d | grep -E 'E/flutter|FATAL|AndroidRuntime|Unhandled|LateInitialization|sqlite' | tail -20
    。 完成标志:输出中无来自当前应用的
    FATAL
    /
    AndroidRuntime
    /
    E/flutter
    日志行(可忽略其他应用的sqlite日志——可按包名过滤或排除)。
  5. 验证UI渲染。截图:执行
    adb -s <serial> exec-out screencap -p > /tmp/app.png
    ;确认执行
    file /tmp/app.png
    显示该文件为对应设备分辨率的PNG图片。 注意:除非启用无障碍功能,否则
    uiautomator dump
    无法获取Flutter应用的文本内容——因此需以截图而非uiautomator输出作为证据。
  6. 验证存储创建。检查应用私有目录: 先执行
    adb -s <serial> shell run-as <packageId> ls -la app_flutter/
    ,再执行
    find app_flutter/<wikiRoot> -type f
    。 完成标志:预期文件存在(如
    index.sqlite
    wiki.yaml
    )。引号陷阱
    run-as pkg sh -c '...'
    会通过adb破坏嵌套引号——建议每次仅传递一条简单命令,且检查
    app_flutter/
    (path_provider的文档目录)而非
    files/
    目录。

Crash-fix loop

崩溃修复循环

When step 4 shows a crash, find the blame line in logcat (a
LateInitializationError
, a native-symbol error like
sqlite3_initialize
, etc.), fix the code, rebuild (
flutter build apk --debug
), reinstall, relaunch, and re-verify. Some crashes only reproduce on slow real devices — a clean host test suite is not evidence the device is fine.
当步骤4检测到崩溃时,在logcat中找到问题根源行(如
LateInitializationError
sqlite3_initialize
等原生符号错误),修复代码后重新构建(执行
flutter build apk --debug
)、重新安装、重新启动并再次验证。部分崩溃仅在性能较慢的真机上复现——本地测试套件无异常并不代表真机运行正常。

Reference

参考资料

  • Race on slow devices: async init (DB open, service wiring) may not finish before the first frame renders →
    LateInitializationError: Field 'x' has not been initialized
    . Fix with a splash gate — see the
    flutter-async-init-gate
    skill.
  • Missing native symbol at runtime (e.g.
    sqlite3_initialize
    ) is a packaging problem — see
    flutter-android-build-triage
    .
  • Device used here: Samsung Galaxy A04, wireless adb
    192.168.0.101:33929
    .
  • 慢设备上的竞争问题:异步初始化(如数据库打开、服务连接)可能在第一帧渲染前未完成,导致
    LateInitializationError: Field 'x' has not been initialized
    。可通过启动页闸门解决——参考
    flutter-async-init-gate
    技能。
  • 运行时缺失原生符号(如
    sqlite3_initialize
    )属于打包问题——参考
    flutter-android-build-triage
    技能。
  • 本文所用设备:三星Galaxy A04,无线adb地址
    192.168.0.101:33929