自动链接
编辑
学习如何使用 Expo 自动链接在您的 Expo 项目中自动链接原生依赖。
通常,当您开发一个原生移动应用并想要安装第三方库时,您需要将依赖项添加到包管理器的清单文件中(build.gradle 在 Android 上,Podfile 在 iOS 的 CocoaPods 上,Package.swift 在 iOS 的 SwiftPM 上)。 在 Expo 和 React Native 中,您通过从 npm 注册表中安装包,已经使用了您的 package.json 文件。由于大多数 React Native 库都带有某些原生(特定平台的)代码, 安装库将需要配置多达三个不同的包管理器!
Expo 自动链接是自动化此过程的机制,将库安装过程减少到最小——通常只需从 npm 安装包并重新运行 pod install。
核心实现可以在 expo-modules-autolinking 包中找到,并分为三个部分:
- 带有模块解析算法的 CLI 命令
- 与 Android 的 Gradle 构建系统集成的代码
- 与 iOS 的 CocoaPods 集成的代码
自 SDK 52 起,Expo 自动链接不仅链接 Expo 模块,还链接 React Native 模块。要使用 React Native 社区 CLI 的自动链接,请参见 选择退出 Expo 自动链接以用于 React Native 模块 部分。
链接行为
Expo 自动链接集成到 Android 的 Gradle 构建系统和 iOS 的 CocoaPods 中。当构建您的应用时,Expo 自动链接 CLI 会被调用并搜索 Expo 和 React Native 模块以进行自动链接。
该模块解析在四个单独的步骤中搜索要自动链接的候选依赖项:
- 仅针对 React Native 模块,它考虑您项目根目录的 react-native.config.js 中包含显式
root路径的任何dependencies。此文件是可选的,且在大多数 Expo 项目中并不存在。 - 它搜索您自动链接配置中的
searchPaths选项指定的所有目录。 - 它搜索在您自动链接配置的
nativeModulesDir选项中指定的目录中的本地模块,默认为./modules/。 - 它递归解析您的应用的依赖及任何依赖或同伴依赖。这符合 Node.js 解析算法。
自动链接的模块会自动添加到构建中,这通常意味着您应用中的包含原生(特定平台)代码的依赖被自动设置。
配置
模块解析的行为可以使用一些配置选项进行自定义。这些选项可以在三个不同的位置定义,从最低优先级到最高优先级:
- 应用程序的 package.json 中的
expo.autolinking配置对象 - 通过
expo.autolinking.ios和expo.autolinking.android对象进行每个平台的覆盖 - 提供给 CLI 命令的选项,Podfile 中的
use_expo_modules!方法或 settings.gradle 中的useExpoModules函数
searchPaths
一个路径列表,相对于应用的根目录,Expo 自动链接应搜索以进行模块自动链接。 在您的项目具有自定义结构或您想要链接来自于与 node_modules 不同目录的本地包时很有用。 您指定的路径仍然必须像 node_modules 目录那样结构化。
{ "expo": { "autolinking": { "searchPaths": ["../../packages"] } } }
在 SDK 54 之前,此列表默认指向您应用的 node_modules 目录,以及在单体仓库中高于它的所有 node_modules 目录。 要恢复为旧行为,请将此列表设置为您应用的 node_modules 目录,例如:["../../node_modules", "./node_modules"]。
nativeModulesDir
一个路径,相对于应用的根目录,Expo 自动链接应搜索以进行本地模块的自动链接。此选项默认为 "./modules"。更改此选项仅在您需要更改 本地 Expo 模块 的路径时有用。
{ "expo": { "autolinking": { "nativeModulesDir": "./modules" } } }
exclude
一个要从自动链接中排除的包名称列表。如果您不想链接某些特定平台不使用的包以减少二进制大小,这很有用。
以下在 package.json 中的配置将在 Android 上排除 expo-random 和 third-party-expo-module 的自动链接:
{ "expo": { "autolinking": { "android": { "exclude": ["expo-random", "third-party-expo-module"] } } } }
React Native 模块也可以通过在项目的根目录中创建 react-native.config.js 并将应排除的平台配置设置为 null 来排除。以下配置将在 Android 上排除 library-name 的自动链接:
module.exports = { dependencies: { 'library-name': { platforms: { android: null, }, }, }, };
在 SDK 54 之前,exclude选项仅适用于 Expo 模块,而不适用于 React Native 模块。React Native 模块只能通过在您项目的根目录中使用 react-native.config.js 文件进行排除。
flags
传递给每个自动链接的 pod 的 CocoaPods 标志。 inhibit_warnings 可能是大多数开发人员希望使用的唯一标志,以抑制编译自动链接模块时产生的 Xcode 警告。
您可以参考 CocoaPods Podfile 文档 获取可用的标志。
use_expo_modules!({ flags: { :inhibit_warnings => false } })
{ "expo": { "autolinking": { "ios": { "flags": { "inhibit_warnings": true } } } } }
legacy_shallowReactNativeLinking
在解析您的应用的 React Native 模块时,Expo 自动链接搜索您的应用的依赖以及这些依赖的依赖(符合 Node.js 解析算法)。在 SDK 54 之前,Expo 自动链接未递归搜索依赖项,仅解析您应用的直接依赖。
启用时,此标志让您选择退出新行为,并恢复到 SDK 54 之前的行为,仅搜索您应用的直接依赖项以查找 React Native 模块。此选项在解析 Expo 模块时不予考虑。
CLI 命令
search
此命令由构建系统调用以在自动链接的第一阶段解析 Expo 模块。其实现与所有平台共享。 search 的输出将包含每个包的 duplicates 列表(如果找到任何重复)。
- npx expo-modules-autolinking search上述命令返回一个 JSON 格式的对象,包含 Expo 自动链接找到的 Expo 模块:
{ "expo-random": { "path": "/absolute/path/to/node_modules/expo-random", "version": "13.0.0", "config": { // `expo-module.config.json` 的内容 }, "duplicates": [ // 此模块的冲突重复项列表(优先级较低) ] } // 更多模块... }
resolve
此命令在自动链接的第二阶段由构建系统调用。它输出每个 Expo 模块的更多(特定平台)详细信息,例如 build.gradle 或 podspec 文件的路径和需要链接的模块类。
- npx expo-modules-autolinking resolve --platform <apple|android>例如,使用 --platform apple 选项,它以 JSON 格式返回一个对象,其中包含模块和该平台的解析详细信息的数组:
{ "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 } // 更多模块... ] }
verify
验证自动链接的原生模块,通过检查重复项。对于每个冲突的重复安装,会显示警告。
- npx expo-modules-autolinking verify传递 --verbose 选项以列出所有自动链接的原生模块。
react-native-config
此命令在自动链接 React Native 模块时由构建系统调用。它输出每个 React Native 模块的更多特定平台详细信息,例如 gradle 或 podspec 文件的路径。
- npx expo-modules-autolinking react-native-config例如,使用 --platform ios 选项,它返回一个 react-native.config.js 输出格式的对象,包含每个 React Native 依赖项的信息及其 React Native 安装的路径。
{ "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": [] } } } // 更多模块... } }
依赖解析和冲突
重要 这是从 SDK 54 开始的实验性功能。
自动链接和 Node 解析有不同的目标,而 Node 和 Metro 中的模块解析算法有时可能会发生冲突。如果您的应用包含由自动链接选中的原生模块的重复安装,则您的 JavaScript 包可能同时包含该原生模块的两个版本,而自动链接和您的原生应用中仅包含一个版本。这可能导致运行时崩溃,并存在不兼容的风险。
这是一个在孤立依赖或单体仓库中特别常见的问题,您应该 检查并去重您的依赖中的原生模块。
从 SDK 54 开始,您可以在 应用配置 中将 experiments.autolinkingModuleResolution 设置为 true,以自动将自动链接应用于 Expo CLI 和 Metro 打包程序。这将强制 Metro 解析的依赖项与 自动链接 解析的原生模块相匹配。
常见问题
如何在我的应用中设置自动链接?
所有使用 npx create-expo-app 命令创建的项目都已配置为使用 Expo 自动链接。如果您的项目是使用其他工具创建的,请参见 安装 Expo 模块,以确保您的项目包含所有必要的更改。
我需要在我的模块中有什么才能使其支持自动链接?
模块解析算法仅搜索包含 Expo 模块配置 文件(expo-module.config.json)的包,该文件位于根目录,位于 package.json 文件旁边。
还需要在 platforms 数组中包含支持的平台——如果进行自动链接算法运行的平台不在此数组中,则在搜索结果中将被跳过。
与 React Native 社区 CLI 自动链接有何不同?
- Expo 自动链接内置支持单体仓库、包管理器工作区、传递依赖和孤立依赖安装。
- 它的速度也显著更快,尽管模块解析算法更复杂,以便更可靠并匹配 Node.js 的模块解析。
- Expo 模块解析还能够检测重复依赖,这是单体仓库中常见的问题。
- 最后但同样重要的是,它与 Expo 模块 API 提供的功能集成良好,并支持 React Native 模块。
选择退出 Expo 自动链接以用于 React Native 模块
自 SDK 52 起,Expo 自动链接默认替代了 React Native 社区 CLI 自动链接。如果您希望使用 React Native 社区 CLI 的自动链接,请设置环境变量 EXPO_USE_COMMUNITY_AUTOLINKING=1 并将 @react-native-community/cli 添加为您项目的开发依赖。
设置此环境变量后,将不会使用 Expo 自动链接来解析 React Native 模块,但将继续自动链接 Expo 模块。