解决构建错误和崩溃问题
使用 EAS Build 时排除构建错误和崩溃的参考。
当出现问题时,可能会以以下两种方式之一出现问题:
🌐 When something goes wrong, it probably will go wrong in one of two following ways:
- 你的构建将会失败。
- 构建将成功,但会遇到运行时错误,例如,运行时崩溃或挂起。
关于缩小错误来源的所有标准建议在这里同样适用;本文档提供的信息可能在你通常的故障排除流程和技巧之外有所帮助。故障排除是一门艺术,你可能需要发挥创造性思维。
🌐 All standard advice around narrowing down the source of an error applies here; this document provides information that may be useful on top of your typical troubleshooting processes and techniques. Troubleshooting is an art, and you might need to think creatively.
查找相关错误日志
🌐 Find the related error logs
在进一步操作之前,你需要确认已经找到了错误信息并阅读了它。具体操作方式会有所不同,这取决于你是在调查构建失败还是运行时错误。
🌐 Before you go further, you need to be sure that you have located the error message and read it. How you do this will be different depending on whether you're investigating a build failure or runtime error.
运行时错误
🌐 Runtime errors
这一类别下的常见问题包括:“我的应用在本地运行良好,但在构建后立即崩溃”或“我的应用在 Expo Go 中可以正常运行,但在我的构建中启动屏幕卡住”。当你的应用构建成功,但运行时崩溃或卡住时,这被认为是运行时错误。
🌐 Common questions that fall under this category are: "my app runs well locally but crashes immediately when I run a build" or "my app works in Expo Go but hangs on the splash screen in my build". When your app builds successfully but crashes or hangs when you run it, this is considered a runtime error.
请参阅调试指南中的【“生产错误”部分】(/debugging/runtime-issues/#production-errors),了解当发布版在运行时崩溃时如何定位日志。
🌐 Refer to the "Production errors" section of the debugging guide to learn how to locate logs when your release builds are crashing at runtime.
如果你通过这种方法找不到任何有用的信息,尝试逐步缩小崩溃来源。
🌐 If you can't find any useful information through this approach, try narrowing down the source of the crash step by step.
构建错误
🌐 Build errors
进入你的构建详细信息页面(如果你还没有打开,可以在构建仪表板上找到)并点击展开任何失败的构建阶段。通常,最早出现错误的阶段会包含最有用的信息,任何随后的失败阶段都可能是由第一个阶段引发的。
🌐 Go to your build details page (find it on the build dashboard if you don't have it open already) and expand any failed build phases by clicking on them. Often, the earliest phase with errors will contain the most useful information and any subsequent failed phase will have cascaded from the first.
无论处于哪个阶段,看到日志条目前缀为 [stderr] 是很常见的,但请记住,这并不一定意味着这些日志指向错误;CLI 工具通常会使用 stderr 输出警告和其他诊断信息。
例如,你可能会在 Android 版本上看到类似的内容:
🌐 For example, you might see something like this on your Android builds:
[stderr] Note: /build/workingdir/build/app/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java uses or overrides a deprecated API.[stderr] Note: Recompile with -Xlint:deprecation for details.虽然你可能对跟进那个警告感兴趣,也可能不感兴趣,但它并不是导致构建失败的原因。那么,你如何知道哪些日志才是真正负责的呢?如果你正在构建一个空白项目,你已经很擅长这件事了。如果你正在构建一个托管项目,可能会有些棘手,因为你并不直接操作原生代码,只是编写 JavaScript。
🌐 While you may or may not be interested in following up on that warning, it is not the cause of your failed build. So how do you know which logs are truly responsible? If you are building a bare project, you will already be good at this. If you are building a managed project, it may be tricky because you don't directly interact with the native code, only write JavaScript.
一个好的前进方向是确定构建失败是由于本地错误还是 JavaScript 错误。当你的构建因 JavaScript 构建错误而失败时,通常会看到类似这样的情况:
🌐 A good path forward is to determine if the build failed due to a native or JavaScript error. When your build fails due to a JavaScript build error, you will usually see something like this:
❌ Metro encountered an error:Unable to resolve module ./src/Routes from /Users/expo/workingdir/build/App.js这个特定错误意味着应用正在导入 ./src/Routes,但未找到。原因可能是 Git 中的文件名大小写与开发者的文件系统不同(例如,Git 中是 routes.js 而不是 Routes.js),或者项目有一个构建步骤,但它没有设置在 EAS Build 上运行。在这种情况下,事实证明 ./src/Routes 本意是导入 ./src/Routes/index.js,但该路径在开发者的 .gitignore 中意外被排除了。
🌐 This particular error means that the app is importing ./src/Routes and it is not found. The cause could be that the filename case is different in Git than the developer's filesystem (for example, routes.js in Git instead of Routes.js), or maybe the project has a build step and it wasn't set up to run on EAS Build. In this case, it turns out that in this case ./src/Routes was intended to import ./src/Routes/index.js, but that path was accidentally excluded in the developer's .gitignore.
需要注意的是,对于 iOS 构建,构建详细信息页面只显示日志的简化版本,因为 xcodebuild 的完整输出可能达到 10MB 左右。有时需要打开完整的 Xcode 日志才能找到所需的信息;例如,如果 JavaScript 构建失败,但在构建详细信息页面上看不到任何有用的信息。要打开完整的 Xcode 日志,请在构建完成后滚动到构建详细信息页面底部,然后点击查看或下载它们。
🌐 It's important to note that with iOS builds the build details page only displays an abridged version of the logs because the full output from xcodebuild can be in the order of 10MB. Sometimes it's necessary to open the full Xcode logs to find the information that you need; for example, if the JavaScript build failed but you don't see any useful information on the build details page. To open the full Xcode logs, scroll to the bottom of the build details page when the build has been completed and either click to view or download them.
如果你正在开发一个受管理的应用,并且构建错误是原生错误而不是 JavaScript 错误,这很可能是由于你的项目中的 配置插件 或某个依赖引起的。请注意查看日志中自上次成功构建以来你新增的任何包。运行 npx expo-doctor 以确定你项目中 Expo SDK 依赖的版本是否与你的 Expo SDK 版本兼容。
🌐 If you are working on a managed app and the build error is a native error rather than a JavaScript error, this is likely due to a config plugin or a dependency in your project. Keep an eye out in the logs for any new packages that you have added since your previous successful build. Run npx expo-doctor to determine that the versions of Expo SDK dependencies in your project are compatible with your Expo SDK version.
有了错误日志,你通常可以开始修复你的构建问题,或者在论坛和 GitHub 问题中搜索相关的包以进行更深入的调查。下面列出了一些常见的问题来源。
🌐 Armed with your error logs, you can often start to fix your build or search the forums and GitHub issues for related packages to dig deeper. Some common sources of problems are listed below.
你在使用单体仓库吗?
单仓库非常有用,但它们确实会带来一系列问题。需要将整个单仓库上传到 EAS Build 构建器,进行设置,然后运行构建。
🌐 Monorepos are incredibly useful but they do introduce their own set of problems. It's necessary to upload the entire monorepo to the EAS Build builders, set it up, and run the build.
EAS Build 更像是一个典型的 CI 服务,因为我们需要源代码,而不是已编译的 JavaScript 包和清单。EAS Build 对 Yarn 工作区有一流的支持,而使用其他 monorepo 工具时,你的成功可能会有所不同。
🌐 EAS Build is more like a typical CI service in that we need the source code, rather than a compiled JavaScript bundle and manifest. EAS Build has first-class support for Yarn workspaces, and your success may vary when using other monorepo tools.
欲了解更多信息,请参阅 使用 monorepo。
🌐 For more information, see Working with monorepos.
内存不足(OOM)错误
如果你的构建失败,并且在 Gradle 日志中出现“Gradle build daemon 异常消失(它可能被杀死或崩溃)”,这是因为负责打包你的应用 JavaScript 的 Node 进程被终止了。
🌐 If your build fails with "Gradle build daemon disappeared unexpectedly (it may have been killed or may have crashed)" in your Gradle logs, this is because the Node process responsible for bundling your app JavaScript was killed.
这通常可能是你的应用包非常大的一个信号,这会导致你的整体应用二进制文件更大,并导致启动时间变慢,特别是在低端安卓设备上。有时,当将大型文本文件当作源代码处理时,也可能会发生此错误,例如,如果你有一个 JavaScript 文件,其中包含 1MB 以上的 HTML 字符串以加载到 webview 中,或者一个大小相似的 JSON 文件。
🌐 This can often be a sign that your app bundle is extremely large, which will make your overall app binary larger and lead to slow boot up times, especially on low-end Android devices. Sometimes the error can occur when large text files are treated as source code, for example, if you have a JavaScript file that contains a string of 1MB+ of HTML to load into a webview, or a similarly sized JSON file.
要确定你的包有多大并查看大小来源的详细分解,请使用 Expo Atlas。
🌐 To determine how large your bundle is and to see a breakdown of where the size comes from, use Expo Atlas.
要增加 EAS Build 构建器的内存限制,请在你的 eas.json 中使用 large 资源类。有关更多信息,请参阅 Android 专用资源类 和 iOS 专用资源类。
🌐 To increase memory limits on your EAS Build builders, use large resource class in your eas.json. See Android-specific resource class and iOS-specific resource class for more information.
没有任何文件存在错误
当你运行 eas build 时,你项目的文件会被上传到 Expo 的构建服务器。然而,任何在 .gitignore 中提到的文件或目录 不会被上传。这是为了防止敏感信息,如 API 密钥,在你的应用代码中被暴露,这是有意为之的。
🌐 When you run eas build, your project's files are uploaded to Expo's build servers. However, any file or directory mentioned in the .gitignore is not uploaded. This is intentional to prevent sensitive information, such as API keys, from being exposed in your app's code.
如果你的项目导入了 .gitignore 中列出的文件,构建将会因为 None of these files exist 错误而失败。有多种方法可以解决此错误:
🌐 If your project imports a file listed in .gitignore, the build will fail with a None of these files exist error. There are different ways you can resolve this error:
- 删除被忽略文件的导入语句并测试你的项目。如果项目按预期运行,该导入语句可能已过时或未使用。
- 从你的 .gitignore 中移除 Metro 无法解析的任何文件或目录。然而,这会带来安全风险,因为这些文件中包含的任何敏感信息现在都可以在你的项目源代码和 Git 提交历史中访问。
- 使用
base64对文件进行编码,将该字符串保存为 secrets,然后在 EAS Build 钩子中创建该文件。有关更多信息,请参阅 如果文件被 gitignore,我如何将它们上传到 EAS Build?。 - 重构你的源代码,避免在客户端导入敏感文件。如果某个文件是来自第三方提供者的自动生成代码,并且该提供者已经自动将文件列入你的 .gitignore,那么该文件很可能包含敏感信息。你不应在客户端包含它。在应用开发过程中,确保遵循安全做法,例如使用环境变量或通过后端提供这些信息。更多信息请参见 在环境变量中使用密钥。
比较构建日志
🌐 Compare build logs
当以前成功的 EAS 构建开始失败时,确定两个构建之间发生的变化可以帮助找出根本原因。EAS 构建详情页面上的 比较 按钮可以帮助你并排比较两个构建,显示它们的构建日志和配置差异。
🌐 When an EAS Build that previously succeeded starts failing, identifying what changed between the two builds can help pinpoint the root cause. The Compare button on the EAS Build details page helps you compare two builds side-by-side, showing differences in their build logs and configuration.
比较两个版本:
🌐 To compare two builds:
- 在你失败的构建的EAS 仪表板上打开你的构建详细信息页面
- 点击 比较 按钮以打开比较窗口
- 输入要比较的构建的构建 ID 或完整构建 URL。这将是之前已成功的构建。
- 点击 比较。
上面的截图显示了比较视图,其中在顶部显示了两个构建及其元数据。这包括状态、环境、Expo SDK 版本等。在元数据下方,左右并排的日志比较显示了按每个构建阶段组织的输出。
🌐 The above screenshot shows the comparison view that displays both builds with their metadata at the top. This includes, status, environment, Expo SDK version, and more. Below the metadata, a side-by-side log comparison shows output organized by each build phase.
在每个构建阶段,会使用一个指示器来显示两次构建之间的变化:
🌐 Within each build phase, an indicator is used to show what changed between the two builds:
- 已更改 (X 行):该阶段在两个构建中都运行,但产生了不同的输出。
- + 已添加:该阶段仅存在于比较版本中(原始版本在达到此阶段之前已失败)。
- - 已移除:该阶段仅存在于原始版本中。
在上面的例子中,将右侧失败的构建与左侧成功的构建进行比较,可以发现已安装的包和高亮显示的锁文件不匹配的差异。
🌐 In the above example, comparing a failed build on the right side against a successful build on the left reveals differences in installed packages and highlighted lock files mismatch.
验证你的 JavaScript 包是否在本地运行
🌐 Verify that your JavaScript bundles locally
当构建因 Task :app:bundleReleaseJsAndAssets FAILED(Android)或 Metro encountered an error(iOS)失败时,这意味着 Metro 打包器在尝试将应用的 JavaScript 代码嵌入应用二进制文件时无法打包。这条错误信息通常会跟随一个语法错误或其他关于打包失败原因的详细信息。不幸的是,标准的 React Native 项目配置是在 Gradle/Xcode 构建步骤的后期才执行此步骤,这意味着看到这个错误可能需要一些时间。
🌐 When a build fails with Task :app:bundleReleaseJsAndAssets FAILED (Android) or Metro encountered an error (iOS), it means Metro bundler was unable to bundle the app's JavaScript code while trying to embed it in your app's binary. This error message is usually followed by a syntax error or other details about why bundling failed. Unfortunately, a standard React Native project is configured to perform this step late in the Gradle/Xcode build step, meaning it can take a while to see this error.
你可以通过运行 npx expo export 在本地构建生产包,以跳过所有其他构建步骤,从而更快地看到此错误。重复运行此命令,解决发现的任何语法错误或其他问题,直到包成功构建。然后再尝试你的 EAS 构建。
🌐 You can build the production bundle locally by running npx expo export to bypass all of the other build steps so you can see this error much more quickly. Run this command repeatedly, resolving any syntax errors or other issues uncovered until the bundle builds successfully. Then try your EAS Build again.
验证你的项目在本地能构建并运行
🌐 Verify that your project builds and runs locally
如果日志不足以立即帮助你理解并解决根本原因,那么就该尝试在本地重现该问题。如果你的项目在本地以发布模式构建和运行正常,那么只要以下条件都成立,它也可以在 EAS Build 上构建成功:
🌐 If the logs weren't enough to immediately help you understand and fix the root cause, it's time to try to reproduce the issue locally. If your project builds and runs locally in release mode then it will also build on EAS Build, provided that the following are all true:
你可以使用 npx expo run:android 和 npx expo run:ios 命令在本地机器上验证你的项目是否能够构建,并将变体/配置标志设置为发布,以最忠实地再现 EAS Build 上的执行情况。欲了解更多信息,请参阅 Android 构建流程 和 iOS 构建流程。
🌐 You can verify that your project builds on your local machine with the npx expo run:android and npx expo run:ios commands, with variant/configuration flags set to release to most faithfully reproduce what executes on EAS Build. For more information, see Android build process and iOS build process.
# Locally compile and run the Android app in release mode- npx expo run:android --variant release# Locally compile and run the iOS app in release mode- npx expo run:ios --configuration Release如果使用 CNG,这些命令将运行
npx expo prebuild来生成本地项目以进行编译。完成故障排除后,你可能想要清理更改,除非你想直接管理这些项目,而不是按需生成它们。
另外,你可以使用
eas build --local执行本地构建 —— 该命令将运行一系列步骤,这些步骤尽可能接近托管的 EAS 构建服务远程运行的过程。它会将你的项目复制到一个临时目录,并在那里进行必要的更改。了解如何设置并使用它进行调试。
如果本地的原生工具链已正确安装,但你仍然无法在本地机器上以发布模式构建和运行项目,那么在 EAS Build 上也无法构建。请先在本地解决这些问题,然后再在 EAS Build 上重试。本文档中的其他建议可能有助于你在本地解决问题,但通常这需要对原生工具有一定的了解,或者合理使用 Google、Stack Overflow 和 GitHub Issues。
🌐 If your native toolchains are installed correctly and you are unable to build and run your project in release mode on your local machine, it will not build on EAS Build. Fix the issues locally, then try again on EAS Build. The other advice in this doc may be useful to help you resolve the issue locally, but often this requires some knowledge of native tooling or judicious application of Google, Stack Overflow, and GitHub Issues.
你的电脑上没有安装 Xcode 和 Android Studio 吗?
如果你本地没有安装原生工具链,例如,因为你没有 Apple 电脑,因此无法在你的机器上构建 iOS 应用,那么排查构建错误可能会更加棘手。在 EAS Build 上做小修改并查看结果的反馈循环,比在本地执行相同步骤要慢,因为 EAS Build 构建器必须先设置环境、下载你的项目并安装依赖,然后才能开始构建。
如果你愿意并且能够设置适当的本地工具,请参阅 React Native 环境设置指南。
🌐 If you are willing and able to set up the appropriate native tools, then refer to the React Native environment setup guide.
我的应用可以在本地构建,但在 EAS Build 上无法构建
默认情况下,EAS Build 在为你的应用构建(Android 或 iOS)时遵循相对简单的流程。如果 npx expo run:android --variant release 和 npx expo run:ios --configuration Release 在本地可以正常运行,但你的构建失败,那么就是时候缩小范围,找出你机器上存在但尚未为 EAS Build 项目配置的设置。
🌐 By default, EAS Build follows a relatively straightforward process for building your app for (Android or iOS). If npx expo run:android --variant release and npx expo run:ios --configuration Release work locally, but your builds fail, then it's time to narrow down what configuration exists on your machine that hasn't been set up for your project on EAS Build yet.
为什么我的生产环境应用与开发环境应用不一致?
你可以通过使用 npx expo start --no-dev 启动你的应用来测试其 JS 部分在生产环境中的运行情况。这会告诉打包工具在提供服务之前压缩 JavaScript,最显著的是会移除被 __DEV__ 布尔值保护的代码。这会删除大部分日志、HMR、快速刷新功能,并让调试变得稍微困难一些,但你可以以这种方式更快地对生产包进行迭代。
🌐 You can test how the JS part of your app will run in production by starting it with npx expo start --no-dev. This tells the bundler to minify JavaScript before serving it, most notably stripping code protected by the __DEV__ boolean. This will remove most of the logging, HMR, Fast Refresh functionality, and make debugging a bit harder, but you can iterate on the production bundle faster this way.
仍然有问题吗?
🌐 Still having trouble?
本指南远非全面,根据你的经验水平,你可能仍然在努力让你的应用正常运行。
🌐 This guide is far from being comprehensive, and depending on your level of experience you might still be struggling to get your app working.
如果你按照这里的建议去做,现在你已经处于一个有利的位置,可以向其他开发者描述你的问题并寻求帮助。
🌐 If you have followed the advice here, you're now in a good position to describe your issue to other developers and get some help.
如何提出一个好问题
🌐 How to ask a good question
加入我们的 Discord和论坛 ,向社区和 Expo 团队寻求帮助。Expo 团队会尽力回应高质量且表达清晰的问题和情况,但除非你注册了支持计划,否则无法保证一定会得到回应。为了确保 Expo 团队的成员看到你的问题,你可以在expo.dev/contact提交工单。
当你寻求故障排除帮助时,请务必分享以下信息:
🌐 When you ask for troubleshooting help, be sure to share the following information:
- 你的构建页面的链接。此链接只能由你的团队或 Expo 员工访问。如果你想更公开地分享它,可以截个图。如果你想更私密地分享,请发送电子邮件至 secure@expo.dev,并在聊天或论坛的帮助请求中提及此事。如果你正在本地使用
eas build --local执行此构建,可以省略此步骤,但请提及这一事实。 - 错误日志。任何你怀疑可能与构建或运行时错误有关的内容。如果你无法提供,请解释原因。
- 最小可复现示例或你的代码仓库链接。获取问题解决方案的最快方法是确保其他开发者能够复现你的问题。如果你曾经在团队中工作过,你会从经验中了解这一点。在很多情况下,如果你无法提供可复现的示例,那么可能无法得到帮助,最多也只是问答的反复过程,效率低下。了解更多关于如何创建可复现示例的信息,请参阅手动调试指南和 Stack Overflow 的最小可行可复现示例指南。
尽量清晰、准确并且有帮助。Stack Overflow 的《如何提出好问题》(https://stackoverflow.com/help/how-to-ask) 指南提供的一般性指导同样适用。
🌐 Try to be clear, precise, and helpful. General guidance provided by Stack Overflow's How to ask a good question guide applies.