
为现有 React Native 项目接入 expo-modulesinstall-expo-modules 迁移指南【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expoinstall-expo-modules是 Expo 官方仓库中提供的一键式迁移工具专门帮助已经存在的、通过 React Native Community CLI 创建的裸 React Native 项目平滑接入 expo-modules 与新版本 Expo SDK。本文将以该工具在 packages/install-expo-modules 中的真实实现为骨架完整讲解其使用方法、命令行参数、底层改动了哪些原生文件以及迁移后如何继续安装你需要的 Expo 模块让你在读完本文后能够安全、可回滚地将任意 RN 项目升级为支持 Expo 生态的工程。适用场景与核心价值如果你手头有一个不是通过create-expo-app创建、也没有任何 Expo 依赖的裸 React Native 项目典型特征项目由react-native init或react-native-community/cli脚手架生成原生目录android/与ios/是直接暴露、可自由修改的你通常面临两个痛点手动把expo包、expo-modules-core、autolinking 机制逐一接入原生工程步骤繁琐且容易漏改各版本 React Native 对应的 Expo SDK 版本各不相同版本匹配需要查阅大量资料。install-expo-modules把这两件事自动化了它在你的项目根目录执行一条命令即可完成依赖安装与原生文件改造。从源码结构看该工具本质上是一组基于expo/config-plugins的配置插件mods的编排器入口文件 src/index.ts 会依次执行 Android、iOS 与 CLI 集成的各类修改最后安装依赖并在 macOS 上执行pod install。快速开始一条命令完成迁移在项目的根目录即包含package.json、android/、ios/的目录执行npx install-expo-modules工具会自动向上查找包含package.json的目录作为项目根见 src/utils/projectRoot.ts 中的normalizeProjectRootAsync并检测根目录下是否存在android/与ios/子目录从而决定只改 Android、只改 iOS 还是两端都改。执行过程中工具可能会弹出若干交互式确认框详见下文「交互式确认机制」一节。迁移完成后你便可以像在 Expo 项目中一样安装其他需要的 Expo 模块例如expo install expo-device注意这里expo install命令来自expo-cli。如果全局还没有安装 expo-cli需要先安装npm -g install expo-cli使用expo install而不是直接npm install的好处是它会自动匹配当前 SDK 版本所对应的模块版本避免版本冲突。命令行选项install-expo-modules使用commander解析参数完整的命令行用法源码见 src/index.ts如下npx install-expo-modules [project-directory] [options]选项说明[project-directory]目标项目目录。省略时默认使用当前工作目录process.cwd()-s, --sdk-version version指定要安装的 Expo SDK 版本。传入的版本必须存在于内置版本映射表中否则会抛出Unsupported sdkVersion: version错误--non-interactive禁用所有交互式提示以非交互模式运行。此时对 AGP 升级、iOS 部署目标升级、Expo CLI 集成等默认全部视为同意并打印黄色警告日志其中--sdk-version的解析逻辑在getSdkVersionInfo()中若显式传入则调用getVersionInfo()精确查找该 SDK 版本未传入时则调用getDefaultSdkVersion()根据项目node_modules中react-native/package.json的实际版本自动匹配最合适的 SDK详见下文「版本自动匹配机制」。迁移工具到底改了什么逐平台源码拆解README 明确列出该工具为项目做的四件事安装expo包、修改项目文件以适配 expo-modules、必要时提升 iOS 最低部署版本、最后执行pod install。下面结合源码逐项展开。1. 安装 expo 核心包工具会通过项目自带的包管理器npm / yarn / pnpm由 expo/package-manager 自动识别安装expo包。安装逻辑在 src/utils/packageInstaller.ts 中首先尝试安装正式发布版本例如expo~45.0.0若正式版本安装失败则回退安装预发布prerelease区间例如expo45.0.0-0 46.0.0用于覆盖 beta 测试场景。该包是后续一切工作的基础expo包不仅提供 JS API还承载了 React Native 的 autolinking 机制与 config plugins 所需的元数据。2. Android 端原生改造Android 侧由 src/plugins/android/withAndroidModules.ts 编排依次应用四个子插件MainApplication 改造withAndroidModulesMainApplication.ts——根据目标 SDK 版本对MainApplication.kt/.java做多种模式的适配对 RN 0.71 引入的DefaultReactNativeHost用ReactNativeHostWrapper包裹对 SDK 51 的getDefaultReactHost()调用替换为 Expo 的工厂方法SDK 55 使用ExpoReactHostFactory.getDefaultReactHost()SDK 51~54 使用ReactNativeHostWrapper.createReactHost()对传统ReactNativeHost与 new architecture 的MainApplicationReactNativeHost同样包裹一层ReactNativeHostWrapper补充ApplicationLifecycleDispatcher的 import并在onCreate中调用ApplicationLifecycleDispatcher.onApplicationCreate(this)在onConfigurationChanged中派发配置变更事件。MainActivity 改造withAndroidModulesMainActivity.ts——目标是把 Activity 委托包装成ReactActivityDelegateWrapper若尚未覆写createReactActivityDelegate()则新增覆写并返回ReactActivityDelegateWrapper若已覆写RN 0.71 常见则把DefaultReactActivityDelegate/MainActivityDelegate/ReactActivityDelegate的实例化代码原位替换为 Wrapper 包裹版本这些模式分支分别对应 RN 0.64、0.68、0.71、0.73 等不同历史版本测试夹具位于 src/plugins/android/tests/fixtures可以看到覆盖了MainActivity-anonymous-delegate、MainActivity-rn064、MainActivity-rn068、MainActivity-rn071、MainActivity-rn073等多样化的既有代码形态。settings.gradle 改造withAndroidSettingsGradle.ts——SDK 53 会在pluginManagement中注入基于expo-modules-autolinking/package.json解析路径的includeBuild在plugins块中加入id(expo-autolinking-settings)并把ex.autolinkLibrariesFromCommand()升级为使用expoAutolinking.rnConfigCommand最后追加expoAutolinking.useExpoModules()、useExpoVersionCatalog()与 RN Gradle 插件的includeBuild。对 SDK 52 及更早版本则走updateAndroidSettingsGradleSdk52分支追加useExpoModules()的 autolinking 脚本。项目级 build.gradle 改造withAndroidGradles.ts——SDK 53 会在根build.gradle中追加apply plugin: expo-root-projectGroovy 语法或在plugins块中注册id(expo-root-project)Kotlin DSL 语法。3. iOS 端原生改造iOS 侧由 src/plugins/ios/withIosModules.ts 编排同样包含多个子插件AppDelegate 改造withIosModulesAppDelegate.ts——依据 AppDelegate 的语言Objective-C / Objective-C / Swift与 SDK 版本做不同处理Objective-C 实现在application:didFinishLaunchingWithOptions:中补插[super application:application didFinishLaunchingWithOptions:launchOptions];SDK 44 时把RCTBridge/RCTRootView/RCTAppSetupDefaultRootView/UIViewController的创建统一替换为reactDelegate的对应工厂方法ObjC 头文件为interface AppDelegate补#import Expo/Expo.h并把父类替换为EXAppDelegateWrapperRN 0.71 时替代RCTAppDelegate更早版本替代UIResponderSwift 实现为import Expo补 importSDK 55 使用internal import以兼容 Swift 6把父类替换为ExpoAppDelegate为didFinishLaunchingWithOptions补override与super.application(...)调用并把RCTReactNativeFactory替换为ExpoReactNativeFactory、RCTDefaultReactNativeFactoryDelegate替换为ExpoReactNativeFactoryDelegateSwift Bridging Header若工程使用了 Swift 桥接头文件则为其追加#import Expo/Expo.h。Podfile 改造withIosModulesPodfile.ts——对ios/Podfile追加requireexpo 包的 autolinking 脚本require.resolve(expo/package.json)定位在 app target 中插入use_expo_modules!SDK 52 时把use_native_modules!的调用替换为基于expo-modules-autolinking的react-native-config --json --platform ios命令并支持通过环境变量EXPO_USE_COMMUNITY_AUTOLINKING1回退到社区版 autolinkingSDK 44~51 时在post_integrate钩子中补插expo_patch_react_imports!(installer)以修正 React import。iOS 最低部署版本提升withIosDeploymentTarget.ts——这是 README 中特别提到的一点expo-modules 的最低 iOS 版本要求通常高于 React Native core 的要求。该插件会同时修改两处Podfile中的platform :ios, x.y或min_ios_version_supported占位符行若当前值低于目标版本则提升Xcode 工程pbxproj中所有XCBuildConfiguration的IPHONEOS_DEPLOYMENT_TARGET构建设置。其中min_ios_version_supported占位符的实际值会从react-native/scripts/cocoapods/helpers.rb或react-native/scripts/react_native_pods.rb中读取见lookupReactNativeMinIosVersionSupported。此外还会通过 withSwiftVersion.ts 将 Swift 版本统一设置为 5.0含为缺失SWIFT_VERSION的测试 target 补上该设置。4. 最后一步pod install全部文件修改完成并安装expo包之后工具会在 macOSprocess.platform darwin上自动执行pod install以更新 iOS 的链接模块见 src/utils/packageInstaller.ts 中的installPodsAsync。这也意味着在 Linux/Windows 上运行该工具不会尝试执行 CocoaPods之后需自行在 iOS 环境中执行pod install。版本自动匹配机制工具内置了一张「Expo SDK 版本 ↔ React Native 版本 ↔ iOS 最低部署目标 ↔ Android Gradle Plugin 版本」的映射表位于 src/utils/expoVersionMappings.tsExpoVersionMappings数组。表中每条记录包含字段含义expoPackageVersion要安装的expo包版本号sdkVersion对应的 Expo SDK 版本iosDeploymentTarget该 SDK 要求的最低 iOS 部署版本reactNativeVersionRange兼容的 React Native 版本范围semver 区间androidAgpVersion该 SDK 要求的最低 Android Gradle Plugin 版本部分 SDK 提供supportCliIntegration该 SDK 是否支持 Expo CLI 集成较新的 SDK 均为true例如表中显示SDK 56 对应 RN~0.85.0、iOS 部署目标16.4SDK 55 对应 RN~0.83.0、iOS15.1SDK 52 对应 RN 0.76.0 0.78.0而 SDK 48 额外要求 AGP7.4.1。默认匹配逻辑getDefaultSdkVersion会读取项目node_modules中的react-native/package.json版本号对 RNTV 风格的版本字符串会先按-切分取主版本段再用semver.satisfies在映射表中找到第一条满足条件的记录并打印类似Defaulting to SDK 52.0.0 for react-native version 0.76.5的日志。如果找不到匹配则抛出Unable to find compatible Expo SDK version错误。交互式确认机制为避免破坏性修改工具在改动两个高风险项之前会先征得用户同意实现于 src/index.ts 的promptUpgradeAgpVersionAsync与promptUpgradeIosDeployTargetAsyncAndroid Gradle Plugin 升级当项目android/build.gradle中com.android.tools.build:gradle版本低于目标 SDK 要求时弹出确认框提示「本工具将把你的 AGP 版本修改为 x.y.z」iOS 部署目标升级当Podfile的platform :ios低于目标 SDK 要求时弹出确认框提示「本工具将把你的 iOS 部署目标修改为 x.y」Expo CLI 集成工具还会询问是否安装 Expo CLI 集成promptCliIntegrationAsync官方推荐安装以获得最佳体验不使用可能导致部分功能不符合预期。在--non-interactive模式下以上提示全部跳过并默认继续仅输出黄色警告日志。若用户对 AGP 或部署目标的升级选择「否」整个流程会直接中止return不做任何修改。可选的 Expo CLI 集成做了什么若你确认安装 Expo CLI 集成由 src/plugins/cli/withCliIntegration.ts 实现工具会额外做一批面向expo-cli/expo/cli工作流的改造Androidapp/build.gradle注入entryFile通过expo/scripts/resolveAppEntry解析入口、cliFilerequire.resolve(expo/cli)与bundleCommand export:embedAndroidMainApplication与 iOSAppDelegate把 JS 入口从index替换为.expo/.virtual-metro-entryBabel 配置把module:metro-react-native-babel-preset或react-native/babel-preset替换为babel-preset-expo并在依赖中安装babel-preset-expometro.config.js把getDefaultConfig的来源从react-native/metro-config替换为expo/metro-configXcode 工程改写Start Packager与Bundle React Native code and images两个 Shell Script 构建阶段使用 Expo CLI 的打包命令与包管理器脚本.gitignore追加.expo、dist/、web-build/等 Expo 相关忽略项。迁移的验证与回滚README 特别建议如果项目由 git 管理可以随时用git diff审查工具对你的项目做了哪些改动。这是验证迁移正确性的最直接手段——你可以在运行命令前先git status确认工作区干净迁移后逐一 diff 查看MainActivity、MainApplication、Podfile、AppDelegate、Gradle 文件等改动是否符合预期。若发现异常直接git checkout .即可回滚因为工具在安装expo依赖前已完成文件修改。为 install-expo-modules 贡献代码如果你是 Expo 仓库的贡献者想要修改本工具并用一个 RNC CLI 项目验证改动README 给出了开发流程在仓库根目录运行pnpm watch以 watch 模式持续构建本项目修改源码建议同时为改动编写单元测试本包使用 jest测试目录见 src/plugins/android/tests与 src/plugins/ios/tests覆盖了各 RN 版本夹具的对比快照在 RNC CLI 测试项目中直接运行构建产物验证node path_to_expo/packages/install-expo-modules/bin/install-expo-modules.js .其中path_to_expo指本仓库在本地克隆后的路径。单测、lint、类型检查分别对应pnpm test、pnpm lint、pnpm typecheck脚本见 packages/install-expo-modules/package.json。小结install-expo-modules的价值在于把「裸 RN 项目 → Expo 兼容工程」这一繁琐迁移过程封装为一条命令并通过 config plugins 机制保证修改的可组合性与可审查性。理解其背后的版本映射表、平台级子插件与交互确认机制能让你在迁移遇到问题时快速定位是版本不匹配查expoVersionMappings.ts、还是某个原生文件形态未被识别查对应 fixtures 与测试。迁移完成后即可无缝使用expo install module接入 packages 目录下的各类 Expo 模块例如 expo-device、expo-camera、expo-image 等享受 Expo 生态带来的能力扩展。【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考