自动链接
了解如何使用 Expo 自动链接自动链接 Expo 项目中的原生依赖。
通常,当你开发原生移动应用并想要安装第三方库时,你需要在包管理器的清单文件中添加依赖(在 Android 上是 build.gradle,在 iOS 上通过 CocoaPods 是 Podfile,通过 SwiftPM 是 Package.swift)。 在 Expo 和 React Native 中,你已经可以通过 package.json 文件从 npm 注册表安装包来做到这点。由于大多数 React Native 库都包含一些原生(特定平台的)代码,安装一个库可能需要配置多达三个不同的包管理器!
🌐 Usually, when you're developing a native mobile app and want to install a third-party library, you're asked to add the dependency to the manifest files of your package managers (build.gradle on Android, Podfile for CocoaPods on iOS, Package.swift for SwiftPM on iOS). In Expo and React Native, you already do that with your package.json file by installing the package from the npm registry. Since most of the React Native libraries come with some native (platform-specific) code, installing a library will require configuring even up to three different package managers!
Expo 自动链接是一种自动化机制,它将这一过程简化到最小——通常只需从 npm 安装包并重新运行 pod install 即可。
核心实现可以在 expo-modules-autolinking 包中找到,并分为三部分:
🌐 Expo Autolinking is a mechanism that automates this process and reduces the library installation process to the minimum — usually just installing the package from npm and re-running pod install.
The core implementation can be found in the expo-modules-autolinking package and is divided into three parts:
- 带有模块解析算法的 CLI 命令
- 与 Android Gradle 构建系统集成的代码
- 与 iOS CocoaPods 集成的代码
自 SDK 52 起,Expo 自动链接不仅可以链接 Expo 模块,还可以链接 React Native 模块。要改为使用 React Native 社区 CLI 的自动链接,请参阅 为 React Native 模块退出 Expo 自动链接 部分。
🌐 Since SDK 52, Expo Autolinking not only links Expo modules, but also React Native modules. To use the React Native community CLI autolinking instead, see opting out of Expo Autolinking for React Native modules section.
链接行为
🌐 Linking behavior
Expo 自动链接已集成到 Android 的 Gradle 构建系统和 iOS 的 CocoaPods 中。在构建应用时,会调用 Expo 自动链接 CLI,它会搜索 Expo 和 React Native 模块进行自动链接。
🌐 Expo Autolinking is integrated into the Gradle build system for Android and CocoaPods for iOS. When building your app, the Expo Autolinking CLI is called and searches for Expo and React Native modules to autolink.
此模块解析会通过四个单独的步骤搜索要自动链接的候选依赖:
🌐 This module resolution searches for candidate dependencies to autolink in four separate steps:
- 仅针对 React Native 模块,它会检查你项目根目录下的 react-native.config.js 中是否包含指定的
root路径的dependencies。这个文件是可选的,大多数 Expo 项目中并不存在。 - 它会搜索你自动链接配置中
searchPaths选项指定的所有目录。 - 它会在自动链接配置中
nativeModulesDir选项指定的目录中搜索本地模块,该选项默认值为./modules/。 - 它会递归地解析你的应用及其任何依赖或同辈依赖的依赖。这与Node.js解析算法一致。
自动链接的模块会自动添加到构建中,这通常意味着应用包含原生(平台特定)代码的依赖会自动设置。
🌐 The autolinked modules are automatically added to the build, which usually means that your app's dependencies that contain native (platform-specific) code are set up automatically.
配置
🌐 Configuration
模块解析的行为可以通过一些配置选项进行自定义。这些选项可以在三个不同的位置定义,优先级从低到高依次为:
🌐 The behavior of the module resolution can be customized using some configuration options. These options can be defined in three different places, from the lowest to the highest precedence:
- 应用 package.json 中的
expo.autolinking配置对象 - 使用
expo.autolinking.ios和expo.autolinking.android对象进行每个平台的覆盖 - 提供给 CLI 命令的选项,Podfile 中的
use_expo_modules!方法或 settings.gradle 中的useExpoModules函数
searchPaths
一个相对于应用根目录的路径列表,Expo 自动链接应在这些路径中搜索要自动链接的模块。当你的项目有自定义结构或你想从不同于node_modules的目录链接本地包时,这非常有用。你指定的路径仍然必须像node_modules目录一样结构化。
🌐 A list of paths relative to the app's root directory that Expo Autolinking should search for modules to autolink. Useful when your project has a custom structure or you want to link local packages from directories different than node_modules. The paths you specify must still be structured like node_modules directories.
{ "expo": { "autolinking": { "searchPaths": ["../../packages"] } } }
信息 在 SDK 54 之前,这个列表默认指向你应用的 node_modules 目录,以及单体仓库中它上层的所有 node_modules 目录。 若要恢复旧的行为,请将此列表设置为你应用的 node_modules 目录,例如:
["../../node_modules", "./node_modules"]。
nativeModulesDir
相对于应用根目录的路径,Expo 自动链接应该在该路径中搜索本地模块以进行自动链接。此选项的默认值为 "./modules"。只有在需要更改本地 Expo 模块的路径时,才需要更改此选项。
🌐 A path relative to the app's root directory that Expo Autolinking should search for local modules to autolink. This option defaults to "./modules". Changing this option is only useful if you need to change the path for local Expo modules.
{ "expo": { "autolinking": { "nativeModulesDir": "./modules" } } }
exclude
要从自动链接中排除的包名列表。如果你不想链接某些特定平台未使用的包,以减小二进制文件的大小,这非常有用。
在 package.json 中使用以下配置将在 Android 上将 expo-random 和 third-party-expo-module 排除在自动链接之外:
🌐 A list of package names to exclude from autolinking. This is useful if you don't want to link some packages that specific platforms aren't using to reduce the binary size.
The following config in package.json will exclude expo-random and third-party-expo-module from autolinking on Android:
{ "expo": { "autolinking": { "android": { "exclude": ["expo-random", "third-party-expo-module"] } } } }
React Native 模块也可以通过在项目根目录下创建 react-native.config.js 并将模块应排除的平台配置设置为 null 来排除。以下配置将从 Android 的自动链接中排除 library-name:
🌐 React Native modules can also be excluded by creating a react-native.config.js in the root directory of your project and setting the platform's configuration that the module should be excluded from to null. The following config will exclude library-name from autolinking on Android:
module.exports = { dependencies: { 'library-name': { platforms: { android: null, }, }, }, };
信息 在 SDK 54 之前,
exclude选项仅适用于 Expo 模块,而不适用于 React Native 模块。React Native 模块只能通过在项目根目录下使用 react-native.config.js 文件来排除。
flags
CocoaPods 标志,用于传递给每个自动链接的 Pod。inhibit_warnings 很可能是大多数开发者唯一想使用的标志,用于抑制在编译自动链接模块时产生的 Xcode 警告。
你可以参考 CocoaPods Podfile 文档 了解可用的标志。
🌐 CocoaPods flags to pass to each autolinked pod. inhibit_warnings is likely the only flag most developers want to use, to inhibit Xcode warnings produced when compiling the autolinked modules.
You can refer to the CocoaPods Podfile documentation for available flags.
use_expo_modules!({ flags: { :inhibit_warnings => false } })
{ "expo": { "autolinking": { "ios": { "flags": { "inhibit_warnings": true } } } } }
buildFromSource
要选择不使用预构建 Expo 模块的包名称列表。完整参考,请参见 Android 的预构建 Expo 模块。
🌐 A list of package names to opt out of prebuilt Expo modules. For complete reference, see Prebuilt Expo Modules for Android.
legacy_shallowReactNativeLinking
在解析你的应用的 React Native 模块时,Expo 自动链接会搜索你应用的依赖,以及这些依赖的依赖,递归进行(符合 Node.js 解析算法)。在 SDK 54 之前,Expo 自动链接不会递归搜索依赖,只会解析你应用的直接依赖。
🌐 When resolving your app's React Native modules, Expo Autolinking searches your app's dependencies, and those dependencies' dependencies recursively (matching the Node.js resolution algorithm). Before SDK 54, Expo Autolinking didn't search dependencies recursively and only resolved your app's direct dependencies.
启用此标志后,你将选择不使用新行为,而是恢复 SDK 54 之前的行为,仅在应用的直接依赖中搜索 React Native 模块。解析 Expo 模块时不会考虑此选项。
🌐 When enabled, this flag opts you out of the new behavior and restores the behavior from before SDK 54, only searching your app's direct dependencies for React Native modules. This option isn't considered when resolving Expo modules.
CLI 命令
🌐 CLI commands
search
此命令由构建系统调用,用于在自动链接的第一阶段解析 Expo 模块。其实现是在所有平台之间共享的。search 的输出将包含每个包的 duplicates 列表,如果发现有重复项的话。
🌐 This command is called by the build system to resolve Expo modules during the first phase of autolinking. Its implementation is shared between all platforms. The output from search will contain a list of duplicates per package, if any duplicates were found.
- npx expo-modules-autolinking search上述命令返回一个 JSON 格式的对象,其中包含 Expo Autolinking 找到的 Expo 模块:
🌐 The above command returns an object in JSON format with Expo modules that Expo Autolinking found:
{ "expo-random": { "path": "/absolute/path/to/node_modules/expo-random", "version": "13.0.0", "config": { // Contents of `expo-module.config.json` }, "duplicates": [ // List of conflicting duplicates for this module (with lower precedence) ] } // more modules... }
resolve
此命令在自动链接的第二阶段由构建系统调用。它为每个 Expo 模块输出一个包含更多(平台特定)详细信息的对象,例如 build.gradle 或 podspec 文件的路径以及要链接的模块类。
🌐 This command is called by the build system during the second phase of autolinking. It outputs an object with more (platform-specific) details for each Expo module, such as the path to the build.gradle or podspec files and module classes to link.
- npx expo-modules-autolinking resolve --platform <apple|android>例如,使用 --platform apple 选项,它会返回一个 JSON 格式的对象,其中包含一个模块数组和平台的解析详情:
🌐 For example, with the --platform apple option, it returns an object in JSON format with an array of modules and resolved details for the platform:
{ "modules": [ { "packageName": "expo-random", "packageVersion": "13.0.0", "pods": [ { "podName": "ExpoRandom", "podspecDir": "/absolute/path/to/node_modules/expo-random/ios" } ], "swiftModuleNames": ["ExpoRandom"], "modules": ["RandomModule"], "appDelegateSubscribers": [], "reactDelegateHandlers": [], "debugOnly": false } // more modules... ] }
verify
通过检查重复项来验证自动链接的原生模块。每个有冲突的重复安装都会显示警告。
🌐 Verifies the autolinked native modules by checking for duplicates. Warnings are shown for each conflicting, duplicate installation.
- npx expo-modules-autolinking verify传递 --verbose 选项以列出所有自动链接的原生模块。
🌐 Pass the --verbose option to list all autolinked native modules.
react-native-config
当自动链接 React Native 模块时,构建系统会调用此命令。它会输出一个对象,其中包含每个 React Native 模块的更多平台特定的详细信息,例如 gradle 或 podspec 文件的路径。
🌐 This command is called by the build system when autolinking React Native modules. It outputs an object with more platform-specific details for each React Native module, such as the path to the gradle or podspec files.
- npx expo-modules-autolinking react-native-config例如,使用 --platform ios 选项时,它会返回一个对象,该对象采用 react-native.config.js 的输出格式,包含每个 React Native 依赖的信息以及 React Native 安装路径。
🌐 For example, with the --platform ios option, it returns an object in react-native.config.js's output format with information about each React Native dependency and the path to the React Native installation.
{ "root": "/absolute/path/to", "reactNativePath": "/absolute/path/to/node_modules/react-native", "dependencies": { "@react-native-async-storage/async-storage": { "root": "/absolute/path/to/node_modules/@react-native-async-storage/async-storage", "name": "@react-native-async-storage/async-storage", "platforms": { "ios": { "podspecPath": "/absolute/path/to/node_modules/@react-native-async-storage/async-storage/RNCAsyncStorage.podspec", "version": "", "configurations": [], "scriptPhases": [] } } } // more modules... } }
依赖解析和冲突
🌐 Dependency resolution and conflicts
自动链接和 Node 解析有不同的目标,Node 和 Metro 中的模块解析算法有时可能会发生冲突。如果你的应用包含由自动链接识别的本地模块的重复安装,你的 JavaScript 包可能会包含本地模块的两个版本,而自动链接和你的本地应用只会包含一个版本。这可能导致运行时崩溃并存在兼容性风险。
🌐 Autolinking and Node resolution have different goals and the module resolution algorithm in Node and Metro can sometimes come into conflict. If your app contains duplicate installations of a native module that is picked up by autolinking, your JavaScript bundle may contain both versions of the native module, while autolinking and your native app will only contain one version. This might cause runtime crashes and risks incompatibilities.
这是一个在孤立依赖或单仓库中尤其常见的问题,你应该检查并去重依赖中的本地模块。
🌐 This is an especially common problem with isolated dependencies or monorepos, and you should check for and deduplicate native modules in your dependencies.
从 SDK 54 开始,你可以在你的 应用配置 中将 experiments.autolinkingModuleResolution 设置为 true,以自动将 Expo CLI 和 Metro 打包器 进行自动链接。这将强制 Metro 解析的依赖与 自动链接 解析的原生模块匹配。
🌐 From SDK 54, you can set experiments.autolinkingModuleResolution to true in your app config to apply autolinking to Expo CLI and Metro bundler automatically. This will force dependencies that Metro resolves to match the native modules that autolinking resolves.
从 SDK 55 开始,experiments.autolinkingModuleResolution 标志在 monorepos 中的应用默认已启用。
🌐 From SDK 55, the experiments.autolinkingModuleResolution flag is enabled by default for apps in monorepos.
常见问题
🌐 Common questions
如何在我的应用中设置自动链接?
🌐 How to set up the autolinking in my app?
使用 npx create-expo-app 命令创建的所有项目都已配置为使用 Expo 自动链接。如果你的项目是使用其他工具创建的,请参阅 安装 Expo 模块 以确保你的项目包含所有必要的更改。
🌐 All projects created with the npx create-expo-app command are already configured to use Expo Autolinking. If your project was created using a different tool, see Installing Expo modules to make sure your project includes all necessary changes.
我的模块中需要有什么才能使其可自动链接?
🌐 What do I need to have in my module to make it autolinkable?
模块解析算法只会搜索在根目录中包含 Expo 模块配置 文件(expo-module.config.json),并且与 package.json 文件在同一目录下的包。
同时,还需要在 platforms 数组中包含支持的平台——如果运行自动链接算法的平台不在此数组中,它在搜索结果中将被直接跳过。
🌐 The module resolution algorithm searches only for packages that contain the Expo module config file (expo-module.config.json) at the root directory, next to the package.json file.
It's also necessary to include supported platforms in the platforms array — if the platform for which the autolinking algorithm is run is not present in this array, it's just skipped in the search results.
它与 React Native 社区 CLI 自动链接有何不同?
🌐 How is it different from React Native community CLI autolinking?
- Expo Autolinking 内置支持单一仓库、包管理器工作区、传递依赖和独立依赖安装。
- 虽然模块解析算法更加复杂,以提高可靠性并与 Node.js 的模块解析匹配,但它的速度也显著提高。
- Expo 模块解析还能够检测重复依赖,这是单一仓库中常见的问题。
- 最后但同样重要的是,它与 Expo Modules API 提供的功能完美集成,并支持 React Native 模块。
退出 React Native 模块的 Expo 自动链接
🌐 Opting out of Expo Autolinking for React Native modules
从 SDK 52 开始,Expo 自动链接默认取代了 React Native 社区 CLI 的自动链接。如果你想改为使用 React Native 社区 CLI 的自动链接,请设置环境变量 EXPO_USE_COMMUNITY_AUTOLINKING=1 并将 @react-native-community/cli 添加为项目的开发依赖。
🌐 Starting from SDK 52, Expo Autolinking replaces the React Native community CLI autolinking by default. If you would like to use the React Native community CLI's autolinking instead, set the environment variable EXPO_USE_COMMUNITY_AUTOLINKING=1 and add @react-native-community/cli as a dev dependency to your project.
设置此环境变量后,Expo Autolinking 将不会用于解析 React Native 模块,但将继续自动链接 Expo 模块。
🌐 With this environment variable set, Expo Autolinking will not be used to resolve React Native modules, but will continue to autolink Expo modules.