本页说明 Expo Config Plugins 如何通过在 expo prebuild 阶段运行 JS 函数来自动生成原生配置文件,解决 Managed 工作流无法直接修改 Info.plist、AndroidManifest.xml 等原生文件的问题。
问题背景:Managed 工作流的两难
Expo 的 Managed 工作流核心承诺是:你不需要碰原生代码。你只写 JS/TS,EAS 云端负责构建原生 App。
但现实是:几乎所有非平凡的功能都需要某种程度的原生配置——
- 推送通知需要在
Info.plist添加权限声明 - 启动页需要在 iOS
LaunchScreen.storyboard和 Androidstyles.xml配置 - 某些 SDK 需要在
build.gradle添加依赖或修改compileSdkVersion
如果 Managed 工作流的答案是”这些不支持,自己 eject 到 Bare 工作流”,那它的价值就大打折扣。Config Plugins 是 Expo 给出的解法:用声明式配置代替手工改原生文件。
Config Plugin 是什么
Config Plugin 本质上是一个函数,签名如下:
type ConfigPlugin<Options = void> = (
config: ExpoConfig,
options?: Options
) => ExpoConfig
它接收当前的 Expo 配置对象,对其修改后返回。expo prebuild 阶段,Expo 会收集所有 plugin 函数,依次执行,最终把修改后的配置写入原生文件(iOS 的 Info.plist、AppDelegate、Xcode project;Android 的 AndroidManifest.xml、build.gradle、strings.xml 等)。
在 app.json 里使用 plugin:
{
"expo": {
"plugins": [
[
"expo-splash-screen",
{
"image": "./assets/splash.png",
"backgroundColor": "#1a1a2e",
"resizeMode": "contain"
}
]
]
}
}
expo prebuild 时,expo-splash-screen 的 Config Plugin 会:
- iOS:修改
LaunchScreen.storyboard,在Info.plist里写入背景色 - Android:修改
res/values/styles.xml,把图片复制到res/drawable/
你不需要打开 Xcode 或 Android Studio,不需要知道 storyboard 的 XML 格式。
expo prebuild 的位置
app.json(声明 plugins)
↓
expo prebuild
↓
执行所有 Config Plugin 函数
↓
生成/修改 ios/ 和 android/ 目录下的原生文件
↓
xcodebuild / gradlew 构建原生 App
prebuild 生成的 ios/ 和 android/ 目录是可以被 gitignore 的(Expo 推荐在 Managed 工作流中不提交这两个目录,每次构建前重新生成)。这和 Bare 工作流的核心区别之一——Bare 工作流把原生目录作为代码库的一部分长期维护。
和 Bare 工作流的对比
| Managed(Config Plugins) | Bare 工作流 | |
|---|---|---|
| 原生文件 | 自动生成,可 gitignore | 手工维护,必须提交 |
| 配置方式 | app.json 声明式 | 直接编辑 Info.plist、build.gradle |
| 原生代码能力 | 通过 plugin 间接控制 | 完全自由 |
| 升级成本 | 重新 prebuild 即可 | 手工合并原生变更 |
| 适合场景 | 标准功能 + 主流三方库 | 深度定制原生代码 |
选 Managed + Config Plugins 的核心理由:升级成本低。Expo SDK 升级时,你只需要更新 app.json 里的 plugin 版本和 expo 版本,重新 prebuild,原生代码自动重新生成——不需要手工处理 iOS/Android 的 breaking changes。Bare 工作流每次 RN 升级都可能需要手工 diff 和合并数百行原生代码变更。
自定义 Config Plugin
当你需要的原生配置没有现成 plugin 时,可以写自己的:
// plugins/withCustomPermission.ts
import { ConfigPlugin, withInfoPlist } from '@expo/config-plugins'
export const withCustomPermission: ConfigPlugin = (config) => {
return withInfoPlist(config, (plistConfig) => {
// withInfoPlist 是 Expo 提供的 modifier helper,封装了 Info.plist 的读写
plistConfig.modResults['NSCameraUsageDescription'] =
'需要相机权限以扫描二维码'
return plistConfig
})
}
// app.json
{
"expo": {
"plugins": ["./plugins/withCustomPermission"]
}
}
Expo 提供了一组 modifier helpers(withInfoPlist, withAndroidManifest, withGradleProperties 等),封装了常用原生文件的读写,让你可以用 JS 操作它们而不需要手写 XML/plist。
面试视角
“Expo Config Plugins 解决了什么问题?”
它解决了 Managed 工作流无法处理原生配置的问题,通过在构建时运行 JS 函数来生成原生代码,把”手工改原生文件”变成”声明式配置”。核心价值是降低了 RN 升级成本——原生代码可以重新生成而不是手工维护。代价是:如果你的需求超出现有 plugin 的能力,需要自己写 plugin,这要求理解原生文件结构。
参见
- Expo SDK 54 特性
参考
版本说明
- 本页基于 2026-04-13 调研结果整理,适用范围以当前工具版本为准。