调试运行时问题

了解可用于调试 Expo 项目的不同技术。


无论你是在本地开发应用、将其发送给特定的测试用户,还是将应用正式发布到应用商店,你总会遇到调试问题。将错误分为两类是很有用的:

🌐 Whether you're developing your app locally, sending it out to select beta testers, or launching your app live to the app stores, you'll always find yourself debugging issues. It's useful to split errors into two categories:

  • 开发中遇到的错误
  • 你(或你的用户)在生产中遇到的错误

让我们来看看处理上述每种情况时的推荐做法。

🌐 Let's go through recommended practices when dealing with each of the above situations.

信息 已经熟悉 React Native 调试?请参阅 调试工具 了解针对 Expo 的特定工具,例如 React Native 开发工具和内置性能分析器。

开发错误

🌐 Development errors

它们是在开发应用时常遇到的常见错误。深入研究这些错误并不总是简单的。通常,在使用 Expo CLI 运行应用时进行调试就足够了。

🌐 They are common errors that you encounter while developing your app. Delving into them isn't always straightforward. Usually, debugging when running your app with Expo CLI is enough.

调试这些问题的一种方法是查看堆栈跟踪。然而,在某些情况下,仅查看堆栈跟踪是不够的,因为跟踪到的错误信息可能有些难以理解。对于此类错误,请按照以下步骤操作:

🌐 One way you can debug these issues is by looking at the stack trace. However, in some scenarios, looking at the stack trace isn't enough as the error message traced might be a little more cryptic. For such errors, follow the steps below:

  • 在 Google 和 Stack Overflow 上搜索错误信息,很可能你不是第一个遇到这个问题的人。
  • 隔离引发错误的代码。这一步在修复难以发现的错误时至关重要。操作方法如下:
    • 还原到可以正常工作的代码版本。这甚至可以是一个完全空白的 npx create-expo-app 项目。
    • 一点一点地应用你最近的更改,直到它崩溃。
    • 如果你在每个“部分”中添加的代码很复杂,你可能想简化你的操作。例如,如果你使用像 Redux 这样的状态管理库,你可以尝试完全去掉它,看看问题是否出在你的状态管理上(在 React 应用中这很常见)。
    • 这应该可以缩小错误的可能来源,并为你提供更多信息,以便你在互联网上搜索遇到相同问题的其他人。
  • 使用断点(或 console.log)来检查并确保某段代码被执行,或者某个变量具有特定的值。然而,使用 console.log 进行调试并不被认为是最佳实践,但它快速、简单,并且往往能提供一些有启发性的信息。

尽可能简化代码以追查错误来源是调试应用的一个好方法,而且这种方法会让调试变得指数级容易。这也是为什么许多开源仓库在你提交问题时要求提供最小可复现示例的原因。它确保你已经隔离了问题,并准确找出问题发生的地方。如果你的应用过大或过于复杂而无法做到这一点,尝试将你想添加的功能提取到一个空的 npx create-expo-app 项目中,然后从那里开始。

🌐 Simplifying code as much as possible to track down the source of error is a great way to debug your app and it gets exponentially easier. That's why many open-source repositories require a minimal reproducible example when you open an issue. It ensures you have isolated the issue and identified exactly where the problem occurs. If your app is too large and complex to do that, try and extract the functionality you're trying to add in a blank npx create-expo-app project, and go from there.

原生调试

🌐 Native debugging

你可以通过在本地生成源代码并从该源构建来使用 Android Studio 和 Xcode 执行完整的原生调试。

🌐 You can perform full native debugging with Android Studio and Xcode by generating source code locally and building from that source.

安卓工作室

🌐 Android Studio

1

通过运行以下命令为你的项目生成本地代码:

🌐 Generate the native code for your project by running the following command:

Terminal
npx expo prebuild -p android

这将在你的项目根目录下添加一个 android 目录。

🌐 This will add an android directory at the root of your project.

2

通过运行以下命令在 Android Studio 中打开项目:

🌐 Open the project in Android Studio by running the command:

Terminal
open -a "/Applications/Android Studio.app" ./android

3

从 Android Studio 构建应用并连接调试器。更多信息请参阅 Google 的文档

🌐 Build the app from Android Studio and connect the debugger. See Google's documentation for more information.

当你完成此过程后,可以删除 android 目录。这可以确保你的项目继续由 Expo CLI 管理。如果保留该目录并在 npx expo prebuild 之外手动修改它,你将需要自己手动升级和配置原生库。

Xcode

这仅适用于 macOS 用户,并且需要安装 Xcode。

1

通过运行以下命令为你的项目生成本地代码:

🌐 Generate the native code for your project by running the following command:

Terminal
npx expo prebuild -p ios

这将在你的项目根目录下添加一个 ios 目录。

🌐 This will add an ios directory at the root of your project.

2

通过运行命令在 Xcode 中打开项目,该命令是一个快捷方式,可从项目的 ios 目录中打开 .xcworkspace 文件。

🌐 Open the project in Xcode by running the command which is a shortcut to open the .xcworkspace file from your project's ios directory in Xcode.

Terminal
xed ios

3

使用 Cmd ⌘ + r 构建应用,或者点击 Xcode 左上角的播放按钮。

4

你现在可以使用 低级调试器 (LLDB) 以及所有其他 Xcode 调试工具 来检查原生运行时。

🌐 You can now utilize Low-level debugger (LLDB) and all of the other Xcode debugging tools to examine the native runtime.

完成此过程后,你可以删除或将 ios 目录加入 gitignore。这样可以确保你的项目仍由 Expo CLI 管理。如果保留该目录并在 npx expo prebuild 外手动修改它,那么你将需要自己手动升级和配置原生库。

查看本地日志

🌐 Viewing native logs

当你的应用崩溃或表现异常时,JavaScript 的错误输出并不总是能说明全部情况。来自 Android 和 iOS 的原生日志可以显示崩溃原因、原生模块错误以及在 Metro 打包工具或 React Native 开发工具中无法显示的系统级警告。

🌐 When your app crashes or behaves unexpectedly, the JavaScript error output doesn't always tell the full story. Native logs from Android and iOS can reveal crash reasons, native module errors, and system-level warnings that don't surface in the Metro bundler or React Native DevTools.

如何使用 ADB Logcat 和 macOS 控制台进行调试
如何使用 ADB Logcat 和 macOS 控制台进行调试

在本教程中,你将学习如何使用本地设备日志功能,如 ADB Logcat 和 macOS 控制台,来查找代码中的错误并快速修复它们。

安卓:adb logcat

🌐 Android: adb logcat

连接你的 Android 设备(或使用模拟器)并运行以下命令:

🌐 Connect your Android device (or use an emulator) and run the following command:

Terminal
adb logcat

Android 调试桥(adb)程序是 Android SDK 的一部分,允许你查看实时日志。避免安装 Android SDK 的一种替代方法是在 Chrome 中使用 WebADB

🌐 The Android Debug Bridge (adb) program is part of the Android SDK and allows you to view streaming logs. An alternative to avoid installing the Android SDK is to use WebADB in Chrome.

iOS:控制台应用

🌐 iOS: Console app

你可以通过将设备连接到 Mac(或在运行 iOS 模拟器时)来使用 Xcode 中的 Console 应用。按照以下步骤访问 Console 应用:

🌐 You can use the Console app in Xcode by connecting your device to your Mac (or while running an iOS Simulator). Follow the steps below to access the Console app:

1

打开 Xcode 应用,然后按下 Shift + Cmd ⌘ + 2 打开 设备与模拟器 窗口。

2

如果你已连接物理设备,请在 设备 下选择它。否则,如果你使用模拟器,请在 模拟器 下选择它。

🌐 If you have connected a physical device, select it under Devices. Otherwise, if you are using a simulator, select it under Simulators.

3

点击窗口中显示的 打开控制台 按钮以打开控制台应用。

🌐 Click on Open Console button shown in the window to open the console app.

这将为你打开控制台应用,以便查看你的设备或模拟器的日志。

🌐 This will open the console app for you to view logs from your device or simulator.

生产错误

🌐 Production errors

生产环境中的应用错误或漏洞可能更难解决,主要因为你对错误的上下文了解较少(也就是说,错误发生的地点、方式以及原因是什么?)。

🌐 Errors or bugs in your production app can be much harder to solve, mainly because you have less context around the error (that is, where, how, and why did the error occur?).

解决生产错误的最佳第一步是在本地重现它。 一旦你在本地重现了错误,就可以按照开发调试流程来定位并解决根本原因。

生产应用崩溃

🌐 Production app is crashing

当生产环境的应用崩溃时,可用的信息非常有限,相比开发环境更难获取。首先尝试在本地重现崩溃,然后按以下步骤逐步排查原因:

🌐 When a production app crashes, there is very little information available compared to development. Start by trying to reproduce the crash locally, then work through these steps to narrow down the cause:

  • 检查特定平台的崩溃报告。
  • 使用本地日志工具。 连接一个会重现崩溃的设备,并使用adb logcat或控制台应用捕获本地日志输出。当 JavaScript 错误边界未能捕获问题时,本地日志通常可以揭示根本原因。
  • 在本地尝试生产模式。 在本地以 生产模式 运行你的应用将显示通常不会抛出的错误。为此,你可以运行 npx expo start --no-dev --minify--no-dev 标志告诉服务器以生产模式运行,而 --minify 则用于像生产 JavaScript 包一样压缩你的代码。
  • 检查你的崩溃报告仪表板。 如果你使用 SentryBugSnag 或类似服务,请先在那里检查崩溃情况。这些服务提供堆栈跟踪、设备信息和复现上下文。

应用在某些(较旧)设备上崩溃

🌐 App crashes on certain (older) devices

这可能表明存在性能问题。你可能需要通过分析器运行你的应用,以更好地了解哪些进程导致应用性能下降,React Native 提供了非常好的相关文档。我们还建议使用 React Native 开发工具 以及附带的 分析器,这样可以非常容易地识别应用中的 JavaScript 性能瓶颈。

🌐 This might indicate that there is a performance issue. You likely need to run your app through a profiler to get a better idea of what processes are killing the app, and React Native provides some great documentation for this. We also recommend using React Native DevTools and the included profiler, which makes it super easy to identify JavaScript performance sinks in your app.

使用错误报告服务

🌐 Using error reporting services

在生产应用中实现崩溃和错误报告服务有几个好处,例如:

🌐 Implementing a crash and bug reporting service in your production app offers several benefits, such as:

  • 实时洞察生产部署,并提供重现崩溃和错误的信息。
  • 设置警报系统以获取有关致命 JavaScript 错误或你配置的任何其他事件的通知。
  • 使用 Web 仪表板查看异常的详细信息,例如堆栈跟踪、设备信息等。

使用 Expo,你可以集成像 SentryBugSnag 这样的报告服务,以实时获取更多洞察。

🌐 With Expo, you can integrate a reporting service like Sentry or BugSnag to get more insights in real-time.

卡住?

🌐 Stuck?

当你遇到困难时,Expo 社区以及 React 和 React Native 社区都是很好的帮助资源。很有可能其他人也遇到过同样的错误,所以一定要阅读文档,搜索论坛GitHub 问题以及Stack Overflow

🌐 The Expo community and the React and React Native communities are great resources for help when you get stuck. There's a good chance someone else has run into the same error as you, so make sure to read the documentation, search the forums, GitHub issues, and Stack Overflow.