new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Expo & React Native · all subjects

config-plugins

207 notes in this subject, read out of this brain and free to use. This is page 2 of 4.

Config plugin structure and entry point

A config plugin is referenced in the `plugins` property of the app config file and is made up of one or more plugin functions. The top-level config plugin is the entry point and is conventionally named using the pattern `with<Plugin Name>`, for example `withMyPlugin`.

Plugin function definition

Plugin functions are one or more functions inside a config plugin that wrap the underlying logic of performing platform-specific modifications. Technically, plugin functions look just like the function for the top-level plugin itself and could be used as a plugin independently. Breaking plugins into smaller functions is helpful for testing and debugging.

Mod plugin function and mods

Mod plugin functions are wrapper functions from the `expo/config-plugins` library that provide a safe way to modify native files using mods. Developers use these functions instead of underlying mods. Mods are the underlying platform-specific modifiers like `mods.android.manifest` and `mods.ios.infoplist` that directly modify native project files during prebuild.

Config plugin uses and benefits

Config plugins can add native configuration not included by default. They can generate app icons, set the app name, configure AndroidManifest.xml and Info.plist, and perform other native modifications. In CNG projects, config plugins allow modification of native projects in a predictable way by consolidating changes into a configuration file and applying them when running `npx expo prebuild`. This avoids the need to manually update native files.

Config plugin synchronous behavior

Plugins are synchronous functions that accept an ExpoConfig and return a modified ExpoConfig. In rare cases, plugins can also be asynchronous if available methods to communicate with native projects are asynchronous, but they will not be performant. Plugins are always evaluated during the app config evaluation phase.

Config plugin naming convention

Plugins should be named using the convention `with<Plugin Functionality>`. For example, `withFacebook` or `withMyPlugin`.

Why avoid manual native project modifications in CNG

In Continuous Native Generation projects, it is best to avoid modifying native projects manually because you cannot regenerate them safely without potentially overwriting manual modifications. Config plugins provide the recommended way to consolidate native project changes into a configuration file.

Dynamic app config required for function-based plugins with parameters

Using a dynamic app config (app.config.js or app.config.ts instead of app.json) is required when you want to create or use a function-based config plugin that accepts parameters. Dynamic app config is not required for simple config plugins.

Config plugin hierarchy: creating and using plugins

Config plugins follow a hierarchy: creating a config plugin, using parameters with a config plugin, and chaining multiple config plugins together. The guide focuses on learning the first two parts of this hierarchy.

ConfigPlugin and withAndroidManifest import source

ConfigPlugin and withAndroidManifest are imported from 'expo/config-plugins'. withAndroidManifest is an async mod plugin that accepts a config and a data object and modifies the value before returning an object.

ConfigPlugin and withInfoPlist import source

ConfigPlugin and withInfoPlist are imported from 'expo/config-plugins'. withInfoPlist is an async mod plugin that accepts a config and a data object and modifies the value before returning an object.

Add meta-data to AndroidManifest using config plugin

To add meta-data to the AndroidManifest.xml file, access mainApplication['meta-data'] array, ensure it exists by initializing if necessary, then push an object with a $ property containing the android:name and android:value attributes.

Add custom key to Info.plist using config plugin

To add a custom key to Info.plist, assign the value directly to config.modResults with the key name, for example: config.modResults.HelloWorldMessage = message.

TypeScript support in config plugins requires tsx parser

To use TypeScript in config plugins, install the 'tsx' library as a dev dependency using npm/yarn/pnpm/bun, then add 'import "tsx/cjs";' at the top of app.config.ts. This allows Node.js to parse TypeScript files from the plugins directory.

Config plugin parameter passing pattern

To allow a config plugin to accept parameters, define a type for the options object (e.g., type AndroidProps = { message?: string }), declare the config plugin as ConfigPlugin<AndroidProps>, add an options parameter with a default empty object, and use options.propertyName with a fallback default value.

Pass parameters to config plugin in app.config.ts

To pass parameters to a config plugin in app.config.ts, use array syntax: pass the plugin path as the first element and an object with parameters as the second element, for example: ["./plugins/withPlugin.ts", { message: "Custom message" }].

Chaining config plugins execution order

Config plugins can be chained together by passing an array of plugins to the plugins array property in app.config.ts. Each plugin runs in the order it appears, with the output of one plugin becoming the input for the next. This is supported in both TypeScript and JSON app config formats.

withPlugins method for readable plugin chaining

The withPlugins method from 'expo/config-plugins' can be used to chain plugins together in a readable way instead of nested function calls. It takes a config object and an array of plugin/options pairs, executes them in order, and is especially useful when the plugins array is long or has complex configuration.

withPlugins syntax for plugins with and without parameters

When using withPlugins, pass plugins as [pluginFunction, parameter] for plugins with parameters, or just pluginFunction for plugins without parameters. Example: withPlugins(config, [[withFoo, 'input 1'], [withBar, 'input 2'], withDelta])

Installing Expo config plugins from npm

Expo config plugins are usually included in Node.js modules and can be installed like other libraries using npm, yarn, pnpm, or bun. For example, expo-camera has a config plugin that adds camera permissions to AndroidManifest.xml and Info.plist.

Using config plugin in app.json

To use a config plugin from an Expo library in app.json, add the plugin name to the plugins array: {"expo": {"plugins": ["expo-camera"]}}. For plugins that accept options, use array syntax: [["expo-camera", {"cameraPermission": "Allow $(PRODUCT_NAME) to access your camera."}]]

Prebuild compiles mods and modifies native files

Running 'npx expo prebuild' compiles the mods and changes native files. Changes don't take effect until you rebuild the native project. For CNG (Continuous Native Generation) projects without native directories, config plugins are applied during the prebuild step in EAS Build or when running 'npx expo prebuild|android|ios' locally.

Expo library config plugin documentation location

For every Expo library that has a config plugin, information about the plugin can be found in the library's API reference documentation. For example, expo-camera library has a config plugin section in its SDK documentation.

Verify config plugin modifications with prebuild

To see custom config applied in native projects, run 'npx expo prebuild --clean --no-install'. Then verify the modifications by opening android/app/src/main/AndroidManifest.xml and ios/<your-project-name>/Info.plist files to confirm the changes were applied correctly.

Plugin resolution order for packages

When you import a plugin package, files are resolved in this specific order: (1) app.plugin.js in package root (highest priority), (2) Package's main entry from package.json, (3) Direct internal imports (not recommended and bypasses standard resolution).

Avoid direct internal imports in plugins

Avoid importing module internals directly as it bypasses the standard resolution order and may break in future updates.

app.plugin.js transpilation benefits

The app.plugin.js approach is preferred for config plugins because it allows different transpilation settings from the main package code. Node environments often require different transpilation presets compared to Android, iOS, or web JS environments (for example, `module.exports` instead of `import/export`).

iOS mod plugins available

The following mod plugins are available for iOS in the expo/config-plugins library: | Default iOS mod | Mod plugin | Dangerous | Description | |---|---|---|---| | `mods.ios.infoPlist` | `withInfoPlist` | No | Modify ios/<name>/Info.plist as JSON (parsed with @expo/plist) | | `mods.ios.entitlements` | `withEntitlementsPlist` | No | Modify ios/<name>/<product-name>.entitlements as JSON (parsed with @expo/plist) | | `mods.ios.expoPlist` | `withExpoPlist` | No | Modify ios/<name>/Expo.plist as JSON (Expo updates config for iOS) (parsed with @expo/plist) | | `mods.ios.xcodeproj` | `withXcodeProject` | No | Modify ios/<name>.xcodeproj as an XcodeProject object (parsed with xcode) | | `mods.ios.podfile` | `withPodfile` | No | Modify ios/Podfile as a string | | `mods.ios.podfileProperties` | `withPodfileProperties` | No | Modify ios/Podfile.properties.json as JSON | | `mods.ios.appDelegate` | `withAppDelegate` | Yes | Modify ios/<name>/AppDelegate.m as a string |

Dangerous mods use regex and should be avoided

Dangerous modifications rely on regular expressions (regex) to modify application code, which may cause the build to break. Regex mods are also difficult to version and should be used sparingly. Always opt toward using application code to modify application code (for example, Expo Modules native API) instead of dangerous mods.

Mods definition and purpose

Mods (short for modifiers) are asynchronous functions used by config plugins to modify native project files during the prebuild process. They allow you to make changes to platform-specific files such as AndroidManifest.xml and Info.plist without manually editing them. Mods execute only during the syncing phase of `npx expo prebuild`. They accept a config and a data object, then modify and return both as a single object.

Mods cannot be accessed via Updates.manifest

Mods are omitted from the manifest and cannot be accessed via Updates.manifest. Mods exist solely for the purpose of modifying native project files during code generation.

Mods object structure in app config

Mods are platform-specific and should always be added to a platform-specific object. The mods object is different from the rest of the app config because it does not get serialized, which means you can use it to perform actions during code generation.

modResults property in mod plugins

The modResults object contains the data to modify and return when a mod plugin is executed. Its type depends on the mod that is being used.

modRequest property structure

The modRequest object contains the following properties supplied by the mod compiler: | Property | Type | Description | |---|---|---| | `projectRoot` | string | Project root directory for the universal app | | `platformProjectRoot` | string | Project root for the specific platform | | `modName` | string | Name of the mod | | `platform` | ModPlatform | Name of the platform used in the mods config | | `projectName` | string | (iOS only) The path component used for querying project files. For example, `projectRoot/ios/[projectName]/` |

Example mod plugin implementation

```ts my-config-plugin.ts import { ConfigPlugin, withXcodeProject, IOSConfig } from 'expo/config-plugins'; const withCustomProductName: ConfigPlugin<string> = (config, customName) => { return withXcodeProject( config, async (config) => { config.modResults = IOSConfig.Name.setProductName({ name: customName }, config.modResults); return config; } ); }; // Usage: const config = { name: 'my app', }; export default withCustomProductName(config, 'new_name'); ``` This example shows how to create a config plugin that updates the Xcode Project's product name using the withXcodeProject mod plugin.

Mod plugins vs mods: when to use each

Mod plugins are wrappers around top-level mods that are made available from the expo/config-plugins library. When developing a feature that requires mods, you should use mod plugins instead of interacting with top-level mods directly. You do not use mods as top-level functions (for example `with.android.manifest`) directly in your config plugin.

Android mod plugins available

The following mod plugins are available for Android in the expo/config-plugins library: | Default Android mod | Mod plugin | Dangerous | Description | |---|---|---|---| | `mods.android.manifest` | `withAndroidManifest` | No | Modify android/app/src/main/AndroidManifest.xml as JSON (parsed with xml2js) | | `mods.android.strings` | `withStringsXml` | No | Modify android/app/src/main/res/values/strings.xml as JSON (parsed with xml2js) | | `mods.android.colors` | `withAndroidColors` | No | Modify android/app/src/main/res/values/colors.xml as JSON (parsed with xml2js) | | `mods.android.colorsNight` | `withAndroidColorsNight` | No | Modify android/app/src/main/res/values-night/colors.xml as JSON (parsed with xml2js) | | `mods.android.styles` | `withAndroidStyles` | No | Modify android/app/src/main/res/values/styles.xml as JSON (parsed with xml2js) | | `mods.android.gradleProperties` | `withGradleProperties` | No | Modify android/gradle.properties as a Properties.PropertiesItem[] | | `mods.android.mainActivity` | `withMainActivity` | Yes | Modify android/app/src/main/<package>/MainActivity.java as a string | | `mods.android.mainApplication` | `withMainApplication` | Yes | Modify android/app/src/main/<package>/MainApplication.java as a string | | `mods.android.appBuildGradle` | `withAppBuildGradle` | Yes | Modify android/app/build.gradle as a string | | `mods.android.projectBuildGradle` | `withProjectBuildGradle` | Yes | Modify android/build.gradle as a string | | `mods.android.settingsGradle` | `withSettingsGradle` | Yes | Modify android/settings.gradle as a string |

Plugin module resolution: local vs standalone

There are two fundamental approaches to implementing plugins: (1) Plugins defined within your app's project live locally and are easy to customize and maintain alongside your app code, ideal for project-specific customizations. (2) Standalone package plugins exist as separate packages published to npm, ideal for reusable plugins shared across multiple projects. Both provide the same capabilities for modifying native configuration but differ in structure and import.

Local plugin file import

You can quickly create a plugin in your project by creating a JavaScript/TypeScript file and using it in your config like any other JS/TS file. The plugin file should contain a bare minimum function: `module.exports = ({ config }: { config: ExpoConfig }) => {};`

Inline function plugins in app config

Expo config objects support passing functions directly to the plugins array. This is useful for testing or using a plugin without creating a file. Functions passed this way will be serialized with their function name in the manifest.

Standalone package plugin entry point: app.plugin.js

For standalone npm packages whose sole purpose is to provide a config plugin, you can export your plugin using app.plugin.js. This file is the entry point for custom plugins in dedicated config plugin packages.

Standalone package plugin with main entry point

When a config plugin is part of a Node module without an app.plugin.js file, the package's main entry point from package.json is used to load the config plugin.

expo-font config plugin limitations

The expo-font config plugin does not work with Expo Go because it requires creating a development build.

Font family naming on iOS with config plugin

On iOS, the expo-font config plugin always extracts the font family name from the font file itself, regardless of the file name or configuration method used.

Google Fonts via config plugin file path

When embedding Google Fonts using the expo-font config plugin, the path to the font file is defined relative to the node_modules directory. For example, for @expo-google-fonts/inter, use path like node_modules/@expo-google-fonts/inter/900Black/Inter_900Black.ttf.

Google Fonts via config plugin platform-specific naming

When using Google Fonts with the expo-font config plugin, on Android use the font file name (e.g., 'Inter_900Black'), and on iOS use the font and its weight name (PostScript name, e.g., 'Inter-Black'). Use Platform.select() to choose the correct font family name for each platform.

expo-font config plugin object syntax properties

When using object syntax with the expo-font config plugin on Android, you can specify: fontFamily (required), weight (optional), and style (optional, defaults to 'normal'). These properties embed fonts as native XML resources on Android.

expo-font config plugin supported formats

The expo-font config plugin supports ttf and otf for both Android and iOS. On iOS only, woff and woff2 are also supported.

expo-font config plugin benefits

Using the expo-font config plugin for embedding fonts provides these benefits: fonts are available immediately when the app starts on a device, no additional code required to load fonts asynchronously at app startup, and fonts are consistently available across all devices where the app is installed because they're bundled within the app.

Font family naming on Android with config plugin

When using the expo-font config plugin on Android, if you provide font file paths as an array without object syntax, the file name (without extension) becomes the font family name. For example, a file named FiraSans-MediumItalic.ttf becomes fontFamily 'FiraSans-MediumItalic'. When using object syntax with fontDefinitions, you provide the fontFamily explicitly.

Basic app icon configuration in app.json

Add the icon property to the app config with the local path to your app icon image: ```json { "icon": "./assets/images/icon.png" } ```

Basic splash screen configuration in app.json

Configure the splash screen in app.json under the plugins section. The expo-splash-screen plugin accepts the following properties: backgroundColor (string, required), image (string, path to splash icon), imageWidth (number), and dark (object with image and backgroundColor for dark mode support).

Splash screen configuration example

Example splash screen configuration in app.json: ```json { "expo": { "plugins": [ [ "expo-splash-screen", { "backgroundColor": "#232323", "image": "./assets/images/splash-icon.png", "dark": { "image": "./assets/images/splash-icon-dark.png", "backgroundColor": "#000000" }, "imageWidth": 200 } ] ] } } ``` This shows backgroundColor, image path, dark mode overrides, and imageWidth configuration.

Platform-specific splash screen configuration

The expo-splash-screen plugin supports android and ios properties for platform-specific configuration. You can provide different backgroundColor, image, imageWidth, and resizeMode values for each platform.

Android adaptive icon configuration

Use the android.adaptiveIcon property to configure adaptive icons for Android. Adaptive icons consist of a foreground image and background color or image. Provide the foreground image using android.adaptiveIcon.foregroundImage, optionally a monochrome image using android.adaptiveIcon.monochromeImage, and set the background with android.adaptiveIcon.backgroundColor (default is white) or android.adaptiveIcon.backgroundImage. For older Android devices without adaptive icon support, use android.icon to provide a combined single icon.

iOS app icon configuration with appearance variants

For iOS, use ios.icon to specify different icons for various system appearances. You can provide dark, light, and tinted variants: ```json { "expo": { "ios": { "icon": { "dark": "./assets/images/ios-dark.png", "light": "./assets/images/ios-light.png", "tinted": "./assets/images/ios-tinted.png" } } } } ``` When ios.icon is specified, it overrides the top-level icon key.

iOS Icon Composer .icon directory support

iOS app icons using the Icon Composer .icon directory format are supported in SDK 54 and later. You can add the output .icon directory to your project's assets directory and reference it via ios.icon property. This approach handles dark mode support automatically.

Config plugins for Expo Prebuild

Authors can configure their libraries to work with Expo Prebuild by creating a config plugin. This means you can use any library with Expo Prebuild. You can also use any custom native code with Expo Prebuild by creating a development build.

Adding custom native code to Expo projects

Expo supports adding custom native code and customizing native code (Android/Xcode projects). To use custom native code, you can create a development build and use config plugins. The Expo SDK modules are recommended when possible for easier upgrades and improved developer experience.

Migrate native customizations to app config

If the project has native modifications in the android or ios directories, configure the app config (app.json) to reflect those changes. Check if changes overlap with built-in app config fields, look up if packages require Expo config plugins, use the VS Code Expo extension to introspect changes, or develop local config plugins.

Give your agent this brain