跳到主要内容
教程目录

iOS 真机调试:Windows 上用 VS Code 断点调试 iOS App 并定位崩溃

最后更新

iOS 真机调试在 Windows 上用 VS Code 就能做:连上 iPhone、信任电脑并打开开发者模式,选 Debug 配置按 F5,就能设断点、看变量和调用栈、执行 LLDB 命令。本文讲条件、日志、异常、函数 4 种断点,以及读设备日志、抓崩溃报告和附加到运行中的 App。Swift、Objective-C、C / C++ 都适用,Flutter、React Native、Unity 工程的原生部分操作相同。

第一次连接 iPhone 要做哪些设置?

用数据线把 iPhone 接到电脑上,打开 VS Code 的 KXBuild 视图,「设备」节点会显示手机名、连接方式和系统版本。设备节点显示「点击配置」说明电脑上还没有 Apple 设备驱动,点一下按提示安装,过程中要以管理员身份确认一次。命令行执行 kxdevice doctor 效果相同。

第一次连接要在手机上完成两步设置。

  1. 信任此电脑。解锁手机,在弹窗中点「信任」。用的是充电线或者手机锁屏时弹窗不会出现。
  2. 打开开发者模式。在「设置 → 隐私与安全性 → 开发者模式」中打开,手机会重启一次,重启后按提示确认。这个开关在手机连接过电脑之后才会出现。

同一台手机可能同时出现 USB 和 Wi-Fi 两行,安装和调试选 USB 更稳定。接了多台手机时点设备节点或状态栏选一台,之后 F5 都装到这一台。命令行用下面的命令查看设备,第一列是 UDID。

1kxdevice device list

列表为空时换一根数据线或换个 USB 口,再解锁手机看有没有弹窗。更多情况见设备准备。

第一次调试某个 iOS 版本时会自动下载对应的符号库,有几个 GB,大约十多分钟,进度显示在通知中。只需下载一次,中断后下次继续。下载完成之前断点可能不停,或者只能看到汇编。

为什么调试要用 Debug 配置?

调试前确认 KXBuild 视图「构建配置」节点显示的是 Debug。Release 配置开启了优化,断点位置会跳,变量也常常显示不出来。证书目录里要有 Apple Development 证书和包含这部手机 UDID 的 Development 描述文件,见Windows 给 iOS App 签名。

构建并运行、运行、附加有什么区别?

按场景选一种。

方式 入口 适合的情况
构建并运行 F5、KXBuild 视图标题栏 ▶、target 行内按钮 日常改代码后调试,会构建、签名、安装、启动并附加调试器
运行 「KXBuild: 运行」、target 行内按钮 代码没改,只想重新装一次上一次的构建产物并启动
附加 「KXBuild: 附加到运行中的 App」 App 已经在手机上运行,问题要操作一段时间才出现

构建发生在调试会话开始之前,调试工具栏上的「重启」不会重新编译。改了代码要先停止,再按 F5。

默认按 F5 就能启动,不需要 launch.json。想固定某台设备、某个 target 或构建配置时再写 launch.json,字段说明见运行与调试。

在 Windows 上用 VS Code 断点调试 iPhone 上的 App

断点调试 iOS App 有哪几种断点?

在源码行号左侧单击就能加断点,命中后使用 VS Code 标准的调试视图,单步、继续、跳出的快捷键和其他语言一样。下面几种断点都在行号左侧右键添加,或者在已有断点上右键「编辑断点」修改。

条件断点

循环里或者被频繁调用的函数,普通断点会停很多次。右键「添加条件断点」,选「表达式」,填一个用源码语言写的条件,只有条件为真时才停。

1index == 42 && item.name == "test"

同一个菜单里选「命中次数」,填 10 表示第 10 次经过时才停,适合排查第 N 次才出现的问题。

日志断点

右键「添加日志点」,填一段消息,经过这一行时把消息打印到调试控制台,程序不停。花括号里的表达式会被替换成当时的值。

1加载第 {index} 项,count = {items.count}

临时想看某个值又不想改代码、重新编译时用它,比加 print 快。

异常断点

调试时展开「运行和调试」视图底部的「断点」面板,会列出 Swift Throw、Objective-C Throw、C++ Throw 等选项,勾选后在异常抛出的位置停下。

排查 Objective-C 的 NSException 崩溃(例如数组越界、给 nil 发不存在的消息)时勾选 Objective-C Throw,停下来的位置就是抛出异常的那一行,比等崩溃后看报告直接得多。

函数断点

在「断点」面板标题栏点「+」,输入函数名,例如 viewDidLoad 或 -[MyViewController viewDidLoad],不用找到源码就能在函数入口停下。

断点停下后怎么看变量和调用栈?

断点命中后,左侧几个面板分别回答不同的问题。

面板 用途
变量 当前函数的局部变量和 self,对象可以逐层展开
监视 添加表达式,每次停下都自动求值,适合一直盯着的值
调用栈 每个线程的调用链,点一帧就切到那一层查看它的变量

鼠标悬停在源码里的变量上也能看到当前值。停在没有源码的位置时,可以打开汇编视图查看。

调试控制台里常用哪些 LLDB 命令?

调试控制台(Ctrl+Shift+Y)可以直接输入 LLDB 命令,下面是最常用的几条。

命令 作用
po self 打印对象的描述,等同于调用 description
p count * 2 求表达式的值并打印类型
v 打印当前帧的所有局部变量,不执行代码,速度快
bt 打印当前线程的调用栈
bt all 打印所有线程的调用栈,排查卡死、死锁时用
thread list 列出所有线程和各自停在哪里
expr self.view.backgroundColor = .red 在运行中修改状态,继续执行后能看到效果

输入的内容被当成表达式而不是命令时,在前面加一个反引号,例如 `bt。

App 输出和设备日志在哪里看?

App 里 print、NSLog、os_log 的输出显示在「输出」面板的 KXBuild Console 通道,构建日志在 KXBuild 通道。输出面板用 Ctrl+Shift+U 打开,右上角下拉框切换。

App 没在调试、或者要看系统层面的日志时,用 kxdevice 直接读手机日志。ostrace 只输出 os_log,NSLog 和 Logger 都经过它,比 syslog 干净,还能按子系统和级别过滤。

1kxdevice ostrace --subsystem com.example.myapp --levels error,fault

syslog 输出整机的系统日志,量很大,配合 findstr 过滤。

1kxdevice syslog | findstr MyApp

怎么抓取崩溃报告并定位崩溃?

App 在手机上崩溃后,系统会生成一份崩溃报告。按 F5 时提示 didn’t start in time,通常也是 App 一启动就崩溃了。先列出手机上的报告,再下载到本地。

1kxdevice crash list MyApp*
2kxdevice crash pull .\crashes MyApp*

下载的 .ips 文件用文本编辑器打开,按下面的顺序看。

  1. 异常类型。EXC_BAD_ACCESS 多是访问了已释放的内存或空指针,EXC_CRASH (SIGABRT) 多是未捕获的异常或断言失败,EXC_BREAKPOINT 在 Swift 里常见于强制解包 nil、数组越界。
  2. Last Exception Backtrace。有这一段说明是 Objective-C 异常,这里的调用栈比崩溃线程的更有用。
  3. 崩溃线程的调用栈。找到第一帧属于你的 App 的位置,那里通常就是出问题的代码。

调用栈里你的 App 只显示地址、没有函数名时,最直接的办法是用 Debug 配置按 F5 复现一次。调试器会停在崩溃的那一行,调用栈和变量都能直接看,Objective-C 异常再配合上面的异常断点。

不想记命令时,执行 kxdevice web 后用浏览器打开 http://localhost:8780,崩溃报告、系统日志、进程列表都能在网页上查看。

怎么附加到已经在运行的 App?

有些问题要操作一段时间才出现,重新启动就不好复现。这时让 App 继续运行,把调试器附加上去。

在命令面板运行「KXBuild: 附加到运行中的 App」,会列出手机上正在运行的应用,选一个即可。附加后断点、变量、调试控制台和前面讲的一样。附加的 App 必须是用开发证书签名的,App Store 下载的 App 不能附加。

iOS 真机调试的常见报错怎么处理?

提示 处理
No iOS device selected 在 KXBuild 视图中选一台设备
Developer Mode is off 手机上打开开发者模式并重启
Developer Disk Image is not mounted 重新插拔手机,或运行体检
设备尚未配对 / 信任 解锁手机并点信任
did not report the app as launched in time 解锁手机,检查数据线连接
didn’t start in time App 可能一启动就崩溃,按上一节抓取崩溃报告
断点不停,或只停在汇编上 换成 Debug 配置,等符号库下载完成

签名和安装类的报错见iOS 签名报错与 ipa 安装失败的解决办法,其他错误见排错与 FAQ。

按上表排除连接和配置问题后,iOS 真机调试的日常流程就是「打断点、按 F5、在手机上操作」,崩溃则先抓报告,再用 Debug 配置复现定位。

常见问题

Flutter、React Native 工程的原生部分也能这样调试吗?

能。Flutter、React Native、Unity 等框架工程里的 Swift、Objective-C、C / C++ 代码都按本文的方式下断点,JS、Dart、C# 一侧则用各自框架的调试器。

App Store 下载的 App 能附加调试吗?

不能。附加的 App 必须是用开发证书签名的,App Store 下载的 App 不能附加调试器。

第一次调试为什么要等很久?

第一次调试某个 iOS 版本时要下载对应的符号库,有几个 GB,大约十多分钟。只需下载一次,中断后下次继续,下载完成前断点可能不停或只能看到汇编。

接了 USB 又连着 Wi-Fi,该选哪一行?

选 USB。同一台手机可能同时出现 USB 和 Wi-Fi 两行,安装和调试走 USB 更稳定。