Skip to content
雲里
里雾

Expo Config Plugins 系统

expo 开发 更新于 2026/4/13

本页说明 Expo Config Plugins 如何通过在 expo prebuild 阶段运行 JS 函数来自动生成原生配置文件,解决 Managed 工作流无法直接修改 Info.plistAndroidManifest.xml 等原生文件的问题。

问题背景:Managed 工作流的两难

Expo 的 Managed 工作流核心承诺是:你不需要碰原生代码。你只写 JS/TS,EAS 云端负责构建原生 App。

但现实是:几乎所有非平凡的功能都需要某种程度的原生配置——

如果 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.plistAppDelegate、Xcode project;Android 的 AndroidManifest.xmlbuild.gradlestrings.xml 等)。

app.json 里使用 plugin:

{
  "expo": {
    "plugins": [
      [
        "expo-splash-screen",
        {
          "image": "./assets/splash.png",
          "backgroundColor": "#1a1a2e",
          "resizeMode": "contain"
        }
      ]
    ]
  }
}

expo prebuild 时,expo-splash-screen 的 Config Plugin 会:

你不需要打开 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.plistbuild.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,这要求理解原生文件结构。

参见

参考

版本说明