Expo Go 中的自定义原生代码

了解如何检测和禁用 Expo Go 中不支持的原生功能。


Expo 应用可用于试验大多数 React Native 应用,无论它们是如何引导的。

¥The Expo Go app can be used to experiment with most React Native apps regardless of how they are bootstrapped.

使用 Expo Go 进行迭代的主要缺点是无法将自定义原生代码通过无线方式发送到 Expo Go 应用。这意味着你需要执行以下操作之一:

¥The main drawback of iterating with Expo Go is that it is impossible to send custom native code over-the-air to the Expo Go app. This means you will need to do one of the following:

  1. 创建 开发构建 以使用自定义原生代码,并将其与 内部分配 或 TestFlight 一起分发。

    ¥Create a development build to use custom native code, and distribute it with internal distribution or TestFlight.

  2. 有条件地禁用 Expo Go 中不支持的原生功能。

    ¥Conditionally disable unsupported native features in Expo Go.

本指南将演示如何通过兼容库版本、在运行时检测代码是否在 Expo Go 应用中运行、原生模块检测等来实现第二个选项。

¥This guide will demonstrate achieving the second option by compatible library versions, detecting whether the code is running in an Expo Go app at run time, native module detection, and so on.

用法

¥Usage

在任何 React Native 应用中,启动 使用 Expo CLI 的开发服务器

¥Inside any React Native app, start a development server with Expo CLI:

Terminal
npx expo start
Don't have npx expo start?

Install and configure the expo package in your project.

然后,通过在终端 UI 中按 ia 在 Expo Go 中启动你的项目。某些功能可能会导致你的应用因缺少某些原生代码而引发错误,请继续阅读以了解如何有条件地跳过不受支持的 API。

¥Then, launch your project in Expo Go by pressing i or a in the Terminal UI. Some features may cause your app to throw errors because certain native code is missing, continue reading to learn how you can conditionally skip unsupported APIs.

npx react-native start 不同,命令 npx expo start 托管一个应用清单,Expo Go 等开发客户端可以使用该清单来加载任意项目。将应用清单想象为 index.html<head /> 元素,但适用于 React Native 应用。要查看此清单,请在 Web 浏览器中访问开发服务器 URL。

¥Unlike npx react-native start the command npx expo start hosts an app manifest that dev clients like Expo Go can use to load arbitrary projects. Think of an app manifest like the <head /> element of an index.html but for React Native apps. To view this manifest, visit the dev server URL in your web browser.

安装库

¥Installing libraries

确保你的应用使用与项目的 react-native 版本最兼容的库版本。这意味着使用 npx expo install 而不是 npm install 来安装库。了解有关 npx expo install 的更多信息。

¥Ensure your app uses the most compatible library versions for the project's react-native version. This means that use npx expo install instead of npm install to install libraries. Read more about npx expo install.

运行时检测

¥Runtime detection

检测 JavaScript 包运行位置的最简单方法是检查 Constants.executionEnvironment

¥The easiest way to detect where the JavaScript bundle is running is to check the Constants.executionEnvironment.

Terminal
npx expo install expo-constants
import Constants, { ExecutionEnvironment } from 'expo-constants';

// `true` when running in Expo Go.
const isExpoGo = Constants.executionEnvironment === ExecutionEnvironment.StoreClient;

你可以使用此布尔值有条件地要求自定义原生代码。以下是使用 react-native-blurhash 库的示例,该库在 Expo Go 应用中不可用:

¥You can use this boolean to conditionally require custom native code. Here's an example using the library react-native-blurhash which is not available in the Expo Go app:

Example
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Constants, { ExecutionEnvironment } from 'expo-constants';

// `true` when running in Expo Go.
const isExpoGo = Constants.executionEnvironment === ExecutionEnvironment.StoreClient;

let Blurhash;
// Create a fallback for Expo Go
if (isExpoGo) {
  Blurhash = props => (
    <View
      style={[
        {
          backgroundColor: 'lightblue',
          alignItems: 'center',
          justifyContent: 'center',
        },
        props.style,
      ]}>
      <Text>(Blurhash not available)</Text>
    </View>
  );
} else {
  // Conditionally require this module to prevent Metro from throwing warnings.
  Blurhash = require('react-native-blurhash').Blurhash;
}

export default function App() {
  return <Blurhash blurhash="LGFFaXYk^6#M@-5c,1J5@[or[Q6." style={{ flex: 1 }} />;
}

如果你在 Expo Go 应用中运行此代码,你将看到后备视图。如果你可以使用 Expo CLI 运行命令 在本地构建它,那么你将看到原生模糊哈希视图。

¥If you run this code in the Expo Go app, you'll see the fallback view. If you can build this locally with the Expo CLI run commands then you'll see the native blur hash view.

原生模块检测

¥Native module detection

原生模块在运行时添加到 JavaScript 全局对象中。这意味着你可以有条件地检查它们是否存在以确保功能:

¥Native modules are added to the JavaScript global object at the runtime. This means you can conditionally check if they exist to ensure functionality:

import { NativeModules } from 'react-native';

const isAvailable = !!NativeModules.MyAnalytics;

上面的代码片段确保必须安装并链接原生模块。然而,这个解决方案有两个问题:

¥The above code snippet ensures the native module must be installed and linked. However, there are two issues with this solution:

  1. 你需要提前知道原生模块名称。

    ¥You need to know the native module name ahead of time.

  2. 当自定义构建中缺少原生模块时,你可能希望抛出错误。这可以帮助你确定是否存在原生链接问题。

    ¥You likely want an error to be thrown when a native module is missing in a custom build. This helps you determine if there is a native linking issue.

可选导入

¥Optional imports

Metro 打包器 支持可选导入。它们指的是用 try/catch 封装 require 语句,以防止在请求的模块丢失时抛出错误:

¥Optional imports are supported by Metro bundler. They refer to wrapping a require statement with a try/catch to prevent an error from being thrown when the requested module is missing:

Example
import React from 'react';
import { View } from 'react-native';

let Blurhash;

try {
  Blurhash = require('react-native-blurhash').Blurhash;
} catch {
  Blurhash = View;
}

export default function App() {
  return <Blurhash blurhash="LGFFaXYk^6#M@-5c,1J5@[or[Q6." style={{ flex: 1 }} />;
}

此方法最不可靠,因为 require 语句可能引发错误的原因有多种。例如,可能存在内部错误、模块可能丢失、原生模块可能链接不正确等等。你应该避免使用此方法。

¥This method is the least reliable because there are several reasons that a require statement might throw an error. For example, there could be an internal error, the module could be missing, the native module could be linked incorrectly, and so on. You should avoid using this method.

已弃用的 .expo 扩展

¥Deprecated .expo extensions

用于提供 Expo Go 特定后备的 .expo.[js/json/ts/tsx] 扩展被删除,以支持可选的导入语法。欲了解更多信息,请参阅 迁移掉 expo 文件扩展名

¥The .expo.[js/json/ts/tsx] extensions to provide Expo Go specific fallbacks are removed in favor of optional imports syntax. For more information, see Migration off the expo file extension.

Expo 中文网 - 粤ICP备13048890号