故障排除
我的 Android 模拟器没有显示#
- 运行
adb devices。如果模拟器没有列在那里,EmuLabZip 也看不到它。重启它,或运行adb kill-server && adb start-server。 - 找不到
adb时,设备选择器的页脚会显示 adb unavailable。请安装 Android SDK 的 platform tools,或将ANDROID_HOME或EMULABZIP_ADB指向你的 SDK。 - 列为 unauthorized 的设备正在等你接受 USB 调试提示。
- 自定义的 ADB 服务器端口也必须为 EmuLabZip 设置
ANDROID_ADB_SERVER_PORT或ADB_SERVER_SOCKET。
我的模拟器没有显示#
- 只会列出已启动的 iOS 模拟器。用
xcrun simctl list devices booted检查。 - 缺少 Xcode 命令行工具时,页脚会显示 simctl unavailable。运行
xcode-select --install, 如果安装了多个 Xcode 版本,则运行sudo xcode-select -s /Applications/Xcode.app。
日志是空的#
- 在 Android 上,检查
adb logcat是否会输出行。 - 查看最低级别和过滤器;当有日志行但没有一行匹配时,会出现 Reset filters。
- 应用过滤器需要应用正在运行。启动应用;过滤器会自动获取新的进程 id。
日志太繁忙#
见统一日志很繁忙。在 Android 上,提高最低级别或按 标签过滤。
截图失败#
- 在 Android 上,
adb exec-out screencap -p > shot.png必须能正常工作。一些安全屏幕(DRM 视频、银行应用) 按设计就是黑的。 - 在 iOS 上,
xcrun simctl io booted screenshot shot.png必须能正常工作。
Storage 提示 “only debuggable apps can be browsed”#
Android 只允许 run-as 读取可调试应用的私有数据。请安装你应用的 debug 构建,或用示例应用试用
这些工具(tools/sample-app/install.sh)。共享存储对每个应用都有效。
Android 上堆转储失败#
am dumpheap 需要可调试的应用,或 userdebug/eng 类型的模拟器镜像(不带 Google Play 的镜像)。
错误信息会显示 Android 给出的原因,例如 Process not debuggable。
Performance 没有显示帧率#
只有在应用绘制时才会统计帧。请操作应用;静止的屏幕不会渲染任何内容。在 iOS 模拟器上,帧指标会随第 4 阶段的 Instruments 追踪一起提供。
Network:什么也没有显示#
- 检查设备是否显示 sending traffic here。在 Android 上,
adb shell settings get global http_proxy应该 输出127.0.0.1:<port>。 - 有些应用会忽略系统代理(自己打开 socket 的应用,或使用 HTTP/3 的应用)。它们无法被捕获。
- 大量使用缓存的应用可能根本不请求网络。清除它们的数据,或使用一个新的 URL。
Network:HTTPS 请求失败或显示为 “Connections”#
设备不信任该证书,或者应用固定了其服务器的证书。点击 Certificate 并按提示操作。在来自 Google Play 的 Android 镜像上,只有 Chrome 和允许用户证书的应用才会信任它;见 证书。横幅会列出正在直通的主机;修复之后请使用 Decrypt again。
Network:设备或 Mac 仍然指向代理#
点击 Disconnect,或者在 Android 上运行 adb shell settings put global http_proxy :0。对于 Mac,请打开一次 EmuLabZip:
如果之前的运行被强制终止,它会恢复自己保存的代理设置。否则请在
System Settings › Network › Details › Proxies 中关闭代理。
Network:macOS 要求输入密码#
更改 Mac 的代理是一项系统设置。EmuLabZip 先以你的身份尝试,只有在 macOS 拒绝时才会请求管理员权限。
Network:规则不起作用#
规则看到的是已解密的请求,因此 HTTPS 需要安装证书,拒绝了该证书的主机会被直通,
无法修改。第一条匹配的已启用规则生效;请把你期望生效的那条移到其他规则之上。主机
模式只匹配主机(api.example.com,而不是 https://api.example.com/)。
Network:HTTP/3 没有显示 h3#
该功能默认关闭(HTTP/3 → Use HTTP/3 to servers)。只有当某个主机的响应表明 它支持 HTTP/3 之后,才会尝试它,所以第一个请求总是 TCP。阻止 UDP 的网络会使 QUIC 失败;该主机随后 会在 TCP 上停留 10 分钟。
Layout:在 iOS 上没有可读取的内容#
Simulator.app 必须在该设备上打开,并且运行 EmuLabZip 的程序必须在 System Settings,
Privacy & Security, Accessibility 中获得允许(应用,或运行 emulabzip layout 时的终端)。如果设备显示
黑屏,请唤醒它。
Flutter:“Could not find where the Dart VM service listens”#
只有 debug 和 profile 构建才有,并且应用只在启动时向日志写一次它的地址。请重新启动应用,
或用 --uri 提供 flutter run 输出中的地址。发布构建没有 VM service。
Flutter:树里没有文件名#
应用不是用 --track-widget-creation 构建的。flutter run 会添加它;对于 flutter build,请添加
--extra-front-end-options=--track-widget-creation。
React Native:“Metro is not running” 或 “does not list a runtime”#
启动 Metro(npx react-native start),并在能连到它的设备上打开应用(Android 上用 adb reverse tcp:8081 tcp:8081)。
只有当应用连接到 Metro 时,Metro 才会列出运行时,并且一次只允许一个调试器接入:请关闭 React
Native DevTools 和 Chrome 的 inspector,然后重试。发布构建没有 Metro,也没有 React DevTools hook。
State:“RN state is empty” 或 “no DevTools hook”#
Redux、React Query 和 context 是通过 React 的 DevTools hook 找到的,只有开发构建才有它。在发布
构建中,请在 globalThis.__EMULABZIP_STORES__ 中注册 store(见 React Native 状态)。未使用 react-redux Provider
的 store 也必须注册。
State:在 Android 上恢复或保存失败#
应用必须是可调试的(与 Storage 相同)。run-as 和 tar 在设备上运行:run-as 被锁定的模拟器镜像
无法保存状态。提示 tar 被拒绝的恢复,是发现了应用文件夹之外的条目;该文件不是来自 EmuLabZip,或者已损坏。
Edit:“the table cannot be changed”#
行是通过 rowid 或其主键找到的。视图,或者两者都没有的表,无法区分它的各行:
请改用应用中的 SQL 来更改。读回内容不一致的编辑会放回旧文件,并说明这一点。
Devices:模拟器无法启动#
emulabzip avd boot 需要 SDK 的 emulator(通过 ANDROID_HOME、ANDROID_SDK_ROOT 和常用文件夹找到)。
请自己运行 emulator -avd <name>,查看它自己的消息。运行中的模拟器绝不会被清除或删除:请先
将其关闭。
Audit:“the area could not be read”#
日志要求应用正在运行,这样才能把它的行与系统的行区分开:启动并使用它,然后再次审计。
Android 上的 Storage 需要可调试的应用,与 Storage 相同。请求来自代理(在
Network 视图中启动它,或传入 --har)。
Language:“Android changes the language of one app at a time”#
Android 无法通过 shell 更改设备的语言,只能更改某个应用的语言(cmd locale set-app-locales,Android 13
及更高版本)。请传入 --app,或在工具栏中选择应用。iOS 模拟器会为每个应用更改语言,每个应用在
重新启动时生效。
文本检查:报告了一个并没有被截断的标签#
text-cut-off 是一种启发式检查:单行文本,其框被限制在其容器(或同一行中的下一个视图)
留出的空间内,并且文本一直延伸到框的末尾。请在 130% 和 200% 下检查;如果放得下,就忽略它。
Visual:“the screenshots are not the same size”#
它们来自不同的设备、方向或显示尺寸。请在同类条件下比较:相同的设备、方向和
显示尺寸(control reset-display 可让 Android 设备恢复)。
Network:Gradle 构建无法下载其发行版#
这不是 EmuLabZip 的问题,但在使用演示应用时会遇到:有些网络让 curl 能访问 Gradle 服务器,
而 Java 却超时。请用 curl 下载发行版,并放到 Gradle 期望的位置
(~/.gradle/wrapper/dists/<name>/<hash>/),或者使用你已有的 Gradle 构建。
Layout:Android 提示 uiautomator 没有产生任何内容#
有些窗口禁止它:安全屏幕和少数播放器。请切换到另一个屏幕再试。如果设备很忙 (开机动画、ANR 对话框),请稍等片刻。
Sessions:录制留下了一个 .partial 文件夹#
录制在能够自行打包之前就被终止了。什么都没有丢失:emulabzip session show run.ezsession.partial
可以打开它。在你再次录制到同一名称之前,请删除或移走该文件夹。
Timeline:缺少触摸#
触摸是通过 getevent 从内核的输入设备读取的,因此模拟器窗口上的手指,或通过
模拟器控制台发送的事件都能被看到。adb shell input tap 是在更高层,也就是 Android 内部注入的,因此看不到。iOS 不会
把模拟器的触摸交给它之外的任何东西,所以那里没有触摸。请使用 --taps 录制。
Timeline:日志时间是 “estimated”#
录制是在 EmuLabZip 0.10 之前完成的,或者设备无法给出它的时间,因此日志的本地时间 是通过比较第一行与录制开始时间推算出来的。它们可能相差两个时钟之间的差值。 请重新录制以获得准确的时间。
Video:“screenrecord made no video”#
有些屏幕无法录制(安全窗口),还有少数镜像根本不支持 screenrecord。消息中
带有该工具打印的内容。在 iOS 模拟器上,recordVideo 需要模拟器已启动;如果它在
20 秒内没有开始,消息会说明原因。
Video:报告里有一个单独的 .mp4#
最大 20 MB 的片段是 HTML 文件的一部分。更大的片段会写在它旁边,名为 emulabzip-report.mp4,文件
以该名称引用它:请把两者一起移动或附加。
Replay:“not in the recording”#
应用请求了录制中没有的内容:另一个地址、另一个查询、一个未使用过的方法,或
录制时失败的请求。代理会回复 504,并把它列在 Not recorded 下(或列在
emulabzip net --replay 的末尾)。请连同该请求重新录制,或添加 --passthrough 让它到达服务器。匹配
会忽略查询参数的顺序和端口,但不会忽略值:为每个请求添加时间戳或随机 id 的应用
总是会匹配不上。
Replay:WebSocket 和某些连接失败#
回放录制期间,无法从 HAR 文件作答的内容会被拒绝,因此无法访问互联网:
WebSocket、gRPC 调用、不接受 EmuLabZip 证书的应用,以及代理无法读取的非 TLS 连接。
如果这些必须工作,请使用 --passthrough。
Traces:“Perfetto did not record a trace”#
Perfetto 需要 Android 9 或更高版本。如果消息提到某项权限,请重启模拟器,或运行
adb shell setprop persist.traced.enable 1 后重新录制。带有语法错误的自定义配置会由 Perfetto 自己报告;
用 adb shell perfetto --txt -c - -o /data/misc/perfetto-traces/test <config.txt 检查它。
Traces:CPU profile 失败#
simpleperf 只对可调试或可分析的应用采样,并且应用必须正在运行。对于整个系统,
你需要允许 adb root 的模拟器镜像(不带 Google Play)。“No samples were recorded” 表示应用在录制期间
什么也没做:请使用它,然后重新录制。
Traces:Instruments 提示 Developer Mode 已关闭#
在终端中运行 sudo DevToolsSecurity -enable,输入你的密码,然后重新录制。DevToolsSecurity -status
显示当前状态。
Traces:trace processor 下载失败#
它来自 github.com/google/perfetto/releases。在代理后面时,请设置 HTTPS_PROXY。与固定的 SHA-256 不匹配的文件
会被丢弃,绝不会运行。你仍然可以在 Perfetto UI 中打开任何 Perfetto 追踪。
Crashes:什么也没有列出#
在 Android 上,系统会把崩溃保存在 DropBox 中并对重复崩溃限速,因此循环崩溃的应用被列出的次数少于它
实际崩溃的次数。在 iOS 模拟器上,macOS 会在崩溃几秒后把 .ips 报告写入
~/Library/Logs/DiagnosticReports;不在任何模拟器文件夹中的应用的报告不会被列出。点击
Refresh,或运行 emulabzip crashes。
Crashes:名称仍然是乱的#
mapping 只会用于它所对应的应用版本,崩溃会说明是哪个版本(“Add the
mapping.txt of com.example 1.2.0 (42)”)。请用完全一致的版本添加文件:emulabzip mappings add com.example "1.2.0 (42)" mapping.txt。另一个构建的文件会给出错误的名称,因此不会使用。当
R8 没有保留行号时,帧也会保持原样:请在下一个构建的规则中添加 -keepattributes SourceFile,LineNumberTable。
Crashes:React Native 显示 1:608617 而不是文件#
发布构建运行的是 bundle,其位置需要该 bundle 的 source map。对于 Hermes,请使用合成的 map,
android/app/build/generated/sourcemaps/react/release/index.android.bundle.map,而不是 packager 或 compiler 的 map。
它还必须是崩溃的那个构建的 map。
Crashes:iOS 显示裸地址#
添加崩溃那个构建的 .dSYM(emulabzip mappings add com.example.app "1.2.0 (42)" MyApp.app.dSYM)。它的
UUID 必须与应用的一致,因此另一个构建的 dSYM,即使版本相同,也不会被使用。读取地址需要
Mac,因为它使用 atos。
Bug report:没有失败的请求#
请求来自 Network 中的代理。请在缺陷发生之前启动它并连接设备;用
--network 录制的会话所生成的报告也包含它们。
Controls:位置在设备上不起作用#
只有模拟器才接受新的位置,方式是通过模拟器控制台。它需要
~/.emulator_console_auth_token 中的令牌,该文件由模拟器在你的账户下首次运行时创建。Android 上的真机
和其他类型的模拟器不支持设置位置。
Controls:Android 上通知没有出现#
通知是通过 shell 用 cmd notification post 发出的(在 Android 14 上试过)。如果设备隐藏了通知,请为 “Android Shell” 开启
通知。在 Android 上会忽略应用参数。
Web pages:我的 WebView 没有列出#
只有当 WebView 所在的应用调用了 WebView.setWebContentsDebuggingEnabled(true)(debug 构建通常会)并且
页面已打开时,才会列出该 WebView。Chrome 在打开时会被列出。列表在你打开 Frameworks 时以及点击
Refresh 时读取。在 iOS 上请使用 Safari 的 Develop 菜单;见应用中的网页。
Flows:我的触摸没有被录制#
只会读取触摸屏:请触摸模拟器自己的窗口。从 EmuLabZip 发出的点击(Interact、Play)或通过
adb shell input 发出的点击都不会到达它,输入的文字也不会被录制。只有当屏幕在触摸之前
两三秒被及时读取时,点击才会得到它所点中视图的名称;无论如何,点击的位置都会保留。见
输入与流程。
Deep links:检查提示域名未验证#
在 Android 上,用 Verify again 或 emulabzip link verify <app> 让设备重试,几秒后再检查。指纹不匹配通常
意味着文件中列出的是发布密钥,而设备上的构建是用
debug 密钥签名的。重定向的域名文件(到 www,或从 http 到 https)会被两个系统拒绝。见
深层链接。
Network:脚本规则不起作用#
脚本只有在其确切字节被批准之后才会运行(规则中的 Approve this script,或 emulabzip script approve)。
修改文件后需要再次批准。如果脚本运行了但请求没有变化,流程的详情会说明
脚本写了什么,或为什么失败。见规则脚本。
Plugins:插件无法运行#
必须先启用它,编辑其 plugin.json 会再次将其禁用。以错误退出的插件会显示其错误输出的
末尾。请检查 command 中的程序是否存在(先在插件的文件夹中查找,再在
PATH 中查找),以及它是否可执行(chmod +x run.sh)。
MCP:助手看不到任何工具#
手动运行 emulabzip mcp,并向它发送 initialize 请求,如 MCP 服务器中所示。如果客户端
找不到 emulabzip,请给它完整路径。标准输出只承载协议;请查看标准错误
(EMULABZIP_LOG=debug)了解出了什么问题。
获取诊断信息#
使用 EMULABZIP_LOG=debug 启动应用或 CLI,并在提交 issue时附上输出。