# Expo Documentation Expo is an open-source React Native framework for apps that run natively on Android, iOS, and the web. Expo brings together the best of mobile and the web and enables many important features for building and scaling an app such as live updates, instantly sharing your app, and web support. The company behind Expo also offers Expo Application Services (EAS), which are deeply integrated cloud services for Expo and React Native apps. # 快速开始 ## 引言 立即开始使用Expo创建应用程序。 Expo 是一个简化 Android 和 iOS 应用开发的框架。我们的框架提供基于文件的路由系统、标准原生模块库等丰富功能。Expo 采用开源模式,在 [GitHub](https://github.com/expo/expo) 和 [Discord](https://chat.expo.dev) 上拥有活跃的社区。 我们还推出了[Expo应用服务(EAS)](https://expo.dev/eas),这套服务在开发流程的每个环节都为Expo框架提供补充支持。 开始使用请访问: ## 创建项目 学习如何创建一个新的Expo项目。 系统要求: - [Node.js (LTS)](https://nodejs.org/en/)。 - 支持 macOS、Windows(需 Powershell 和 [WSL 2](https://expo.fyi/wsl))及 Linux 系统。 建议从 `create-expo-app` 生成的默认项目开始。该项目包含示例代码以助您快速入门。 创建新项目请执行以下命令: ```sh $ npx create-expo-app@latest ``` > 您可以通过添加 [`--template` 选项](/more/create-expo/#--template) 来选择不同的模板。 ## 下一步 您已经创建了一个项目。现在是时候设置开发环境,以便您可以开始开发。 ## 设置您的环境 学习如何设置您的开发环境,以便开始使用 Expo 构建应用程序。 让我们为在 Android 和 iOS 上运行您的项目设置本地开发环境。 ## 您希望在哪里开发? 我们建议使用真实设备进行开发,因为您将能够准确看到用户所看到的内容。 ## 您希望如何开发? Expo Go 是一个快速尝试 Expo 的沙盒环境。开发构建是您自己应用的构建,其中包含 Expo 的开发工具。 --- # Android Emulator Setup ## 设置模拟器 Step 1: 在 Android Studio 主屏幕上,点击 **More Actions**,然后在下拉菜单中选择 **Virtual Device Manager**。 Step 2: 点击 **Create device** 按钮。 Step 3: 在 **Add device** 下,选择您想要模拟的硬件类型。我们建议测试多种设备,但如果您不确定从哪里开始,Pixel 系列中的最新设备可能是一个不错的选择。 Step 4: 选择要在模拟器上加载的操作系统版本(可能是系统映像之一),并下载该映像(如果需要)。 Step 5: 更改任何其他设置,然后按 **Finish** 创建模拟器。您现在可以通过在 AVD 管理器窗口中点击播放按钮随时运行此模拟器。 # Android Studio Environment Setup ## 安装 Watchman 和 JDK #### 先决条件 使用包管理器,例如 [Homebrew](https://brew.sh/),安装以下依赖项。 #### 安装依赖项 Step 1: 使用工具如 Homebrew [安装 Watchman](https://facebook.github.io/watchman/docs/install#macos): ```sh $ brew install watchman ``` Step 2: 使用 Homebrew 安装名为 Azul Zulu 的 OpenJDK 发行版。该发行版提供适用于 Apple Silicon 和 Intel Mac 的 JDK。 在终端中运行以下命令: ```sh $ brew install --cask zulu@17 ``` 安装 JDK 后,在 **~/.bash_profile**(如果使用 Zsh,请在 **~/.zshrc** 中)添加 `JAVA_HOME` 环境变量: ```bash export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home ``` #### 先决条件 使用包管理器,例如 [Chocolatey](https://chocolatey.org/),安装以下依赖项。 #### 安装依赖项 安装 [Java SE Development Kit (JDK)](https://openjdk.org/): ```sh $ choco install -y microsoft-openjdk17 ``` For Linux: #### 安装依赖项 Step 1: 按照 [Watchman 文档中的说明](https://facebook.github.io/watchman/docs/install#linux) 从源代码编译和安装它。 Step 2: 安装 [Java SE Development Kit (JDK)](https://openjdk.org/): 您可以从 [AdoptOpenJDK](https://adoptopenjdk.net/) 或您的系统打包程序下载并安装 [OpenJDK@17](http://openjdk.java.net/)。 # Android Studio Setup ## 设置 Android Studio For macOS: Step 1: 下载并安装 [Android Studio](https://developer.android.com/studio)。 Step 2: 打开 **Android Studio** 应用程序,您将看到 **SDK Components setup** 屏幕。点击 **Next** 继续安装 Android SDK 和 Android SDK 平台。再次点击 **Next** 验证设置并安装。 Step 3: 默认情况下,Android Studio 将安装最新版本的 Android SDK。但是,要编译 React Native 应用,需要 Android 15 (`VanillaIceCream`) SDK。 打开 Android Studio,转到 **Settings** > **Languages & Frameworks** > **Android SDK**。在 **SDK Platforms** 选项卡下,在 **Android 15 (`VanillaIceCream`)** 下,选择 **Android SDK 平台 35** 和 **Android 35 的源代码**。 Step 4: 然后,点击 **SDK Tools** 选项卡,确保您至少安装了一版 **Android SDK Build-Tools** 和 **Android Emulator**。 Step 5: 复制或记住框中显示的 **Android SDK Location**。 Step 6: 将以下行添加到您的 **/.zprofile** 或 **~/.zshrc** (如果您使用 bash,则为 **~/.bash_profile** 或 **~/.bashrc**)配置文件中: ```sh $ export ANDROID_HOME=$HOME/Library/Android/sdk $ export PATH=$PATH:$ANDROID_HOME/emulator $ export PATH=$PATH:$ANDROID_HOME/platform-tools ``` Step 7: 在您当前的 shell 中重新加载路径环境变量: ```sh $ source $HOME/.zshrc $ source $HOME/.bashrc ``` Step 8: 最后,确保您可以从终端运行 `adb`。 Note: 故障排除:Android Studio 未识别 JDK --- 如果 Android Studio 无法识别您通过 homebrew 安装的 JDK,您可以创建一个 Gradle 配置文件以明确设置 Java 路径: 1. 在您的主目录中创建一个 Gradle 属性文件: ```sh $ touch ~/.gradle/gradle.properties ``` 2. 将以下行添加到 **gradle.properties** 文件中,用您的实际 Java 安装路径替换路径: ```bash gradle.properties java.home=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home ``` 3. 如果您的项目目录中已有 `.gradle` 文件夹,请删除它并在 Android Studio 中重新打开项目: ```sh $ rm -rf .gradle ``` 这应该解决 Android Studio 无法检测到您 JDK 安装的问题。 --- For Windows: Step 1: 下载 [Android Studio](https://developer.android.com/studio)。 Step 2: 打开 **Android Studio 安装程序**。在 **Select components to install** 下,选择 Android Studio 和 Android 虚拟设备。然后,点击 **Next**。 Step 3: 在 Android Studio 安装向导中,选择 **Install Type**,选择 **Standard** 并点击 **Next**。 Step 4: Android Studio 安装向导将要求您验证设置,例如 Android SDK 的版本、平台工具等。在您验证后点击 **Next**。 Step 5: 在下一个窗口中,接受所有可用组件的许可证。 Step 6: 默认情况下,Android Studio 将安装最新版本的 Android SDK。但是,要编译 React Native 应用,需要 Android 15 (`VanillaIceCream`) SDK。 打开 Android Studio,转到 **Settings** > **Languages & Frameworks** > **Android SDK**。在 **SDK Platforms** 选项卡下,在 **Android 15 (`VanillaIceCream`)** 下,选择 **Android SDK Platform 35** 和 **Sources for Android 35**。 Step 7: 然后,点击 **SDK Tools** 选项卡,确保您至少安装了一版 **Android SDK Build-Tools** 和 **Android Emulator**。 Step 8: 工具安装完成后,配置 `ANDROID_HOME` 环境变量。转到 **Windows Control Panel** > **User Accounts** > **User Accounts**(再次)> **Change my environment variables**,点击 **New** 创建新的 `ANDROID_HOME` 用户变量。该变量的值将指向您的 Android SDK 路径: Note: 如何找到已安装的 SDK 位置? --- 默认情况下,Android SDK 安装在以下位置: ```bash %LOCALAPPDATA%\Android\Sdk ``` 要在 Android Studio 中手动查找 SDK 位置,转到 **Settings** > **Languages & Frameworks** > **Android SDK**。查看 **Android SDK Location** 旁边的地址。 --- Step 9: 要验证新的环境变量是否已加载,打开 **PowerShell**,并复制粘贴以下命令: ```sh $ Get-ChildItem -Path Env: ``` 该命令将输出所有用户环境变量。在此列表中,查看是否已添加 `ANDROID_HOME`。 Step 10: 要将平台工具添加到路径中,转到 **Windows Control Panel** > **User Accounts** > **User Accounts**(再次)> **Change my environment variables** > **Path** > **Edit** > **New**,并将平台工具的路径添加到列表中,如下所示: Note: 如何找到已安装的平台工具位置 --- 默认情况下,平台工具安装在以下位置: ```bash %LOCALAPPDATA%\Android\Sdk\platform-tools ``` --- Step 11: 最后,确保您可以从 PowerShell 运行 `adb`。例如,运行 `adb --version` 查看您的系统正在运行哪个版本的 `adb`。 # Xcode Setup Step 1: ### 安装 Xcode 打开 Mac App Store,搜索 [Xcode](https://apps.apple.com/us/app/xcode/id497799835),然后点击 **Install**(如果已经安装,则点击 **Update**)。 Step 2: ### 安装 Xcode 命令行工具 打开 Xcode,从 Xcode 菜单中选择 **Settings...**(或按 cmd ⌘ + ,)。然后转到 **Locations**,通过在 **Command Line Tools** 下拉菜单中选择最新版本来安装工具。 Step 3: ### 在 Xcode 中安装 iOS 模拟器 要安装 iOS 模拟器,请打开 **Xcode > Settings... > Components**,在 **Platform Support > iOS ...** 下点击 **Get**。 Step 4: ### 安装 Watchman [Watchman](https://facebook.github.io/watchman/docs/install#macos) 是一个监视文件系统变化的工具。安装它将提高性能。你可以通过以下命令安装它: ```sh $ brew update $ brew install watchman ``` # Create a development build for a physical Android device with EAS ## 使用开发构建设置 Android 设备 Step 1: ### 安装 EAS CLI 要构建您的应用程序,您需要安装 EAS CLI。您可以通过在终端中运行以下命令来完成此操作: ```sh $ npm install -g eas-cli ``` Step 2: ### 创建 Expo 账户并登录 要构建您的应用程序,您需要创建一个 Expo 账户并登录到 EAS CLI。 1. [注册](https://expo.dev/signup) Expo 账户。 2. 在终端中运行以下命令以登录到 EAS CLI: ```sh $ eas login ``` Step 3: ### 配置您的项目 运行以下命令以在您的项目中创建 EAS 配置: ```sh $ eas build:configure ``` Step 4: ### 创建构建 运行以下命令以创建开发构建: ```sh $ eas build --platform android --profile development ``` Step 5: ### 在您的设备上安装开发构建 构建完成后,扫描终端中的二维码或在您的设备上打开链接。点击 **安装** 以下载构建到您的设备上,然后点击 **打开** 进行安装。 # Create a development build for a physical Android device locally ## 设置一个带开发构建的 Android 设备 ## 在 Android 设备上运行你的应用 Step 1: ### 安装 expo-dev-client 在你的项目根目录下运行以下命令: ```sh $ npx expo install expo-dev-client ``` Step 2: ### 启用 USB 调试 默认情况下,大多数 Android 设备只能从 Google Play 下载并运行应用。你需要在设备上启用 USB 调试,以便在开发期间安装你的应用。 要启用设备上的 USB 调试,你首先需要通过访问 **设置** > **关于手机** > **软件信息**,然后点击底部的 `构建编号` 行七次来启用“开发者选项”菜单。然后,你可以返回 **设置** > **开发者选项** 启用“USB 调试”。 Step 3: ### 通过 USB 连接你的设备 通过 USB 将你的 Android 设备连接到计算机。 通过在终端中运行 `adb devices` 检查你的设备是否正确连接到 ADB(Android 调试桥)。你应该看到你的设备列在其中,旁边会有 `device` 字样。例如: ```sh $ adb devices 已连接设备列表 8AHX0T32K device ``` Step 4: ### 运行你的应用 从终端运行以下命令: ```sh $ npx expo run:android ``` > 此命令在构建应用后运行开发服务器。你可以在下一页跳过运行 `npx expo start`。 # Run on a physical Android device with Expo Go ## 设置 Android 设备与 Expo Go 扫描二维码从 Google Play 商店下载应用,或访问 [Google Play 商店](https://play.google.com/store/apps/details?id=host.exp.exponent&referrer=docs) 上的 Expo Go 页面。
# Create a development build for Android Emulator with EAS ## 设置带开发版本的 Android 模拟器 ## 创建开发版本 Step 1: ### 安装 EAS CLI 要构建您的应用程序,您需要安装 EAS CLI。您可以通过在终端中运行以下命令来完成此操作: ```sh $ npm install -g eas-cli ``` Step 2: ### 创建 Expo 账户并登录 要构建您的应用程序,您需要创建一个 Expo 账户并登录到 EAS CLI。 1. [注册](https://expo.dev/signup) 一个 Expo 账户。 2. 在终端中运行以下命令以登录到 EAS CLI: ```sh $ eas login ``` Step 3: ### 配置您的项目 运行以下命令在项目中创建 EAS 配置: ```sh $ eas build:configure ``` Step 4: ### 创建构建 运行以下命令以创建开发版本: ```sh $ eas build --platform android --profile development ``` Step 5: ### 在模拟器上安装开发版本 构建完成后,CLI 会提示您自动下载并在 Android 模拟器上安装它。当提示时,按 Y 以直接在模拟器上安装。 如果您错过了此提示,您可以从终端提供的链接下载构建,并将其拖放到 Android 模拟器上进行安装。 # Create a development build for Android Emulator locally ## 设置一个带有开发构建的安卓模拟器 ## 在安卓模拟器上运行您的应用程序 Step 1: ### 安装 expo-dev-client 在您的项目根目录中运行以下命令: ```sh $ npx expo install expo-dev-client ``` Step 2: 从终端运行以下命令: ```sh $ npx expo run:android ``` > 该命令在构建您的应用后运行开发服务器。您可以跳过下一页的 `npx expo start`。 # Run on Android Emulator with Expo Go ## 使用 Expo Go 设置 Android 模拟器 ## 安装 Expo Go 当您在 [开始开发](/get-started/start-developing) 页面上使用 `npx expo start` 启动开发服务器时,按 a 打开 Android 模拟器。Expo CLI 会自动安装 Expo Go。 # Create a development build for a physical iOS device with EAS ## 设置带开发构建的 iOS 设备 Step 1: ### 注册 Apple 开发者计划 要在您的 iOS 设备上安装开发构建,您需要一个有效的 Apple 开发者计划订阅。 在此注册 [Apple 开发者计划](https://developer.apple.com/programs/)。 Step 2: ### 安装 EAS CLI 要构建您的应用,您需要安装 EAS CLI。 您可以通过在终端中运行以下命令来完成此操作: ```sh $ npm install -g eas-cli ``` Step 3: ### 创建 Expo 账户并登录 接下来,您需要创建一个 Expo 账户并登录到 EAS CLI。 1. [注册](https://expo.dev/signup)一个 Expo 账户。 2. 在终端中运行以下命令以登录 EAS CLI: ```sh $ eas login ``` Step 4: ### 配置您的项目 运行以下命令在您的项目中创建 EAS 配置: ```sh $ eas build:configure ``` Step 5: ### 创建临时配置文件 要在您的 iOS 设备上安装开发构建,您需要创建一个临时配置文件。通过在终端中运行以下命令来创建一个: ```sh $ eas device:create ``` Step 6: ### 创建开发构建 运行以下命令以创建开发构建: ```sh $ eas build --platform ios --profile development ``` Step 7: ### 在设备上安装开发构建 构建完成后,扫描终端中的二维码,当它在相机应用中出现时,点击 **使用 iTunes 打开**。 或者,在您的设备上打开终端显示的链接。 确认安装后,应用将出现在您设备的应用库中。 Step 8: ### 打开开发者模式 1. 打开 **设置** > **隐私与安全性**,向下滚动到 **开发者模式** 列表项并进入。 2. 点击开关以启用 **开发者模式**。 完成后,设置会显示警报,提醒您开发者模式会降低设备的安全性。 要继续启用 **开发者模式**,请点击警报中的 **重启** 按钮。 3. 设备重启并解锁后,会显示一个确认您想启用开发者模式的警报。 点击 **开启**,并在提示时输入您的设备密码。 > 或者,如果您在 Mac 上安装了 Xcode,您可以使用它来 [启用 iOS 开发者模式](/guides/ios-developer-mode/#connect-an-ios-device-with-a-mac)。 # Create a development build for a physical iOS device locally ## 设置 iOS 设备以进行开发构建 ## 设置 Xcode 和 Watchman ## 配置您的项目 Step 1: ### 安装 expo-dev-client 在您项目的根目录中运行以下命令: ```sh $ npx expo install expo-dev-client ``` Step 2: ### 通过 USB 连接您的设备并启用开发者模式 1. 使用 USB 数据线将您的 iOS 设备连接到您的 Mac。解锁设备并在提示时点击 **信任**。 2. 打开 Xcode。在菜单栏中选择 **窗口** > **设备与模拟器**。您将在 Xcode 中看到一个警告,提示您启用开发者模式。 3. 在您的 iOS 设备上,打开 **设置** > **隐私与安全性**,向下滚动到 **开发者模式** 列表项并导航进入。 4. 点击开关以启用 **开发者模式**。完成后,设置将显示一个警告,提醒您开发者模式会降低设备的安全性。要继续启用 **开发者模式**,请点击警告的 **重新启动** 按钮。 5. 设备重启后,解锁设备时,将显示一个确认您要启用开发者模式的警报。点击 **开启**,并在提示时输入您的设备密码。 Step 3: ### 在您的设备上运行项目 1. 在根目录中的 **app.json** 文件中添加 `ios.bundleIdentifier`,并设置为唯一值,以便 Xcode 为应用签名步骤生成配置文件。 2. 在您项目的根目录中运行以下命令,并从列表中选择已插入的设备: ```sh $ npx expo run:ios --device ``` > 此命令在构建应用后运行开发服务器。您可以跳过在下一页运行 `npx expo start`。 # Run on a physical iOS device with Expo Go ## 使用 Expo Go 设置 iOS 设备 扫描二维码从 App Store 下载应用,或访问 [App Store](https://itunes.apple.com/app/apple-store/id982107779) 上的 Expo Go 页面。
# Create a development build for iOS Simulator with EAS ## 设置带有开发构建的 iOS 模拟器 ## 设置 Xcode ## 创建开发构建 Step 1: ### 安装 EAS CLI 要构建您的应用,您需要安装 EAS CLI。您可以通过在终端中运行以下命令来完成: ```sh $ npm install -g eas-cli ``` Step 2: ### 创建 Expo 账户并登录 接下来,您需要创建一个 Expo 账户并登录到 EAS CLI。 1. [注册](https://expo.dev/signup) 一个 Expo 账户。 2. 在终端中运行以下命令以登录到 EAS CLI: ```sh $ eas login ``` Step 3: ### 配置您的项目 运行以下命令在您的项目中创建 EAS 配置: ```sh $ eas build:configure ``` Step 4: ### 调整您的构建配置文件 要创建一个与模拟器兼容的开发构建,您需要在 **eas.json** 中更新您的构建配置文件,设置 `ios.simulator` 属性为 `true`: ```json eas.json { "build": { "development": { "developmentClient": true, "distribution": "internal", "ios": { "simulator": true } } } } ``` Step 6: ### 创建开发构建 运行以下命令以创建开发构建: ```sh $ eas build --platform ios --profile development ``` Step 7: ### 在您的模拟器上安装开发构建 构建完成后,CLI 将提示您自动下载并在 iOS 模拟器上安装它。当提示时,按 Y 直接在模拟器上安装。 如果您错过了此提示,您可以从终端提供的链接下载构建,并将其拖放到 iOS 模拟器上进行安装。 # Create a development build for iOS Simulator locally ## 设置一个带有开发构建的 iOS 模拟器 ## 设置 Xcode 和 Watchman ## 在 iOS 模拟器上运行你的应用 Step 1: ### 安装 expo-dev-client 在你项目的根目录下运行以下命令: ```sh $ npx expo install expo-dev-client ``` Step 2: 从你的终端运行以下命令: ```sh $ npx expo run:ios ``` > 此命令在构建你的应用后运行开发服务器。你可以跳过在下一页运行 `npx expo start`。 # Run on iOS Simulator with Expo Go ## 设置 iOS 模拟器与 Expo Go ## 设置 Xcode ## 安装 Expo Go 当你在 [开始开发](/get-started/start-developing) 页面使用 `npx expo start` 启动开发服务器时,按 i 打开 iOS 模拟器。Expo CLI 将自动安装 Expo Go。 ## 下一步 您有一个项目和一个开发环境。现在是时候开始开发了。 ## 开始开发 对 Expo 项目进行首次修改,即可在设备上实时查看效果。 Step 1: ## 启动开发服务器 要启动开发服务器,请运行以下命令: ```sh $ npx expo start ``` Step 2: ## 在设备上打开应用 运行上述命令后,您将在终端中看到一个二维码。扫描此二维码以在设备上打开应用。 如果您使用的是 Android 模拟器或 iOS 模拟器,可以分别按 ai 来打开应用。 Note: 遇到问题? --- 请确保您的计算机和设备在同一 Wi-Fi 网络上。 如果仍然无法正常工作,可能是由于路由器配置问题——这在公共网络中很常见。您可以通过在启动开发服务器时选择 **Tunnel** 连接类型,然后再次扫描二维码来解决此问题。 ```sh $ npx expo start --tunnel ``` > 使用 **Tunnel** 连接类型会使应用的重新加载速度明显慢于 **LAN** 或 **Local**,因此最好在可能的情况下避免使用 Tunnel。如果需要通过其他设备访问您的计算机,您可能希望安装并使用模拟器来加快开发速度。 --- Step 3: ## 进行首次更改 打开 **app/(tabs)/index.tsx** 文件并进行更改。 ```diff diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 45cfa0e..4d1b384 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -17,7 +17,7 @@ export default function HomeScreen() { } > - Welcome! + Hello World! ``` Note: 更改未在设备上显示? --- Expo Go 默认配置为在文件更改时自动重新加载应用,但我们还是要确保检查启用它的步骤,以防某些情况未能正常工作。 - 确保您在 Expo CLI 中启用了 [开发模式](/workflow/development-mode#development-mode)。 - 关闭 Expo 应用并重新打开它。 - 一旦应用再次打开,摇动设备以显示开发者菜单。如果您使用的是模拟器,请按 Ctrl + M(Android)或 Cmd ⌘ + D(iOS)。 - 如果您看到 **启用快速刷新**,请按它。如果您看到 **禁用快速刷新**,请关闭开发者菜单。现在尝试进行另一个更改。 --- --- ## 文件结构 下面,您可以熟悉默认项目的文件结构: ## 功能 默认项目模板具有以下功能: ## 下一步 开发、审查和提交您的项目。 以下是继续构建您的应用的下一步操作: ### 重置您的项目 您可以移除样板代码,并以一个新项目重新开始。运行以下命令以重置您的项目: ```sh $ npm run reset-project ``` 此命令会将现有的 **app** 文件夹中的文件移动到 **app-example**,然后创建一个新的 **app** 目录,并生成一个新的 **index.tsx** 文件。 ### 开发、审核和部署 通过阅读“开发”部分的文档,学习如何进行开发。你将学会如何创建 [UI 元素](/develop/user-interface/splash-screen-and-app-icon/) 、添加 [单元测试](/develop/unit-testing/) 、集成 [原生模块](/config-plugins/introduction/) ,以及更多内容。 开发完应用后,您可以与团队成员分享以进行[评审](/review/overview) 。 最后,您可以[构建](/deploy/build-project/)并[提交](/deploy/submit-to-app-stores/)您的项目到应用商店。 ### 分步指南 如果您需要从头到尾使用 Expo 构建应用的分步指导,请查看[教程](/tutorial/introduction/) 。 # 开发 ## 开发工具 概述 Expo 工具和网站,帮助您在项目构建过程中各个方面。 当你使用 Expo 创建新项目时,了解以下重要工具和网站可以帮助你在应用开发过程中更加顺利。本页面将为你概述一系列推荐工具。 ## Expo CLI Expo CLI 是一个开发工具,在你创建新项目时会随着 `expo` 包自动安装。你可以通过使用 `npx`(一个 Node.js 包运行器)来使用它。 它旨在帮助你在应用开发阶段更快地推进。例如,你与 Expo CLI 的第一次交互通常是通过运行命令 `npx expo start` 来启动开发服务器。 以下是你在开发应用时会与 Expo CLI 一起使用的一些常用命令列表: | 命令 | 描述 | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `npx expo start` | 启动开发服务器(无论你使用的是开发构建还是 Expo Go)。 | | `npx expo prebuild` | 使用 [Prebuild](/workflow/prebuild/) 生成原生 Android 和 iOS 目录。 | | `npx expo run:android` | 在本地编译原生 Android 应用。 | | `npx expo run:ios` | 在本地编译原生 iOS 应用。 | | `npx expo install package-name` | 用于安装新库,或通过在此命令中添加 `--fix` 选项来验证并更新项目中的特定库。 | | `npx expo lint` | [设置并配置](/guides/using-eslint/) ESLint。如果 ESLint 已经配置好,此命令将[对你的项目文件进行 lint 检查](/guides/using-eslint/#usage) 。 | 简而言之,Expo CLI 允许你开发、编译、启动你的应用等。更多可用选项和可执行操作请参见 [Expo CLI 参考文档](/more/expo-cli/) 。 ## EAS CLI EAS CLI 用于登录你的 Expo 账号,并通过不同的 EAS 服务(如 Build、Update 或 Submit)编译你的应用。你还可以使用此工具来: - 将你的应用发布到应用商店 - 创建你的应用的开发、预览或生产版本 - 创建 over-the-air(OTA)更新 - 管理你的应用凭证 - 为 iOS 设备创建临时配置文件 要使用 EAS CLI,您需要在本地机器上全局安装它,运行以下命令: ```sh $ npm install -g eas-cli ``` 您可以在终端窗口中使用 `eas --help` 了解更多可用命令。完整参考请参见 [`eas-cli` npm 页面](https://www.npmjs.com/package/eas-cli) 。 ## Expo Doctor Expo Doctor 是一个用于诊断 Expo 项目问题的命令行工具。要使用它,请在项目的根目录下运行以下命令: ```sh $ npx expo-doctor ``` 此命令会检查并分析你的项目代码库中常见的问题,包括 [应用配置](/workflow/configuration/) 和 **package.json** 文件、依赖兼容性、配置文件以及项目的整体健康状况。检查完成后,Expo Doctor 会输出结果。 如果 Expo Doctor 发现问题,它会提供问题的描述,并给出修复建议或寻求帮助的途径。 默认情况下,Expo Doctor 会根据 [React Native 目录](https://reactnative.directory/)验证你项目的包,并在存在原生目录时检查 app 配置属性是否正确同步。你可以在项目的 **package.json** 文件中配置这些检查。详细信息请参阅 [`reactNativeDirectoryCheck`](/versions/latest/config/package-json/#reactnativedirectorycheck) 和 [`appConfigFieldsNotSyncedCheck`](/versions/latest/config/package-json/#appconfigfieldsnotsynced)。 你也可以使用 `npx expo-doctor --help` 来显示使用信息。 ## Orbit Orbit 是一款适用于 macOS 和 Windows 的应用程序,能够: - 在实体设备和模拟器上安装并启动来自 EAS 的构建。 - 在 Android 模拟器或 iOS 模拟器上安装并启动来自 EAS 的更新。 - 在 Android 模拟器或 iOS 模拟器上启动 snack 项目。 - 使用本地文件安装和启动应用。Orbit 支持任何 Android **.apk**、iOS Simulator 兼容的 **.app**,或临时签名的应用。 - 在你的 EAS 仪表盘中查看已固定项目列表。 ### 安装 For macOS: 你可以通过 Homebrew 在 macOS 上下载 Orbit,或直接从 [GitHub releases](https://github.com/expo/orbit/releases) 获取。 ```sh $ brew install expo-orbit ``` 如果你希望 Orbit 在登录时自动启动,请点击菜单栏中的 Orbit 图标,然后进入 **设置** ,选择 **登录时启动** 选项。 For Windows: > **important** Windows 版 Orbit 目前为预览版,仅兼容 x64 和 x86 机器。未来将会支持其他架构。 你可以直接从 [GitHub releases](https://github.com/expo/orbit/releases) 下载 Windows 版 Orbit。 > **info** Orbit 在 macOS 和 Windows 上都依赖于 Android SDK,并且在 macOS 上仅用于设备管理的 `xcrun`,这需要同时设置 [Android Studio](/workflow/android-studio-emulator/) 和 [Xcode](/workflow/ios-simulator/)。 ## Expo Tools for VS Code Expo Tools 是一个 VS Code 扩展,可以提升你在处理应用配置文件时的开发体验。它为应用配置、EAS 配置、商店配置和 Expo Module 配置等文件提供自动补全和智能感知等功能。 你还可以使用 VS Code 内置的调试器来调试你的应用程序,设置断点、检查变量、通过调试控制台执行代码等。关于如何使用此扩展进行调试,请参阅 [使用 VS Code 进行调试](/debugging/tools/#debugging-with-vs-code) 。 ## 使用 Snack 和 Expo Go 测试原型 ### Snack Snack 是一个浏览器内的开发环境,工作方式类似于 Expo Go。它是分享代码片段和在不下载任何工具到电脑上的情况下尝试 React Native 的绝佳方式。 要使用它,请访问 [snack.expo.dev](https://snack.expo.dev/),编辑 **App.js** 中的 `` 组件,在右侧面板选择一个平台(Android、iOS 或 web),即可实时查看更改效果。 ### Expo Go [Expo Go](https://expo.dev/go) 是一个免费的开源沙盒,用于学习和实验 React Native。它支持 Android 和 iOS。 有关如何使用它的更多信息: - 点击[此链接](/get-started/set-up-your-environment/?mode=expo-go)前往设置您的环境指南 - 在**您想在哪里进行开发?** 下选择一个平台 - 在**您想如何进行开发?** 下选择 Expo Go - 按照该指南中描述的说明进行操作 > **注意:** 不建议用于构建和分发生产环境的应用到应用商店。请改用[开发构建](/get-started/set-up-your-environment/?mode=development-build) 。 Note: What if I open a project with an unsupported SDK version? --- 当你在 Expo Go 中运行一个为不受支持的 SDK 版本创建的项目时,你会看到以下错误: ```sh "Project is incompatible with this version of Expo Go" ``` --- Note: How do I upgrade my project from an unsupported SDK version? --- “项目与此版本的 Expo Go 不兼容” 为了解决这个问题,建议将你的项目升级到[受支持的 SDK 版本](/versions/latest/#each-expo-sdk-version-depends-on-a-react-native-version) 。如果你想了解如何操作,请参阅[将项目升级到新的 SDK 版本](#how-do-i-upgrade-my-project-from) 。 --- Note: How do I upgrade my project from an unsupported SDK version? --- 请参阅[升级 Expo SDK 指南](/workflow/upgrading-expo-sdk-walkthrough) ,获取升级到特定 SDK 版本的操作说明。 --- ## React Native 目录 当你使用开发构建来创建项目时,任何兼容 React Native 的库都可以在 Expo 项目中使用。 [reactnative.directory](https://reactnative.directory/) 是一个可搜索的 React Native 库数据库。如果你需要的库未包含在 Expo SDK 中,可以使用该目录为你的项目查找兼容的库。 ## Expo 与 React Native 应用中的导航 了解在 Expo 和 React Native 项目中集成导航的推荐方法。 核心 React Native 库不包含内置的导航解决方案,因此你可以选择最适合你需求的导航库。对于 Expo 和 React Native 应用,通常是在 [React Navigation](https://reactnavigation.org/) 和 [Expo Router](/router/introduction/) 之间作出选择。 ## 为什么 React Native 应用需要导航库 React Native 核心包含基础 UI 组件、触控处理、设备 API 和网络,但不包括存储、摄像头、地图、大多数设备传感器等,以及**导航** !这些功能旨在由社区库来覆盖。 ## React Navigation React Navigation 是一个基于组件的导航库,在 React Native 生态系统中广泛使用。它让你完全用代码组合栈导航、标签导航和抽屉导航,从而实现复杂的流程、自定义过渡和应用特定的用户体验模式。 该库提供基于平台的外观与流畅的动画与手势,统一的移动端和网页路由、自动深度链接、带静态配置的类型路由,并且高度可定制。 ## Expo Router(推荐用于 Expo 项目) Expo Router 是一个基于文件的路由库,适用于 Expo 和 React Native 项目,且构建在 React Navigation 之上。通过遵循 **app** 目录约定,它将文件转换为路由,并与 Expo 集成,实现 [Expo CLI](/more/expo-cli/) 和打包,无需额外设置。该库还新增了诸如类型化路由、动态路由、开发环境下的懒加载、网页端静态渲染,以及自动深度链接等功能。 使用 `npx create-expo-app@latest` 创建的新 Expo 项目默认包含 Expo Router,因此你可以快速发布跨平台导航,同时在需要时仍然可以访问 React Navigation 的 API。 ## 在 Expo 和 React Native 应用中的身份验证 了解如何在您的 Expo 项目中设置身份验证。 身份验证是现代应用中90%到95%的一个关键部分。本指南解释了常见的方法、模式和解决方案,以帮助您在 Expo 应用中实现身份验证。 > **info** **TL;DR**:身份验证很难。如果您想跳过复杂性,请跳到 [身份验证解决方案](/#auth-solutions) 部分,获取即成解决方案。否则,请继续阅读。 实现身份验证不仅仅是编写客户端代码。您需要管理服务器请求、密码流程、第三方提供商(如 Google 或 Apple)、电子邮件处理和 OAuth 标准。这个过程会迅速变得复杂。 身份验证方法有几种类型。一些方法简单有效,而另一些方法提供更好的用户体验,但需要更多的工作。让我们看看最常见的方法以及如何实现它们。 ## 导航身份验证流程 首先,让我们从基础知识开始:任何身份验证系统都需要将 **公开屏幕**(如登录或注册)与 **受保护屏幕**(如主页或个人资料)分开。在导航层面,这归结为一个简单的检查:用户是否已认证? 开始时,您可以使用硬编码的布尔值模拟此功能,例如 `isAuthenticated = true`,并围绕此构建导航逻辑。一旦一切正常工作,您可以插入真正的身份验证流程。 Note: 使用 Expo Router --- Expo Router v5 引入了 [受保护路由](/router/advanced/protected),它阻止用户在未认证的情况下访问某些屏幕。此功能非常适合客户端导航,并简化您的设置。 如果您使用的是旧版本的 Expo Router,您可以使用 [重定向](/router/advanced/authentication-rewrites)。重定向提供相同的结果,但需要更多的手动配置。为了向后兼容,它们在 Expo Router v5 中仍然受到支持。 Video Tutorial: [Expo Router 受保护路由](https://www.youtube.com/watch?v=zHZjJDTTHJg) --- Note: 使用 React Navigation --- 如果您使用的是 React Navigation,他们提供了一个有用的 [身份验证流程指南](https://reactnavigation.org/docs/auth-flow/),该指南解释了如何构建您的导航逻辑。它包含基于用户身份验证状态的 [静态](https://reactnavigation.org/docs/auth-flow/?config=static#how-it-will-work) 和 [动态](https://reactnavigation.org/docs/auth-flow/?config=dynamic#how-it-will-work) 方法的示例。 --- 无论是 Expo Router 还是 React Navigation,都为您提供灵活的工具,以基于用户是否已登录实现受保护的导航。 ## 电子邮件和密码 电子邮件和密码是为应用添加身份验证时的流行选择。 为了使此流程用户友好,您还需要实现忘记密码和重置密码的功能,以便失去访问权限的用户能够恢复账户。 如果您想要更快的解决方案,几项服务提供内置电子邮件和密码身份验证,包括 [Clerk](/#clerk)、[Supabase](/#supabase)、[Cognito](/#cognito)、[Firebase](/#firebase-auth) 和 [Better Auth](/#better-auth)。其中大多数服务提供慷慨的免费层,但如果您的应用快速增长,评估定价是个好主意。 这些服务的最大优势是易于集成。它们通常提供清晰的文档、入门套件和预构建组件,节省您的时间。 Note: 安全检查清单(OWASP)和应用商店审核陷阱 --- 如果您自己构建这个流程,请务必查看 OWASP 的 [身份验证备忘单](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#authentication-cheat-sheet)。它列出了密码长度、加密、恢复、可靠存储等方面的最佳实践。 > **info** 添加电子邮件和密码身份验证通常足以通过 App Store 和 Play Store 审核。您可以先提交包含此方法的应用。如果您包括“使用 Google 登录”,Apple 可能会拒绝您的应用,除非您还支持“使用 Apple 登录”。在 Google Play 上,反向适用同样的规则。 --- ## 无密码登录 无密码登录消除了用户创建或记住密码的需要。相反,他们在注册时提供电子邮件地址或手机号码。您的应用随后会向他们的收件箱或设备发送一个 [魔法链接](https://auth0.com/docs/authenticate/passwordless/authentication-methods/email-magic-link#classic-login-flow-with-magic-links) 或 [一次性密码(OTP)](https://en.wikipedia.org/wiki/One-time_password)。这为大多数用户提供了更流畅的体验,并减少了入门时的摩擦。 Note: 魔法链接 --- 使用魔法链接,用户收到一封包含将他们重定向回您应用的链接的电子邮件。如果一切正常,会议将被验证和建立。 这里的一个关键细节是 [深层链接](/linking/into-your-app)。由于用户需要离开应用检查电子邮件,因此链接必须打开您的应用并将他们引导到正确的屏幕。如果深层链接失败,则无法验证会议,登录流程将中断。 如果您使用的是 Expo Router,则深层链接会自动处理(在大多数情况下)。您通常不需要配置任何额外的内容来使魔法链接正常工作,这使得此方法更易于采用。有关更多信息,请参阅 [链接到您的应用](/linking/into-your-app)。 [React Navigation](https://reactnavigation.org/) 也支持深层链接,但您需要手动配置。有关更多详细信息,请查看其 [深层链接指南](https://reactnavigation.org/docs/deep-linking/)。 --- Note: 一次性密码(OTP) --- 魔法链接的另一种替代方案是通过电子邮件或短信发送一次性密码。用户无需点击链接,而是复制代码并手动返回应用输入。此操作必须在特定的时间窗口内完成,以便代码不会过期。 这里不涉及深层链接。用户控制着流程,必须自己返回应用。 幸运的是,较新的 Android 和 iOS 版本会自动检测到传入消息中的密码。这使得在键盘上方提供自动填充建议,允许用户通过一次点击输入代码。当这一过程顺利时,体验是无缝的。 --- > **info** 魔法链接和一次性密码都是 Google Play Store 和 Apple App Store 审核的有效身份验证方法。您可以仅使用这些方法之一提交应用并获得批准,甚至在添加社交或 OAuth 登录选项之前。 ## OAuth 2.0 要让用户使用 Google、Apple、GitHub 等服务的现有账户登录,您可以使用 OAuth 2.0。 [OAuth 2.0](https://oauth.net/2) 是一种广泛使用的安全协议,允许您的应用访问来自其他服务的用户信息,而无需要处理密码。它让用户可以通过一次点击登录,节省时间,建立信任,并免去管理密码的需要。 > **info** OAuth 流程可能很复杂。如果您正在寻找简单的集成,大多数提供商都提供 SDK 和服务,帮您处理所有事情。您可以在 [身份验证解决方案](#auth-solutions) 部分中了解更多信息。 如果您希望完全控制或想了解 OAuth 的内部工作原理,以下部分将展示如何使用 Expo 自己实现完整的 OAuth 流程。 ### OAuth 的工作原理 OAuth 通过引入一个作为安全中介的授权服务器来工作。用户不将密码提供给您的应用,而是通过该服务器登录并批准访问特定数据(例如名称或电子邮件)。然后,服务器发放一个临时代码,您的应用可以用它来交换安全访问令牌。 一旦您了解了这一模式,您就可以将其应用于任何提供商。Google、Apple 或 GitHub 的设置将遵循相同的一般步骤。 ### 使用 Expo API 路由的自定义 OAuth 前面的图表显示了 OAuth 流程的高级概述。然而,客户端获得用户的授权授予的首选方法是使用授权服务器作为中介,而这正是您可以使用 Expo API 路由构建的。 以下图表详细说明了这一流程: Expo 让您可以在应用中直接实现整个 OAuth 流程,使用: 一些提供商提供原生 API,以直接在应用内处理登录流程。Google 在 Android 上提供原生的使用 Google 登录体验。如果您正在寻找原生实现,请参阅 [Google 身份验证指南](/guides/google-authentication)。Apple 提供使用原生底部面板和 iOS 的面部识别的 Apple 登录。请查看 [`expo-apple-authentication`](/versions/latest/sdk/apple-authentication) 参考。 以下设置使您可以全面控制 Android、iOS 和 Web 的登录体验。 Note: 什么是 Expo API 路由? --- [Expo Router API 路由](/router/reference/api-routes) 允许您在 Expo 应用中直接编写服务器端逻辑。您可以定义处理请求的函数,就像 Express 或 Next.js 后端一样,无需外部服务器。 这使得可以轻松安全地处理身份验证流程中的敏感部分,例如 [授权代码交换](https://www.oauth.com/oauth2-servers/pkce/authorization-code-exchange),直接在您的应用中进行。由于这些路由在服务器上运行,您可以安全地管理秘密、发行 JWT 和验证令牌。 > **info** 您本质上是在为您自己的应用构建一个轻量级的自定义身份验证服务器,全部使用您的 Expo 项目。 --- Note: 什么是 Expo AuthSession? --- [Expo AuthSession](/versions/latest/sdk/auth-session) 是一个客户端包,帮助您打开网页浏览器或原生模态以开始 OAuth 登录流程。它处理重定向、解析授权响应,并将用户带回您的应用。 这是启动流程的工具,并在用户授权访问后与您的 API 路由进行交互。有关更多信息,请参阅 [使用 OAuth 或 OpenID 提供者的身份验证](/guides/authentication/)。 --- 此设置让您可以: - 使用 AuthSession 启动登录流程 - 在您的 API 路由中接收身份验证代码 - 安全地交换代码以获取令牌 - 使用您自己的逻辑生成自定义 JWT - 将该令牌返回给客户端 - 使用 Cookie(Web)或 JWT(原生)存储会话 - 使用 EAS Hosting 立即部署(免费启动) 以下教程涵盖如何在 Android、iOS 和 Web 上实现 OAuth,包括如何创建和验证自定义 JWT、管理会话和保护 API 路由。如果您对这个流程不熟悉,建议从 Google 教程开始。 Video Tutorial: [使用 Expo OAuth 实现 Google 登录](https://www.youtube.com/watch?v=V2YdhR1hVNw) Video Tutorial: [使用 Expo 实现 Apple 登录](https://www.youtube.com/watch?v=tqxTijhYhp8) Note: 在 OAuth 后管理会话 --- 安全处理 OAuth 流程仅仅是开始。一旦用户通过身份验证,您还需要考虑如何存储、恢复和验证他们的会话。 这包括: - 在客户端安全地存储会话 - 当应用重新启动时恢复会话 - 保护您的 API 路由,以便只有经过身份验证的用户可以访问 传统上,[Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies#what_cookies_are_used_for) 用于在 Web 上存储会话,而 [JSON Web 令牌(JWT)](https://en.wikipedia.org/wiki/JSON_Web_Token) 在原生应用中很常见。 以上教程准确地展示了如何处理这一点。在从 Google 或 Apple 等提供商接收到 ID 令牌后,您使用 Expo API 路由在服务器上生成自定义 JWT。 这让您全面控制会话,包括: - 使用各个提供商一致字段结构化有效负载 - 自定义过期时间 - 使用秘密密钥签署令牌,以便您的服务器可以稍后验证 一旦令牌创建: - 对于 Android 和 iOS 应用,您可以使用 [`expo-secure-store`](/versions/latest/sdk/securestore/) 安全地存储它 - 对于 Web 应用,您可以将其设置为安全 Cookie,以维持会话 在每次请求中,令牌会发送回您的服务器,在那里您验证签名并检查过期。如果一切正常,您可以继续处理请求。 这种会话模型使您的后端保持无状态、可扩展且安全,在各个平台上始终如一地运行。 所有这些都在上述视频教程中涵盖,包括: - 生成和验证自定义 JWT - 使用 Secure Store 和 Cookie 处理会话存储 - 使用身份验证逻辑保护 API 路由 --- ## 身份验证解决方案 如果您不想从头开始构建完整的身份验证系统,有几项服务提供内置解决方案,并对 Expo 的支持一流。以下是一些最受欢迎的选项: Note: Better Auth --- [BetterAuth](https://www.better-auth.com/docs/integrations/expo) 是一个现代的开源身份验证提供商,专为开发人员构建。它与 Expo 的集成十分顺畅,他们提供一份指南,展示如何与 [Expo API 路由](https://www.better-auth.com/docs/integrations/expo) 一起使用,以便进行全面控制。它可以很好地与任何提供商合作,并且容易与 EAS Hosting 部署。 --- Note: Clerk --- [Clerk](https://clerk.com/expo-authentication) 是一个功能强大的全功能身份验证服务,具有出色的 Expo 支持。它包括电子邮件/密码、密码、魔法链接、OAuth 提供商,甚至是密码钥匙。它们还提供一个原生 Expo 模块,为您处理许多集成。 --- Note: Supabase --- [Supabase](https://supabase.com/docs/guides/getting-started/tutorials/with-expo-react-native) 提供完整的后端平台,包括一个与任何 OAuth 提供商配合使用的内置身份验证服务。它与 Expo 应用集成良好,并且还支持电子邮件、魔法链接等。 --- Note: Cognito --- [AWS Cognito](https://medium.com/@juliuscecilia33/aws-cognito-and-react-native-bf23ef7fea23) 是亚马逊管理用户池和身份的解决方案。它与其他 AWS 服务无缝连接,并可以通过 AWS Amplify 集成到 Expo 应用中。虽然它需要更多的配置,但它功能强大且可扩展。 --- Note: Firebase Auth --- [Firebase 身份验证](https://rnfirebase.io/auth/usage) 是谷歌的身份验证平台,支持电子邮件、魔法链接和 OAuth 提供商。它通过 [`react-native-firebase`](https://github.com/invertase/react-native-firebase) 与 React Native 兼容,该库与 Expo 开发构建兼容。 --- ## 现代方法 一旦您的身份验证系统运行正常,您可以通过添加可选但强大的增强功能(如生物识别和密码钥匙)来改善用户体验。这些功能为您的登录流程增添了便利、信任和速度。 Note: 生物识别 --- 生物识别技术,如 Face ID 和 Touch ID,可用于解锁应用或在有效会话建立后确认身份。这些不是独立的身份验证方法,而是作为一个本地网关,使重新身份验证更快、更安全。 React Native 通过像 [`expo-local-authentication`](/versions/latest/sdk/local-authentication) 或 [`react-native-biometrics`](https://github.com/SelfLender/react-native-biometrics) 等库访问生物识别 API。 --- Note: 密码钥匙 --- [密码钥匙](https://safety.google/authentication/passkey) 是一种新的无密码登录应用和网站的方式。受苹果、谷歌和微软支持,它们利用平台级加密技术和生物识别来无密码认证用户。 密码钥匙提供了无缝和安全的体验,但它要求用户在注册之前已经通过身份验证。如果您不使用负责处理它们的提供商,则还需要额外配置。 - React Native 密码钥匙支持:[`react-native-passkeys`](https://github.com/peterferguson/react-native-passkeys) - 与 Clerk 的原生密码钥匙支持:[Clerk Passkeys for Expo](https://clerk.com/docs/references/expo/passkeys) --- ## 建议 本指南涵盖了许多内容,从基本的电子邮件和密码流程到完全自定义的 OAuth 实现、会话管理以及现代方法(如生物识别和密码钥匙)。并非所有内容都需要一次性实施。 在许多情况下,从简单的开始是最佳方法。使用像魔法链接或一次性密码这样的电子邮件认证方法发布应用通常就足够了,可以完成 App Store 审核流程,并开始收集真实用户的反馈。 也就是说,如果您正在构建一个预期从第一天就会有高流量的应用,或需要支持跨平台的登录并且摩擦最小,早期投资于更完整的身份验证流程会有很大差别。这可以帮助您从一开始就改善用户入门、信任和保留。 现代解决方案如 OAuth、生物识别和密码钥匙并不是必需的,但一旦核心系统建立,它们可以是很好的补充。 关键是构建适合您当前需求的身份验证,同时保持足够灵活,以便随着您的产品成长。 ## 使用 Jest 的单元测试 了解如何设置和配置 jest-expo 库,以使用 Jest 为项目编写单元测试和快照测试。 [Jest](https://jestjs.io) 是最常用的单元测试和快照测试的 JavaScript 测试框架。在本指南中,你将学习如何在你的项目中设置 Jest、编写单元测试、编写快照测试,以及在使用 Jest 与 React Native 时对测试结构的最佳实践。 你还将使用 [`jest-expo`](https://github.com/expo/expo/tree/main/packages/jest-expo) 库,它是一个 Jest 预设,仿制 Expo SDK 的原生部分并处理你在 Expo 项目中所需的大部分配置。 ## 安装与配置 创建 Expo 项目后,按以下说明在你的项目中安装和配置 `jest-expo`: Step 1: 在你的项目中安装 `jest-expo` 和其他所需的开发依赖。请从项目的根目录运行以下命令: For macOS/Linux: ```sh $ npx expo install jest-expo jest @types/jest --dev ``` For Windows: ```sh $ npx expo install jest-expo jest @types/jest "--" --dev ``` > **注:** 如果你的项目不使用 TypeScript,可以跳过安装 `@types/jest`。 Step 2: 打开 **package.json**,添加一个用于运行测试的脚本,并添加使用 `jest-expo` 基本配置的预设: ```json package.json { "scripts": { }, "jest": { "preset": "jest-expo" } } ``` Step 3: 在 **package.json** 中,添加 `jest-expo` 作为 preset,以便为 Jest 的配置设置一个基础: ```json package.json { "jest": { "preset": "jest-expo" } } ``` Note: 使用 的其他配置 --- 你可以通过在你的 **package.json** 中配置 [`transformIgnorePatterns`](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring) 来对项目使用的 node_modules 进行转译。该属性接受一个正则表达式模式作为其值: For npm/Yarn: ```json package.json "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg)" ] } ``` For pnpm: ```json package.json "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg))" ] } ``` Jest 有大量的配置选项,但上述配置应覆盖大部分需求。不过,你始终可以向此模式列表添加更多项。有关更多细节,请参阅 [Configuring Jest](https://jestjs.io/docs/configuration)。 --- ## 安装 React Native Testing Library [React Native Testing Library (`@testing-library/react-native`)](https://callstack.github.io/react-native-testing-library/) 是一个用于测试 React Native 组件的轻量级解决方案。它提供实用函数,并可与 Jest 一起使用。 要安装,请运行以下命令: For macOS/Linux: ```sh $ npx expo install @testing-library/react-native --dev ``` For Windows: ```sh $ npx expo install @testing-library/react-native "--" --dev ``` > **warning** **已弃用:** `@testing-library/react-native` 取代了已弃用的 `react-test-renderer`,因为 `react-test-renderer` 不支持 React 19 及以上版本。如果你当前在使用它,请从项目中移除该已弃用的库。有关更多信息,请参阅 React 的文档 [React's documentation for more information](https://react.dev/warnings/react-test-renderer)。 ## Unit test 一个单元测试检查代码中最小的单元,通常是一个函数。要编写你的第一个单元测试,请看下面的示例: Step 1: 在你项目的 **app** 目录中,创建一个名为 **index.tsx** 的新文件,并添加以下代码来渲染一个简单组件: ```tsx index.tsx import { PropsWithChildren } from 'react'; import { StyleSheet, Text, View } from 'react-native'; export const CustomText = ({ children }: PropsWithChildren) => {children}; export default function HomeScreen() { return ( Welcome! ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, }); ``` Step 2: 在你的项目根目录下创建一个 **\_\_tests\_\_** 目录。如果该目录在你的项目中已经存在,请使用现有的目录。然后,创建一个名为 **HomeScreen-test.tsx** 的新文件。`jest-expo` 预设会自定义 Jest 配置,此外还会将扩展名为 **\-test.ts|tsx** 的文件识别为测试文件。 在 **HomeScreen-test.tsx** 中添加以下示例代码: ```tsx HomeScreen-test.tsx import { render } from '@testing-library/react-native'; import HomeScreen, { CustomText } from '@/app/index'; describe('', () => { test('Text renders correctly on HomeScreen', () => { const { getByText } = render(); getByText('Welcome!'); }); }); ``` 在上面的示例中,`getByText` 查询帮助你的测试在应用的用户界面中找到相关元素,并对该元素是否存在进行断言。React Native Testing Library 提供了此查询,每个 [query 变体](https://callstack.github.io/react-native-testing-library/docs/api/queries#query-variant) 在返回类型上有所不同。欲了解更多示例和详细 API 信息,请参阅 React Native Testing Library 的 [Queries API reference](https://callstack.github.io/react-native-testing-library/docs/api/queries)。 Step 3: 在终端窗口中运行以下命令以执行测试: ```sh $ npm run test ``` 你会看到一个测试通过。 ## 结构化你的测试 组织你的测试文件对于让它们更易于维护非常重要。一个常见的模式是创建一个 **\_\_tests\_\_** 目录并将所有测试放在其中。 下面给出一个放在 **components** 目录旁边的测试示例结构: ``` __tests__/ │ └── ThemedText-test.tsx components/ ├── ThemedText.tsx └── ThemedView.tsx ``` 或者,你也可以为项目的不同部分创建多个 **\_\_tests\_\_** 子目录。例如,为 **components** 创建一个单独的测试目录,依此类推: ``` components/ │ ├── ThemedText.tsx │ └── __tests__/ │ └── ThemedText-test.tsx utils/ ├── index.tsx └── __tests__/ └── index-test.tsx ``` 一切都关乎偏好,由你来决定如何组织你的项目目录。 ## 快照测试 > **info** **注意:** 对于 UI 测试,我们推荐进行端到端测试,而不是快照单元测试。请参阅 [E2E tests with Maestro](/eas/workflows/examples/e2e-tests/) 指南。 一个 [快照测试](https://jestjs.io/docs/en/snapshot-testing) 用来确保 UI 保持一致,特别是当项目使用全局样式且可能在组件之间共享时。 要为 `` 添加快照测试,请在 **HomeScreen-test.tsx** 的 `describe()` 中加入以下代码片段: ```tsx HomeScreen-test.tsx describe('', () => { test('CustomText renders correctly', () => { const tree = render(Some text).toJSON(); expect(tree).toMatchSnapshot(); }); }); ``` 运行 `npm run test` 命令,你将会在 **\_\_tests\_\_\\\_\_snapshots\_\_** 目录看到一个快照被创建,并且有两个测试通过。 ## Code coverage 报告 Code coverage 报告可以帮助你了解有多少代码被测试到。若要在你的项目中以 HTML 格式查看代码覆盖率报告,在 **package.json** 中,在 `jest` 下,将 `collectCoverage` 设置为 true,并使用 `collectCoverageFrom` 指定在收集覆盖率时要忽略的文件列表。 ```json package.json "jest": { ... "collectCoverage": true, "collectCoverageFrom": [ "**/*.{ts,tsx,js,jsx}", "!**/coverage/**", "!**/node_modules/**", "!**/babel.config.js", "!**/expo-env.d.ts", "!**/.expo/**" ] } ``` 运行 `npm run test`。你将看到在你的项目中创建一个 **coverage** 目录。找到 **lcov-report/index.html** 并在浏览器中打开它以查看覆盖率报告。 > 通常,我们不建议将 **index.html** 文件上传到 git。请在 **.gitignore** 文件中添加 `coverage/**/*`,以防止被追踪。 ## Jest 流程(可选) 您也可以使用不同的流程来运行测试。下面是一些可尝试的示例脚本: ```json package.json "scripts": { "test": "jest --watch --coverage=false --changedSince=origin/main", "testDebug": "jest -o --watch --coverage=false", "testFinal": "jest", "updateSnapshots": "jest -u --coverage=false" } ``` 有关更多信息,请参阅 Jest 文档中的 [CLI Options](https://jestjs.io/docs/en/cli)。 ## 附加信息 # 用户界面 ## 启动画面和应用图标 了解如何为 Expo 项目添加启动画面和应用图标。 启动画面和应用图标是移动应用的基本元素。它们在用户体验和应用品牌塑造中起着重要作用。本指南将介绍如何创建并将它们添加到你的应用中。 Video Tutorial: [Create an App Icon and Splash Screen](https://www.youtube.com/watch?v=3Bsw8a1BJoQ) --- ## 启动画面 启动画面,也称为启动屏幕,是用户打开应用时看到的第一个界面。在应用加载期间,它会一直显示。你还可以通过使用原生的 [SplashScreen API](/versions/latest/sdk/splash-screen) 来控制启动画面消失的时机。 [`expo-splash-screen`](/versions/latest/sdk/splash-screen) 内置了一个 [配置插件](/config-plugins/introduction) ,可以让你配置启动图标和背景颜色等属性。 > **warning** **不要使用 Expo Go 或开发构建来测试你的启动画面** 。Expo Go 会在启动画面可见时渲染你的应用图标,这可能会影响测试。开发构建包含 `expo-dev-client`,它有自己的启动画面,可能会导致冲突。 **请改用 [预览构建](/build/eas-json/#preview-builds) 或 [生产构建](/build/eas-json/#production-builds)** 。 Step 1: ### 创建启动画面图标 要创建启动屏幕图标,你可以使用这个 [Figma 模板](https://www.figma.com/community/file/1466490409418563617) 。它为 Android 和 iOS 提供了最基本的图标和启动图片设计。 **推荐:** - 使用 1024x1024 的图片。 - 使用 **.png** 文件。 - 使用透明背景。 Step 2: ### 将启动图标导出为 .png 格式 创建启动屏幕图标后,将其导出为 **.png** 格式,并保存到 **assets/images** 目录下。默认情况下,Expo 使用 **splash-icon.png** 作为文件名。如果你决定更改启动屏幕文件的名称,请确保在下一步中使用该名称。 > **注意:** **目前仅支持 .png 图片**作为 Expo 项目中的启动屏幕图标。如果你使用其他图片格式,应用的生产构建将会失败。 Step 3: ### 配置启动屏幕图标 打开应用配置文件,在 plugins 下设置以下属性: ```json app.json { "expo": { "plugins": [ [ "expo-splash-screen", { "backgroundColor": "#232323", "image": "./assets/images/splash-icon.png", "dark": { "image": "./assets/images/splash-icon-dark.png", "backgroundColor": "#000000" }, "imageWidth": 200 } ] ] } } ``` 要测试您的新启动画面,请为[内部分发](/tutorial/eas/internal-distribution-builds)或生产环境构建您的应用,参阅 [Android](/tutorial/eas/android-production-build/) 和 [iOS](/tutorial/eas/ios-production-build/) 的指南。 Note: 为 Android 和 iOS 分别配置 属性 --- [`expo-splash-screen`](/versions/latest/sdk/splash-screen) 还支持 `android` 和 `ios` 属性,用于为特定平台配置启动屏幕。请参见以下示例: ```json app.json { "expo": { "plugins": [ [ "expo-splash-screen", { "ios": { "backgroundColor": "#ffffff", "image": "./assets/images/splash-icon.png", "resizeMode": "cover" }, "android": { "backgroundColor": "#0c7cff", "image": "./assets/images/splash-android-icon.png", "imageWidth": 150 } } ] ] } } ``` --- Note: 未使用 prebuild? --- 如果您的应用没有使用 [Expo Prebuild](/workflow/prebuild)(以前称为 _托管工作流_ )来生成原生的 **android** 和 **ios** 目录,那么应用配置中的更改将不会生效。更多信息请参见 [如何手动自定义配置](https://github.com/expo/expo/tree/main/packages/expo-splash-screen#-installation-in-bare-react-native-projects) 。 --- Note: 故障排除:iOS设备上未显示新启动画面 --- 对于 SDK 版本低于 52 的情况,在 iOS 开发构建中,启动屏有时会在不同构建之间保持缓存,这会导致测试新图片变得更加困难。Apple 建议在重新构建前清除 _derived data_ 目录,可以通过运行 Expo CLI 来完成: ```sh $ npx expo run:ios --no-build-cache ``` 请参阅 [Apple 关于测试启动屏幕的指南](https://developer.apple.com/documentation/technotes/tn3118-debugging-your-apps-launch-screen)以获取更多信息。 --- ## 应用图标 应用的图标是用户在其设备主屏幕和应用商店中看到的内容。Android 和 iOS 对此有不同且严格的要求。 Step 1: ### 创建应用图标 要创建应用图标,你可以使用这个 [Figma 模板](https://www.figma.com/community/file/1466490409418563617) 。它为 Android 和 iOS 提供了最基本的图标和启动图片设计。 Step 2: ### 将图标图片导出为 .png 格式 创建好应用图标后,将其导出为 **.png** 格式,并保存在 **assets/images** 目录下。默认情况下,Expo 使用 **icon.png** 作为文件名。如果你决定使用其他文件名,请确保在下一步中也使用该文件名。 Step 3: ### 在应用配置中添加图标 打开应用配置,并将本地路径作为 [`icon`](/versions/latest/config/app/#icon) 属性的值,指向你的新应用图标: ```json app.json { "icon": "./assets/images/icon.png" } ``` Note: Android 与 iOS 的自定义配置技巧 --- #### Android 可以通过使用 [`android.adaptiveIcon`](/versions/latest/config/app/#adaptiveicon) 属性进一步自定义 Android 图标,该属性会覆盖前面提到的两项设置。 Android 自适应图标由两个独立的图层组成——前景图片和背景颜色或图片。这使得操作系统能够将图标遮罩成不同的形状,并支持视觉效果。对于 Android 13 及更高版本,操作系统支持主题应用图标,可根据设备主题使用壁纸和主题来确定颜色。 您提供的设计应遵循 [Android 自适应图标指南](https://developer.android.com/develop/ui/views/launch/icon_design_adaptive) ,用于启动器图标。您还应: - 使用 **.png** 文件。 - 使用 `android.adaptiveIcon.foregroundImage` 属性来指定前景图片的路径。 - 使用 `android.adaptiveIcon.monochromeImage` 属性来指定单色图片的路径。 - 默认的背景颜色为白色;如需指定其他背景颜色,请使用 `android.adaptiveIcon.backgroundColor` 属性。你也可以使用 `android.adaptiveIcon.backgroundImage` 属性来指定背景图片。请确保其尺寸与前景图片相同。 你可能还需要为不支持自适应图标的旧版 Android 设备提供单独的图标。可以通过 `android.icon` 属性实现。该图标应将前景和背景图层合并为一个。 > 请参阅 [Apple 最佳实践](https://developer.apple.com/design/human-interface-guidelines/app-icons/#Best-practices) ,以确保你的图标看起来专业,例如在不同壁纸上测试图标,并避免在产品字标旁添加文字。请提供至少 512x512 像素的图标。 #### iOS 对于 iOS,您的应用图标应遵循 [Apple 人机界面指南](https://developer.apple.com/design/human-interface-guidelines/app-icons/) 。您可以使用 [Icon Composer](https://developer.apple.com/icon-composer/) 应用来创建您的应用图标。该应用会输出一个 **.icon** 目录,您可以将其添加到项目的 **assets** 目录中。然后,您可以在应用配置中提供该目录的路径。暗黑模式的支持已在 Icon Composer 中处理,因此使用此方法时无需提供变体。 > **info** **注意:** 通过 `ios.icon` 提供 Icon Composer 的 **.icon** 目录在 **SDK 54** 及更高版本中受支持。 ```json app.json { "expo": { "ios": { "icon": "./assets/app.icon" } } } ``` 另外,之前提供图片的方式仍然受支持。你应该: - 使用 **.png** 文件。 - 1024x1024 是一个不错的尺寸。如果你是使用 `npx create-expo-app` 创建的 Expo 项目,[EAS Build](/build/setup/) 会为你生成其他尺寸的图标。如果是裸 React Native 项目,则需要你自行生成图标。EAS Build 生成的最大尺寸为 1024x1024。 - 图标必须是完全正方形的。例如,1023x1024 的图标是无效的。 - 请确保图标填满整个正方形,没有圆角或其他透明像素。操作系统会在适当的时候自动为你的图标添加遮罩。 - 可以使用 `ios.icon` 为不同的系统外观(例如深色和有色)指定不同的图标。如果指定了该项,将会覆盖应用配置文件中的顶级 icon 键。请参见下面的示例: ```json app.json { "expo": { "ios": { "icon": { "dark": "./assets/images/ios-dark.png", "light": "./assets/images/ios-light.png", "tinted": "./assets/images/ios-tinted.png" } } } } ``` --- ## 安全区域 了解如何在 Expo 项目中为屏幕组件添加安全区域。 创建安全区域可以确保你的应用屏幕内容被正确地定位。这意味着内容不会被刘海、状态栏、主屏指示器以及其他设备物理硬件或操作系统控制的界面元素覆盖。当内容被覆盖时,会被这些界面元素遮挡。 以下是应用屏幕内容被 Android 状态栏遮挡的示例。在 iOS 上,相同的内容会被圆角、刘海和状态栏遮挡。 ## 使用 `react-native-safe-area-context` 库 [`react-native-safe-area-context`](https://github.com/AppAndFlow/react-native-safe-area-context) 提供了一个灵活的 API,用于处理 Android 和 iOS 设备的安全区域内边距。它还提供了一个 `SafeAreaView` 组件,你可以用它来替代 [``](https://reactnative.dev/docs/view),以便在屏幕组件中自动适配安全区域。 使用该库后,前面示例的结果会发生变化,因为内容会显示在安全区域内,如下所示: ### 安装 如果你是使用 [默认模板](/get-started/create-a-project/) 创建的项目,可以跳过 `react-native-safe-area-context` 的安装。该库作为 Expo Router 库的 peer 依赖被自动安装。否则,请运行以下命令进行安装: ```sh $ npx expo install react-native-safe-area-context ``` ### 用法 你可以直接使用 [`SafeAreaView`](https://appandflow.github.io/react-native-safe-area-context/api/safe-area-view) 来包裹你屏幕组件的内容。它是一个普通的 ``,但会将安全区域的内边距作为额外的 padding 或 margin 应用。 ```tsx app/index.tsx import { Text } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; export default function HomeScreen() { return ( Content is in safe area. ); } ``` Note: 使用了不同的Expo模板,但未安装Expo Router? --- 在你的屏幕组件中使用 `SafeAreaView` 之前,需在根组件文件(如 **App.tsx**)中导入并添加 [`SafeAreaProvider`](https://appandflow.github.io/react-native-safe-area-context/api/safe-area-provider)。 ```tsx App.tsx import { SafeAreaProvider } from 'react-native-safe-area-context'; export default function App() { return ( return ...; ); } ``` --- ## 可选:`useSafeAreaInsets` 钩子 作为 `SafeAreaView` 的替代方案,你可以在屏幕组件中使用 [`useSafeAreaInsets`](https://appandflow.github.io/react-native-safe-area-context/api/use-safe-area-insets) hook。它可以直接访问安全区域的内边距(insets),让你能够根据该 hook 返回的内边距为 `` 的每个边缘添加相应的 padding。 下面的示例使用了 `useSafeAreaInsets` hook。它通过 `insets.top` 为 `` 添加了顶部内边距。 ```tsx app/index.tsx import { Text, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; export default function HomeScreen() { const insets = useSafeAreaInsets(); return ( Content is in safe area. ); } ``` 该 hook 提供的 insets 对象如下: ```ts { top: number, right: number, bottom: number, left: number } ``` ## 附加信息 ### 最小示例 下面是一个最小可用示例,演示如何使用 `useSafeAreaInsets` hook 为视图应用顶部内边距。 #### Using react-native-safe-area-context ```tsx collapseHeight=320 import { Text, View } from 'react-native'; import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'; function HomeScreen() { const insets = useSafeAreaInsets(); return ( Content is in safe area. ); } export default function App() { return ( ); } ``` ### 与 React Navigation 一起使用 默认情况下,React Navigation 支持安全区域,并将 `react-native-safe-area-context` 作为并列依赖。更多信息请参见 [React Navigation 文档](https://reactnavigation.org/docs/handling-safe-area/) 。 ### 与 Web 一起使用 如果你的目标平台是 Web,请按照 [使用部分](#usage) 中的说明设置 `SafeAreaProvider`。如果你在进行服务端渲染(SSR),请参见该库文档中的 [Web SSR 部分](https://appandflow.github.io/react-native-safe-area-context/optimizations#web-ssr) 。 ## 系统栏 了解如何在Expo项目中处理和自定义系统栏,以实现安全区域和全屏布局。 系统栏是位于屏幕边缘的用户界面元素,用于提供基本的设备信息和导航控制。根据移动操作系统的不同,它们包括状态栏([Android](https://developer.android.com/design/ui/mobile/guides/foundations/system-bars) 和 [iOS](https://developer.apple.com/design/human-interface-guidelines/status-bars))、标题栏(仅限 [Android](https://medium.com/androiddevelopers/insets-handling-tips-for-android-15s-edge-to-edge-enforcement-872774e8839b#:~:text=or%20SHORT_EDGES.-,Caption%20bars,-When%20your%20app))、导航栏([Android](https://developer.android.com/design/ui/mobile/guides/foundations/system-bars#navigation-bar) 和 [iOS](https://developer.apple.com/design/human-interface-guidelines/navigation-bars))以及主屏幕指示器(仅限 iOS)。 这些组件用于显示设备信息,如电池电量、时间、通知提醒,并允许用户在设备界面的任何位置直接与设备交互。例如,应用用户可以下拉状态栏以访问快捷设置和通知,无论当前正在使用哪个应用。 系统栏是移动体验的基础,正确理解如何与它们协作对于开发你的应用程序非常重要。 ## 使用安全区域处理重叠 您的应用部分内容可能会绘制在系统栏后面。为了解决这个问题,您需要正确定位应用内容,避免重叠,并确保系统栏中的控件可见。 以下指南将带您了解如何使用 `SafeAreaView` 或钩子为屏幕的每个边缘直接应用内边距。 ### Android 上的安全区域与边到边布局 在 Android 上启用 [edge-to-edge](https://expo.dev/blog/edge-to-edge-display-now-streamlined-for-android) 之前,通常会使用半透明的状态栏和导航栏。采用这种方式时,绘制在这些栏后面的内容已经位于其下方,通常不需要考虑安全区域。 现在, [在 Android 上启用 edge-to-edge](https://expo.dev/blog/edge-to-edge-display-now-streamlined-for-android) 后,你需要使用安全区域,以确保内容不会与系统栏重叠。 ## 自定义系统栏 系统栏可以根据你的应用设计进行自定义,并在不同场景下提供更好的可见性。在使用 Expo 时,有两个可用的库:`expo-status-bar` 和 `expo-navigation-bar`(仅限 Android)。 ### 状态栏配置 状态栏会显示在 Android 和 iOS 屏幕的顶部。你可以使用 [`expo-status-bar`](/versions/latest/sdk/status-bar) 进行自定义。它提供了一个 `StatusBar` 组件,你可以通过 [`style`](/versions/latest/sdk/status-bar/#style) 属性或 [`setStatusBarStyle`](/versions/latest/sdk/status-bar/#statusbarsetstatusbarstylestyle-animated) 方法,在应用运行时控制状态栏的外观: ```tsx app/_layout.tsx import { StatusBar } from 'expo-status-bar'; export default function RootLayout() { <> {/* Use light text instead of dark text in the status bar to provide more contrast with a dark background. */} ; } ``` > **注意:** 在 Expo 默认模板中,`style` 属性设置为 `auto`。它会根据您的应用当前使用的配色方案(浅色或深色模式)自动选择合适的样式。 要控制 `StatusBar` 的可见性,您可以将 [`hidden`](/versions/latest/sdk/status-bar/#hidden) 属性设置为 `true`,或使用 [`setStatusBarHidden`](/versions/latest/sdk/status-bar/#statusbarsetstatusbarhiddenhidden-animation) 方法。 **在 Android 上启用 edge-to-edge 后,`expo-status-bar` 中依赖于不透明状态栏的功能 [将不可用](https://developer.android.com/about/versions/15/behavior-changes-15#edge-to-edge)** 。只能自定义样式和可见性。其他属性将无效并发出警告。 ### 导航栏配置(仅限 Android) 在 Android 设备上,导航栏显示在屏幕底部。你可以使用 [`expo-navigation-bar`](/versions/latest/sdk/navigation-bar) 库进行自定义。该库提供了一个 `NavigationBar` 组件,你可以通过 [`setStyle`](/versions/latest/sdk/navigation-bar/#navigationbarsetstylestyle) 方法设置导航栏的样式: ```tsx app/_layout.tsx import { Platform } from 'react-native'; import * as NavigationBar from 'expo-navigation-bar'; import { useEffect } from 'react'; useEffect(() => { if (Platform.OS === 'android') { // Set the navigation bar style NavigationBar.setStyle('dark'); } }, []); ``` 要控制 `NavigationBar` 的可见性,你可以使用 [`setVisibilityAsync`](/versions/latest/sdk/navigation-bar/#navigationbarsetvisibilityasyncvisibility) 方法。 **在 Android 上启用边到边后,依赖不透明导航栏的 `expo-navigation-bar` 功能[将不可用](https://developer.android.com/about/versions/15/behavior-changes-15#edge-to-edge)** 。只能自定义样式和可见性。其他属性将无效并发出警告。 ## 字体 了解如何在应用中使用本地文件或 Google Font 包来集成自定义字体 Android 和 iOS 自带一套平台字体。为了提供一致的用户体验并提升应用的品牌形象,可以使用自定义字体。 本指南介绍了在项目中添加和加载自定义字体的不同方法,并提供与字体相关的额外信息。 ## 添加自定义字体 有两种方法可以将自定义字体添加到您的项目中: - 将字体文件放入本地资产中。例如,将字体文件放在 **assets/fonts** 目录。 - 安装一个 Google Font 包。例如,安装 [`@expo-google-fonts/inter`](https://www.npmjs.com/package/@expo-google-fonts/inter) 包。 ### 支持的字体格式 Expo SDK 官方在 Android、iOS 和网页平台上原生支持 OTF 和 TTF 字体格式。如果你的字体是其他字体格式,则需要在项目中进行高级配置以支持该格式。 ### 可变字体 可变字体(包括 OTF 和 TTF 的可变字体实现)并非在所有平台上都得到支持。要获得完整的跨平台支持,请使用静态字体。或者,使用诸如 [fontTools](https://fonttools.readthedocs.io/en/latest/varLib/mutator.html) 之类的工具,从可变字体中提取你想要使用的特定轴配置,并将其保存为单独的字体文件。 ### 如何在 OTF 与 TTF 之间进行选择 如果你使用的字体同时有 OTF 和 TTF 版本,优先选择 OTF。**.otf** 文件比 **.ttf** 文件小。某些情况下,OTF 在某些上下文中还会有略微更好的渲染效果。 ## 使用本地图形字体 将文件复制到你项目的 **assets/fonts** 目录中。 > **info** **assets/fonts** 目录路径是在 React Native 应用中放置字体文件的常见约定。若遵循自定义约定,您也可以将这些文件放在其他位置。 在项目中使用本地字体文件的两种方式: - 将字体文件嵌入使用 [`expo-font` 配置插件](/versions/latest/sdk/font/#configuration-in-app-config) 。 - 在运行时使用 [`useFonts`](/versions/latest/sdk/font/#usefontsmap) 钩子异步加载字体文件。 ### 使用 `expo-font` 配置插件 `expo-font` 配置插件允许在项目的原生代码中嵌入一个或多个字体文件。它对 Android 和 iOS 同时支持 `ttf` 和 `otf`,并且仅在 iOS 上支持 `woff` 和 `woff2`。这是向应用中添加字体的推荐方法,原因如下: - 字体在设备上应用启动时即可立即可用。 - 应用启动时无需额外的代码来异步加载字体。 - 字体在应用安装的所有设备上都可用,因为它们被捆绑在应用中。 然而,这种方法也有一些局限性: - 不适用于 Expo Go,因为此方法需要 [创建开发构建](/develop/development-builds/create-a-build/) 。 要在项目中嵌入字体,请按照以下步骤: Step 1: 在项目中添加自定义字体文件后,安装 `expo-font` 库。 ```sh $ npx expo install expo-font ``` Step 2: 将配置插件添加到你的 [应用配置](/versions/latest/config/app/#plugins) 文件中。配置必须包含使用 [`fonts`, `android` 或 `ios`](/versions/latest/sdk/font/#configurable-properties) 属性的字体文件路径,这些属性接收一个或多个字体定义的数组。每个字体文件的路径相对于项目根目录。 下面的示例展示了所有有效的字体指定方式:可以是一个包含 `fontFamily` 和其他属性的对象数组,,也可以是字体文件路径的数组。 对于 Android,您可以指定 `fontFamily`、`weight`,以及可选的 `style`(默认为 `"normal"`),这将把字体嵌入为本地 [XML 资源](https://developer.android.com/develop/ui/views/text-and-emoji/fonts-in-xml) 。如果您仅在数组中提供字体文件路径,文件名将成为 Android 上的字体族名称。iOS 始终从字体文件本身提取字体族名称。 如果你计划仅使用 `fontFamily` 来引用字体,请提供一个字体路径数组(请参见下方的 `FiraSans-MediumItalic.ttf`)并遵循我们在 [文件命名的推荐](#how-to-determine-which-font-family-name-to-use) 。 如果你想使用 `fontFamily`、`weight` 和 `style` 的组合来引用字体,请提供一个对象数组(见下方的 `Inter`)。 ```json app.json { "expo": { "plugins": [ [ "expo-font", { "fonts": [ "./assets/fonts/FiraSans-MediumItalic.ttf" ], "android": { "fonts": [ { "fontFamily": "Inter", "fontDefinitions": [ { "path": "./assets/fonts/Inter-BoldItalic.ttf", "weight": 700, "style": "italic" }, { "path": "./assets/fonts/Inter-Bold.ttf", "weight": 700 } ] } ] }, "ios": { "fonts": ["./assets/fonts/Inter-Bold.ttf", "./assets/fonts/Inter-BoldItalic.ttf"] } } ] ] } } ``` Step 3: 在使用配置插件嵌入字体后,创建一个 [新的开发构建](/develop/development-builds/create-a-build/) ,并在你的设备、Android 模拟器或 iOS 模拟器上安装。 你可以通过指定 `fontFamily` 样式属性,使用 `` 字体。下面的示例对应于上面配置中定义的字体。 ```tsx Inter Bold Inter Bold Italic Fira Sans Medium Italic ``` - **Android:** 将字体文件复制到 **android/app/src/main/assets/fonts**. - **iOS:** 请在 Apple Developer 文档中查看 [Adding a Custom Font to Your App](https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app)。 #### 如何确定要使用的字体族名称 - 如果你按照上面所述将字体作为文件路径数组提供,在 Android 上,文件名(不包含扩展名)将成为字体族名称。在 iOS 上,字体族名称是从字体文件本身读取的。我们建议将字体文件命名为与其 [PostScript name](#what-is-postscript-name-of-a-font) 相同,这样在两个平台上的字体族名称就保持一致。 - 如果你使用对象语法,请提供 "Family Name"。可以在 macOS 的 Font Book 应用、[fontdrop.info](https://fontdrop.info/) 或其他程序中找到。 Note: 字体文件的 PostScript 名称是什么? --- 字体文件的 **PostScript 名称** 是按 Adobe 的 PostScript 标准分配给字体的唯一标识符。它被操作系统和应用程序用于引用该字体。它不是字体的 **显示名称** 。 例如,Inter Black 字体文件的 PostScript 名称是 `Inter-Black`。 _来自 macOS 的 Font Book 应用截图。_ --- ### 使用 `useFonts` 钩子 `useFonts` 钩子来自 `expo-font` 库,允许异步加载字体文件。该钩子会跟踪加载状态,并在应用初始化时加载字体。 它可与所有 Expo SDK 版本以及 Expo Go 一起使用。要在使用 `useFonts` 钩子的项目中加载字体,请按照以下步骤: 在项目中添加自定义字体文件后,安装 `expo-font` 和 `expo-splash-screen` 库。 Step 1: ```sh $ npx expo install expo-font expo-splash-screen ``` [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) 库提供 `SplashScreen` 组件,您可以使用它在字体加载并就绪之前防止应用渲染。 Step 2: 在项目中的顶层组件(例如根布局 **app/layout.tsx** 文件)中使用 `useFonts` 钩子映射字体文件: ```tsx app/_layout.tsx import {useEffect} from 'react'; SplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [loaded, error] = useFonts({ 'Inter-Black': require('./assets/fonts/Inter-Black.otf'), }); useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } return ( ) } ``` Step 3: 在 React 组件中通过使用 `fontFamily` 样式属性来使用 `` 的字体: ```tsx Inter Black ``` ## 使用 Google Fonts Expo 对 Google Fonts 列出的所有字体提供一流的支持。它们可以通过 [Google Fonts](https://fonts.google.com/) 使用 [`@expo-google-fonts`](https://github.com/expo/google-fonts) 库获得。使用此库中的任意字体包,您可以快速集成该字体及其变体。 在你的项目中使用 Google Font 的两种方式: - 使用 [`expo-font` 配置插件](/versions/latest/sdk/font/#configuration-in-appjsonappconfigjs) 将已安装的字体嵌入。 - 在运行时异步地通过 [`useFonts`](/versions/latest/sdk/font/#usefontsmap) 钩子加载已安装的字体。 ### 使用 `expo-font` 配置插件 > **注意:** 使用 `expo-font` 配置插件嵌入 Google Fonts,与自行嵌入自定义字体具有相同的好处与限制。有关更多信息,请参见 [使用本地字体文件配合 `expo-font` 配置插件](#with-expo-font-config-plugin) 。 Step 1: 安装字体包。例如,要使用 Inter Black 字体,请使用下面的命令安装 [`@expo-google-fonts/inter`](https://www.npmjs.com/package/@expo-google-fonts/inter) 包。 ```sh $ npx expo install expo-font @expo-google-fonts/inter ``` Step 2: 将配置插件添加到你的 [应用配置](/versions/latest/config/app/#plugins) 文件中。该配置必须包含字体文件的路径,通过 [`fonts`](/versions/latest/sdk/font/#configurable-properties) 属性指定,该属性接收一个或多个字体文件的数组。字体文件的路径从 `node_modules` 目录中的字体包中定义。例如,如果你有一个名为 `@expo-google-fonts/inter` 的字体包,那么字体文件的名称是 **Inter_900Black.ttf**。 ```json app.json { "plugins": [ [ "expo-font", { "fonts": ["node_modules/@expo-google-fonts/inter/900Black/Inter_900Black.ttf"] } ] ] } ``` Step 3: 在使用配置插件嵌入字体后,创建一个 [新的开发构建](/develop/development-builds/create-a-build/) 并将其安装在你的设备、Android 模拟器或 iOS 模拟器上。 在 Android 上,你可以使用字体文件名。例如,`Inter_900Black`。在 iOS 上,使用字体及其重量名称([PostScript 名称](#what-is-postscript-name-of-a-font) )。下方示例展示如何使用 [`Platform`](https://reactnative.dev/docs/platform-specific-code#platform-module) 为每个平台选择正确的字体族名称: ```tsx import { Platform } from 'react-native'; // Inside a React component: Inter Black ``` ### 使用 `useFonts` hook > **注意:** 使用 `useFonts` hook 加载 Google Font 与自行嵌入自定义字体具有相同的优点与限制。有关更多信息,请参阅 [使用本地字体文件与 `useFonts` hook](#with-usefonts-hook)。 每个 google Fonts 包都提供 `useFonts` hook,用以异步加载字体。该 hook 会跟踪加载状态,并在应用初始化时加载字体。该字体包还会导入字体文件,因此你无需显式导入。 Step 1: 安装 Google Fonts 包、`expo-font` 和 `expo-splash-screen` 库。 ```sh $ npx expo install @expo-google-fonts/inter expo-font expo-splash-screen ``` [`expo-splash-screen`](/versions/latest/sdk/splash-screen/) 库提供了 `SplashScreen` 组件,您可以使用它在字体加载并就绪之前阻止渲染应用。 Step 2: 安装字体包后,在项目中的顶层组件(例如根布局文件 **app/layout.tsx**)中使用 `useFonts` 钩子映射字体: ```tsx app/_layout.tsx // Rest of the import statements import { Inter_900Black, useFonts } from '@expo-google-fonts/inter'; import * as SplashScreen from 'expo-splash-screen'; import {useEffect} from 'react'; SplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [loaded, error] = useFonts({ Inter_900Black, }); useEffect(() => { if (loaded || error) { SplashScreen.hideAsync(); } }, [loaded, error]); if (!loaded && !error) { return null; } return ( ) } ``` Step 3: 在 React 组件中使用 `` 的字体,通过 `fontFamily` 样式属性: ```tsx Inter Black ``` ## 附加信息 ### 最小示例 ### 超出 OTF 和 TTF 如果你的字体格式不是 OTF 或 TTF,你需要 [自定义 Metro bundler 配置,将其作为额外的资源](/guides/customizing-metro#adding-more-file-extensions-to-assetexts) ,以使其能够工作。在某些情况下,渲染一个平台不支持的字体格式可能会导致应用崩溃。 供参考,以下表格提供在每个原生平台上可使用的列表格式: | 格式 | Android | iOS | Web | | ----- | ----------- | ----------- | ----------- | | bdf | | | | | dfont | | | | | eot | | | | | fon | | | | | otf | | | | | ps | | | | | svg | | | | | ttc | | | | | ttf | | | | | woff | | | | | woff2 | | | | ### 平台内置字体 如果你不想通过指定 `fontFamily` 使用自定义字体,系统默认字体将被使用。每个平台都具有一组内置字体。在 Android 上,默认字体是 Roboto。在 iOS 上,是 SF Pro。 平台的默认字体通常易于阅读。然而,当系统默认字体被更改为另一种不易阅读的字体时,也不要感到惊讶。在这种情况下,使用你的自定义字体,这样你就可以对用户看到的内容进行精确控制。 ### 处理 `@expo/vector-icons` 的初始加载 当 `@expo/vector-icons` 库的图标首次加载时,它们在你的应用中会以不可见的图标呈现。加载完成后,它们会被缓存,供应用的后续使用。为避免在应用首次加载时显示不可见的图标,可以在初始加载屏幕阶段通过 [`useFonts`](/versions/latest/sdk/font/#usefontsmap) 进行预加载。例如: ```tsx app/_layout.tsx import { useFonts } from 'expo-font'; import Ionicons from '@expo/vector-icons/Ionicons'; export default function RootLayout() { useFonts([require('./assets/fonts/Inter-Black.otf', Ionicons.font)]); return ( ) } ``` 现在,您可以在 React 组件中使用 `Ionicons` 库中的任意图标: ```tsx ``` ### 直接从网络加载远程字体 > **warning** **如果你正在加载远程字体,请确保它们来自一个正确配置 CORS 的源** 。如果你不这样做,远程字体在网页平台上可能无法正确加载。 从本地资源加载字体是应用程序中加载字体的最安全方式。当将字体作为本地资源包含时,在你将应用提交到应用商店后,这些字体会随应用下载打包并可立即使用。你无需担心 CORS 或其他潜在问题。 然而,直接从网页加载字体文件,是通过将 `require('./assets/fonts/FontName.otf')` 替换为下面示例所示的字体 URL 来实现。 #### 使用远程字体 ```tsx import { useFonts } from 'expo-font'; import { Text, View, StyleSheet } from 'react-native'; export default function App() { const [loaded, error] = useFonts({ 'Inter-SemiBoldItalic': 'https://rsms.me/inter/font-files/Inter-SemiBoldItalic.otf?v=3.12', }); if (!loaded || !error) { return null; } return ( Inter SemiBoldItalic Platform Default ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` ## 资产 了解在项目中使用静态资源的方法,包括图片、视频、声音、数据库文件和字体。 一个 **静态资源** 是与应用程序二进制文件(本地二进制)打包在一起的文件。此文件类型不属于包含应用程序代码的 JavaScript 包。常见的静态资源类型包括图片、视频、声音、用于 SQLite 的数据库文件以及字体。这些资源可以从你的项目本地提供,或者通过网络远程提供服务。 本地加载并使用静态资源的不同方式,以及关于如何优化和压缩资源的附加信息。 ## 本地提供资源(Serve an asset locally) 当资产存储在项目的文件系统中时,它可以在构建时嵌入到应用二进制中,或在运行时加载。你可以像 JavaScript 模块一样通过 `require` 或 `import` 语句来导入它。 例如,要在 **App.js** 中渲染名为 **example.png** 的图片,可以使用 `require` 从项目的 **assets/images** 目录导入图片,并将其传递给 `` 组件: ```tsx app/index.tsx ``` 在上面的示例中,打包工具会读取所导入图片的元数据并自动提供宽度和高度。有关更多信息,请参阅 [Static Image Resources](https://reactnative.dev/docs/images#static-image-resources). 类似于本地资源的 `expo-image` 和 `expo-file-system` 的库,与 `` 组件的工作方式类似。 ### 资产如何本地提供 本地存储的资产在开发时通过 HTTP 提供。对于生产应用,它们会在构建时自动捆绑到你的应用二进制中,并在设备上从磁盘提供。 ### 在构建时通过 `expo-asset` 配置插件加载资源 要在构建时加载资产,可以使用来自 `expo-asset` 库的 [config plugin](/versions/latest/sdk/asset/#example-appjson-with-config-plugin)。该插件会将资产文件嵌入到你的本地项目中。 Step 1: 安装 `expo-asset` 库。 ```sh $ npx expo install expo-asset ``` Step 2: 将 config plugin 添加到你项目的 [app config](/versions/latest/config/app/#plugins) 文件中。配置必须包含使用 [`assets`](/versions/latest/sdk/asset/#configurable-properties) 属性指向资产文件的路径,该属性接受一个或多个要链接到本地项目的文件或目录的数组。 每个资产文件的路径必须相对于你项目的根目录,因为应用配置文件位于项目的根目录中。 ```json app.json { "expo": { "plugins": [ [ "expo-asset", { "assets": ["./assets/images/example.png"] } ] ] } } ``` Step 3: 在使用配置插件内嵌资产后, [创建一个新的开发构建](/develop/development-builds/create-a-build/) 。现在,您可以在项目中导入并使用该资产,而不需要使用 `require` 或 `import` 语句。 例如,上面的配置插件链接了 **example.png**。你可以直接将其导入到你的组件中,并将其资源名称作为 URI 使用。注意,在不使用 `require` 渲染资源时,需要显式提供宽度 / 高度。 ```tsx app/index.tsx import { Image } from 'expo-image'; export default function HomeScreen() { return ; } ``` > **info** 不同的文件格式通过 `expo-asset` 配置插件得到支持。有关这些格式的更多信息,请参阅 [Assets API reference](/versions/latest/sdk/asset/#configurable-properties)。如果你没有看到配置插件支持的文件格式,你可以在运行时使用 [`useAssets`](#load-an-asset-at-runtime-with-useassets-hook) 钩子来加载资源。 ### 在运行时使用 `useAssets` 钩子加载资源 `useAssets` 钩子来自 `expo-asset` 库,允许异步加载资源。该钩子会下载并将资源本地存储,资源加载完成后,它会返回该资源的实例列表。 Step 1: 安装 `expo-asset` 库。 ```sh $ npx expo install expo-asset ``` Step 2: 在你的屏幕组件中,从 `expo-asset` 库导入 [`useAssets`](/versions/latest/sdk/asset/#useassetsmoduleids) 钩子: ```tsx app/index.tsx import { useAssets } from 'expo-asset'; export default function HomeScreen() { const [assets, error] = useAssets([ require('path/to/example-1.jpg'), require('path/to/example-2.png'), ]); return assets ? : null; } ``` ## 远程提供资源 当资源是远程提供时,它不会在构建时打包进应用二进制文件中。如果资源托管在远程位置,你可以在项目中使用该资源的 URL。例如,将 URL 传递给 `` 组件以渲染远程图片: ```jsx App.js import { Image } from 'expo-image'; function App() { return ( ); } ``` 无法保证通过网页 URL 提供的远程图片的可用性,因为可能无法连接到互联网,或资源已被移除。 此外,加载远程资源还需要你提供资源的元数据。在上面的示例中,由于打包工具(bundler)无法检索图片的宽度和高度,因此将这些值明确传递给 `` 组件。如果不这样做,图片将默认为 0px x 0px。 ## 附加信息 ### 手动优化方法 #### 图像 您可以使用以下方法压缩图像: - [`guetzli`](https://github.com/google/guetzli) - [`pngcrush`](https://pmt.sourceforge.io/pngcrush/) - [`optipng`](http://optipng.sourceforge.net/) 一些图片优化器是无损的。它们会重新编码你的图片,使其在像素显示上没有任何改变或损失,从而变小。当你需要确保每个像素都保持原样时,无损优化器和像 PNG 这样的无损图片格式是一个不错的选择。 其他图片优化器是有损的。优化后的图片与原始图片不同。通常,有损优化器更高效,因为它们会丢弃会降低文件大小的视觉信息,同时让图片在人眼看来几乎不变。像 `imagemagick` 这样的工具可以使用诸如 [SSIM](https://en.wikipedia.org/wiki/Structural_similarity) 的比较算法来显示两张图片看起来有多相似。对于一个与原始图片相似度超过 95% 的优化图片,实际的文件大小往往远小于原始文件的 95%。 #### 其他资源块 对于 GIF 动图、视频等非代码、非图片资源,是否对这些资源进行优化和最小化取决于你。 > **注意:** GIF 是一种非常低效的格式。现代视频编解码器可以在更高的画质下产生显著更小的文件大小。 ### 字体 请参阅 [Add a custom font](/develop/user-interface/fonts/#add-a-custom-font) 获取有关如何将自定义字体添加到您的应用程序的更多信息。 ## 颜色主题 了解如何在应用中支持亮色和暗色模式。 应用通常支持明暗两种颜色模式。下面是一个在 Expo 项目中同时支持这两种模式的示例: ## 配置 > **info** 对于 Android 和 iOS 项目,需要额外的配置来支持在明暗模式之间切换。对于 Web,不需要额外的配置。 要配置所支持的外观样式,可以在项目的 [`userInterfaceStyle`](/versions/latest/config/app/#userinterfacestyle) 属性中进行设置,位于 [应用配置(app config)](/versions/latest/config/app) 中。默认情况下,当你使用 [默认模板](/get-started/create-a-project/) 创建新项目时,此属性被设置为 `automatic`。 以下是一个配置示例: ```json app.json { "expo": { "userInterfaceStyle": "automatic" } } ``` 您也可以通过将 `android.userInterfaceStyle` 或 [`ios.userInterfaceStyle`](/versions/latest/config/app/#userinterfacestyle-1) 设置为首选值来为特定平台配置 `userInterfaceStyle` 属性。 > **info** 如果该属性缺失,应用将默认使用 `light` 样式。 在你创建开发构建时,必须安装 [`expo-system-ui`](/versions/latest/sdk/system-ui/#installation) 以支持 Android 的外观样式。否则,`userInterfaceStyle` 属性将被忽略。 ```sh $ npx expo install expo-system-ui ``` 如果项目配置错误且未安装 `expo-system-ui`,在终端中将显示以下警告: ```sh » android: userInterfaceStyle: Install expo-system-ui in your project to enable this feature. ``` 你也可以使用以下命令检查项目是否配置错误: ```sh $ npx expo config --type introspect ``` Note: 使用裸 React Native 应用? --- #### Android 确保在你的 `MainActivity`(以及任何希望实现此行为的其他活动)中,以及在 **AndroidManifest.xml** 中,包含 `uiMode` 标志: ```xml ``` 在 **MainActivity.java** 中实现 `onConfigurationChanged` 方法: ```java import android.content.Intent; import android.content.res.Configuration; public class MainActivity extends ReactActivity { @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Intent intent = new Intent("onConfigurationChanged"); intent.putExtra("newConfig", newConfig); sendBroadcast(intent); } } ``` #### iOS 您可以在应用的 **Info.plist** 中通过 [`UIUserInterfaceStyle`](https://developer.apple.com/documentation/bundleresources/information_property_list/uiuserinterfacestyle) 键配置受支持的样式。使用 `Automatic` 以同时支持明亮模式和暗黑模式。 --- ### 支持的外观风格 `userInterfaceStyle` 属性支持以下值: - `automatic`:跟随系统外观设置,并在用户做出任何更改时进行通知。 - `light`:将应用限制为仅支持浅色主题。 - `dark`:将应用限为仅支持暗色主题。 ## 检测配色方案 要在你的项目中检测配色方案,请使用 `Appearance` 或 `useColorScheme` 来自 `react-native`: ```tsx app/index.tsx import { Appearance, useColorScheme } from 'react-native'; ``` 然后,你可以像下面这样使用 `useColorScheme()` 钩子: ```tsx app/index.tsx function MyComponent() { let colorScheme = useColorScheme(); if (colorScheme === 'dark') { // render some dark thing } else { // render some light thing } } ``` 在某些情况下,您会发现以命令方式获取当前颜色方案非常有用,例如使用 [`Appearance.getColorScheme()`](https://reactnative.dev/docs/appearance),或通过 `Appearance.addChangeListener()` 监听变化。 ## 附加信息 ### 最小示例 #### useColorScheme example ```tsx import { StatusBar } from 'expo-status-bar'; export default function App() { const colorScheme = useColorScheme(); const themeTextStyle = colorScheme === 'light' ? styles.lightThemeText : styles.darkThemeText; const themeContainerStyle = colorScheme === 'light' ? styles.lightContainer : styles.darkContainer; return ( Color scheme: {colorScheme} ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, text: { fontSize: 20, }, lightContainer: { backgroundColor: '#d0d0c0', }, darkContainer: { backgroundColor: '#242c40', }, lightThemeText: { color: '#242c40', }, darkThemeText: { color: '#d0d0c0', }, }); ``` ### 提示 在开发项目时,您可以通过以下快捷方式来更改模拟器或设备的外观: - 如果使用 Android 模拟器,您可以运行 `adb shell "cmd uimode night yes"` 来开启深色模式,且 `adb shell "cmd uimode night no"` 来关闭深色模式。 - 如果使用实体 Android 设备或 Android 模拟器,您可以在设备设置中切换系统的深色模式设置。 - 如果在本地使用 iOS 模拟器,您可以使用 Cmd ⌘ + Shift + a 快捷方式在明暗模式之间切换。 ## 动画 了解如何集成 React Native 动画并在你的 Expo 项目中使用它。 动画是提升体验、提供更好用户体验的好方法。在你的 Expo 项目中,你可以使用 React Native 的 [Animated API](https://reactnative.dev/docs/next/animations)。然而,如果你想使用更高级的动画、获得更好的性能,可以使用 [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/) 库。它提供了一个简化创建平滑、强大且易维护的动画的 API。 ## 安装 如果你使用 [默认模板](/get-started/create-a-project/) 创建了项目,可以跳过安装 `react-native-reanimated`。这个库已经安装好。否则,请通过以下命令安装: ```sh $ npx expo install react-native-reanimated ``` ## 用法 ### 最小示例 下面的示例展示如何使用 `react-native-reanimated` 库来创建一个简单动画。有关 API 和高级用法的更多信息,请参阅 [`react-native-reanimated` 文档](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/your-first-animation) 。 #### 使用 react-native-reanimated ```tsx import Animated, { useSharedValue, withTiming, useAnimatedStyle, Easing, } from 'react-native-reanimated'; import { View, Button, StyleSheet } from 'react-native'; export default function AnimatedStyleUpdateExample() { const randomWidth = useSharedValue(10); const config = { duration: 500, easing: Easing.bezier(0.5, 0.01, 0, 1), }; const style = useAnimatedStyle(() => { return { width: withTiming(randomWidth.value, config), }; }); return (