This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
排查构建错误和崩溃
编辑页面
使用 EAS Build 时排查构建错误和崩溃的参考指南。
当出问题时,它很可能会以以下两种方式之一出错:
- 你的构建会失败。
- 构建会成功,但会遇到运行时错误,例如,在你运行它时崩溃或卡住。
关于缩小错误来源范围的所有标准建议在这里都适用;本文档提供了一些可能在你常规排查流程和技巧之外有用的信息。故障排查是一门艺术,你可能需要创造性地思考。
查找相关的错误日志
在继续之前,你需要确认自己已经找到了错误信息并且读过了它。具体怎么做会因你是在排查构建失败还是运行时错误而有所不同。
运行时错误
属于此类别的常见问题包括:“我的应用在本地运行良好,但一旦我运行构建就会立即崩溃”或“我的应用在 Expo Go 中可以正常工作,但在我的构建中会卡在启动画面”。当你的应用构建成功,但在运行时崩溃或卡住时,这被视为运行时错误。
请参阅调试指南中的“生产环境错误”部分,以了解当你的发布构建在运行时崩溃时如何查找日志。
如果通过这种方法仍然找不到任何有用的信息,请尝试逐步缩小崩溃来源。
构建错误
前往你的构建详情页面(如果你还没有打开它,可以在 构建仪表板 中找到它),然后点击任意失败的构建阶段将其展开。通常,最早出现错误的阶段会包含最有用的信息,而后续失败的阶段往往是由第一个错误级联导致的。
无论处于哪个阶段,日志条目前缀带有 [stderr] 很常见,但请记住,这并不一定意味着这些日志指向错误;CLI 工具经常使用 stderr 来输出警告和其他诊断信息。
例如,在你的 Android 构建中,你可能会看到类似这样的内容:
[stderr] 注意:/build/workingdir/build/app/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java 使用或重写了已弃用的 API。[stderr] 注意:使用 -Xlint:deprecation 重新编译以获取详细信息。虽然你可能也可能不关心这个警告,但它并不是构建失败的原因。那么,如何判断哪些日志才是真正的原因呢?如果你正在构建一个现有的 React Native 项目,你应该已经很熟悉这一点了。如果你正在构建一个使用 Continuous Native Generation (CNG) 的项目,那么这可能会有些棘手,因为你并不直接与原生代码交互,而只是编写 JavaScript。
一个好的方向是判断构建失败是由原生错误还是 JavaScript 错误导致的。当你的构建因 JavaScript 构建错误而失败时,通常会看到类似这样的信息:
❌ Metro 遇到一个错误:无法解析模块 ./src/Routes,来源于 /Users/expo/workingdir/build/App.js这个特定错误意味着应用正在导入 ./src/Routes,但它没有被找到。原因可能是 Git 中的文件名大小写与开发者文件系统中的不同(例如,Git 中是 routes.js,而不是 Routes.js),或者项目有一个构建步骤,但它没有配置为在 EAS Build 上运行。在这种情况下,事实证明 ./src/Routes 原本是要导入 ./src/Routes/index.js,但这个路径不小心被开发者的 .gitignore 排除了。
需要注意的是,对于 iOS 构建,构建详情页面只会显示一部分日志,因为 xcodebuild 的完整输出可能达到约 10MB。有时有必要打开完整的 Xcode 日志来查找你需要的信息;例如,当 JavaScript 构建失败但你在构建详情页面上看不到任何有用信息时。要打开完整的 Xcode 日志,请在构建完成后滚动到构建详情页面底部,然后点击查看或下载它们。
如果你正在使用 Continuous Native Generation (CNG) 的项目,并且构建错误是原生错误而不是 JavaScript 错误,那么这很可能是由 配置插件 或你项目中的某个依赖项引起的。请留意日志中自上次成功构建以来你新增的任何包。运行 npx expo-doctor 以确定项目中的 Expo SDK 依赖版本与你的 Expo SDK 版本是否兼容。
有了错误日志后,你通常可以开始修复构建问题,或者在 论坛 和 GitHub issues 中搜索相关包以深入排查。下面列出了一些常见问题来源。
你是否在使用 monorepo?
Monorepo 非常有用,但它们也会带来自己的一套问题。需要将整个 monorepo 上传到 EAS Build 构建器,完成设置,然后运行构建。
EAS Build 更像是典型的 CI 服务,因为我们需要的是源代码,而不是编译后的 JavaScript bundle 和清单。EAS Build 对 Yarn workspaces 提供一流支持,而 使用其他 monorepo 工具时,结果可能会有所不同。
有关更多信息,请参阅 使用 monorepo。
内存不足(OOM)错误
如果你的构建在 Gradle 日志中出现 "Gradle build daemon disappeared unexpectedly (it may have been killed or may have crashed)",这是因为负责为应用 JavaScript 打包的 Node 进程被终止了。
这通常表明你的应用 bundle 非常大,这会让整体应用二进制文件更大,并导致启动时间变慢,尤其是在低端 Android 设备上。有时,当较大的文本文件被当作源代码处理时也会出现这个错误,例如,如果你有一个包含 1MB+ HTML 字符串、用于加载到 webview 中的 JavaScript 文件,或者一个大小相近的 JSON 文件。
要确定 bundle 的大小以及查看大小来源的分布情况,请使用 Expo Atlas。
要提高 EAS Build 构建器的内存限制,请在 eas.json 中使用 large resource class。更多信息请参阅 Android-specific resource class 和 iOS-specific resource class。
不存在任何文件的错误
当你运行 eas build 时,项目文件会被上传到 Expo 的构建服务器。然而,.gitignore 中提到的任何文件或目录都不会被上传。这样做是有意为之,目的是防止 API 密钥等敏感信息暴露在应用代码中。
如果你的项目导入了 .gitignore 中列出的文件,构建将会失败,并出现 None of these files exist 错误。你可以通过以下几种方式解决此错误:
-
移除被忽略文件的导入语句并测试你的项目。如果项目按预期运行,那么该导入语句可能已经过时或未被使用。
-
将 Metro 无法解析的任何文件或目录从 .gitignore 中移除。不过,这会带来安全风险,因为这些文件中包含的任何敏感信息现在都会出现在项目的源代码和 Git 提交历史中。
-
使用
base64对文件进行编码,将该字符串保存为 secrets,并在 EAS Build hook 中创建该文件。更多信息请参阅 如果文件被 gitignore,如何将其上传到 EAS Build? -
重构源代码,避免在客户端导入敏感文件。如果某个文件是第三方提供商自动生成的代码,并且该提供商已经自动将文件列入你的 .gitignore,那么该文件很可能包含敏感信息。你不应在客户端包含它。在应用开发过程中,请确保遵循安全实践,例如使用环境变量或通过后端提供这些内容。更多信息请参阅 在环境变量中使用 secrets。
比较构建日志
当之前成功的 EAS Build 开始失败时,找出两次构建之间发生了哪些变化,有助于定位根本原因。EAS Build 详情页面上的 比较 按钮可以帮助你并排比较两个构建,显示它们在构建日志和配置上的差异。
要比较两个构建:
- 在失败构建的 EAS 仪表板 中打开构建详情页面
- 点击 比较 按钮打开比较弹窗
- 输入你想进行比较的构建的 build ID 或完整 build URL。这将是之前成功的构建。
- 点击 比较。
上面的截图展示了比较视图,它在顶部显示两个构建及其元数据。这包括状态、环境、Expo SDK 版本等。在元数据下方,并排的日志比较会按每个构建阶段组织输出。
在每个构建阶段中,会使用指示标记来显示两个构建之间发生了什么变化:
- 已更改(X 行):该阶段在两个构建中都运行了,但输出不同。
- + 新增:该阶段只存在于比较构建中(原始构建在到达此阶段之前就失败了)。
- - 已移除:该阶段只存在于原始构建中。
在上面的示例中,将右侧失败的构建与左侧成功的构建进行比较,可以看出已安装包的差异,并突出显示了 lock 文件不匹配的问题。
在本地验证你的 JavaScript bundles
当构建因 Task :app:bundleReleaseJsAndAssets FAILED(Android)或 Metro encountered an error(iOS)而失败时,这意味着 Metro bundler 在尝试将应用的 JavaScript 代码嵌入到应用二进制文件中时,无法完成打包。该错误信息通常后面会跟随语法错误或其他有关打包失败原因的详细信息。不幸的是,标准 React Native 项目被配置为在 Gradle/Xcode 构建步骤的后期执行此步骤,这意味着你可能需要花一段时间才能看到这个错误。
你可以在本地运行 npx expo export 来构建生产 bundle,从而绕过其他所有构建步骤,以便更快地看到这个错误。重复运行该命令,解决发现的任何语法错误或其他问题,直到 bundle 成功构建。然后再次尝试你的 EAS Build。
验证您的项目是否可以在本地构建和运行
如果日志不足以立即帮助您了解并修复根本原因,那么是时候尝试在本地复现该问题了。如果您的项目可以在本地以 release 模式构建和运行,那么只要满足以下所有条件,它也应该能够在 EAS Build 上构建:
您可以使用 npx expo run:android 和 npx expo run:ios 命令在本地验证项目是否可以构建,并将 variant/configuration 标志设置为 release,以尽可能忠实地复现 EAS Build 的执行过程。更多信息,请参阅 Android 构建流程和 iOS 构建流程。
# 在本地以 release 模式编译并运行 Android 应用- npx expo run:android --variant release# 在本地以 release 模式编译并运行 iOS 应用- npx expo run:ios --configuration Release如果您正在使用 CNG,这些命令将运行
npx expo prebuild,以生成用于构建的原生项目。完成故障排查后,除非您希望直接管理这些项目而不是按需生成它们,否则您可能需要清理这些更改。
您也可以改用
eas build --local进行本地构建——此命令会执行一系列步骤,与托管 EAS Build 服务上的远程执行过程高度相似。它会将您的项目复制到临时目录,并在那里进行任何必要的更改。了解如何设置并使用它进行调试。
如果您的原生工具链已正确安装,但项目仍无法在本地以 release 模式构建和运行,那么它也无法在 EAS Build 上成功构建。请先在本地修复问题,然后再重新尝试 EAS Build。本文档中的其他建议可能会帮助您在本地解决问题,但这通常需要具备一定的原生工具链知识,或寻求 Google、Stack Overflow 和 GitHub Issues 上的适当帮助。
您的机器尚未设置 Xcode 和 Android Studio?
如果您没有在本地安装原生工具链,例如,如果您没有 Apple 电脑,因而无法在自己的机器上构建 iOS 应用,那么调试构建错误会更具挑战性。在本地进行小幅修改并查看 EAS Build 结果的反馈循环,比在本地执行相同步骤更慢,因为 EAS Build 构建器必须先设置环境、下载您的项目并安装依赖项,然后才能开始构建。
如果您愿意并且能够设置相关的原生工具,请参阅 React Native 环境设置指南。
我的应用可以在本地构建,但无法在 EAS Build 上构建
为什么我的生产应用和开发应用不一致?
您可以通过使用 npx expo start --no-dev 启动应用,测试应用的 JS 部分在生产环境中的行为。该命令会告知打包器在提供 JavaScript 之前对其进行压缩,尤其会移除由 __DEV__ 布尔值控制的代码。这会移除大部分日志、HMR 和快速刷新功能,使调试变得稍微困难一些,但可以让您更快地迭代生产构建包。
仍然有问题吗?
本指南远非全面,且根据你的经验水平,你可能仍然在努力让你的应用正常工作。
如果你已经遵循了这里的建议,那么你现在已经处于一个很好的位置,可以向其他开发者描述你的问题并获得一些帮助。
如何提出一个好问题
加入我们的 Discord 和论坛,向社区和 Expo 团队寻求帮助。Expo 团队会尽力回应高质量且表述清晰的问题和议题,但除非你注册了支持计划,否则无法保证一定会得到回复。要确保 Expo 团队成员看到你的问题,你可以在 expo.dev/contact 提交工单。
当你寻求排查帮助时,请务必提供以下信息:
- 构建页面的链接。只有你的团队或 Expo 员工才能访问它。如果你想更公开地分享,可以截屏。如果你想更私密地分享,可以发送电子邮件至 secure@expo.dev,并在你于聊天或论坛中的求助请求里提到这一点。如果你是使用
eas build --local在本地执行此构建,则可以省略这一项,但请说明这一事实。 - 错误日志。任何你怀疑可能与构建或运行时错误相关的内容。如果你无法提供这些内容,请解释原因。
- 最小可复现示例或你的仓库链接。获得问题解决方案最快的方法是确保其他开发者能够复现它。如果你曾在团队中工作过,你就会从经验中知道这一点。在许多情况下,如果你无法提供可复现的示例,那么可能无法帮助你;即使能帮到,来回提问和回答的过程也会是对时间的低效利用。要了解如何创建可复现示例,请参阅 手动调试指南 和 Stack Overflow 的最小可行可复现示例指南。
尽量做到清晰、准确且有帮助。Stack Overflow 的如何提出一个好问题指南中提供的一般建议同样适用。