# Expo SDK Documentation Documentation for Expo SDK libraries, app configuration files, Expo CLI, create-expo-app, and more. # create-expo A command-line tool to create a new Expo and React Native project. [](https://github.com/expo/expo/edit/main/docs/pages/more/create-expo.mdx) `create-expo-app` is a command-line tool to create and set up a new Expo and React Native project. This tool simplifies the initialization process by providing various templates to get started quickly without the need for manual configuration. ## Create a new project To create a new project, run the following command: `npx create-expo-app@latest` Running the above command will prompt you to enter the app name of your project. This app name is also used in the app config's [`name`](https://docs.expo.dev/versions/latest/config/app#name) property. `What is your app named? my-app` ## Options Uses the following options to customize the command behavior. ### `--yes` Uses the default options to create a new project. ### `--no-install` Skips installing npm dependencies or CocoaPods. ### `--template` Running `create-expo-app` with a [Node Package Manager](https://docs.expo.dev/more/create-expo#node-package-managers-support) initializes and sets up a new Expo project using the default template. You can use the `--template` option to select one of the following templates or pass it as an argument to the option. For example, `--template default`. > Looking for more templates? Check out the [`--example`](https://docs.expo.dev/more/create-expo#--example) option to initialize your project with one of the example apps that demonstrate specific features and integrations. ### `--example` Use this option to initialize a project using an example from [expo/examples](https://github.com/expo/examples). For example: * Running `npx create-expo-app --example with-router` sets up a project with the Expo Router library * Running `npx create-expo-app --example with-react-navigation` sets up a project similar to the default template, but configured with plain React Navigation library ### `--version` Prints the version number and exits. ### `--help` Prints the list of available options and exits. ## Node Package Managers support Creating a new project with `create-expo-app` also handles setting up additional configuration needed for a specific Node Package Manager. If you are migrating from one package manager to another, you've to manually carry out the additional configuration in your project. If you are using [EAS](https://docs.expo.dev/eas), you also have to configure your project for any additional required steps manually. All the additional steps for each package manager are listed below. ### npm #### Local installation npm is installed as part of Node.js installation. See [Node.js documentation](https://nodejs.org/en/download/package-manager) for installation instructions. #### EAS installation Supported by default if the project directory contains package-lock.json. ### Yarn 1 (Classic) #### Local installation Yarn 1 (Classic) is usually installed as a global dependency of npm. See [Yarn 1 documentation](https://classic.yarnpkg.com/en/docs/getting-started) for installation instructions. #### EAS installation Supported by default if the project directory contains yarn.lock. ### Yarn 2+ (Modern) #### Local installation See [Yarn documentation](https://yarnpkg.com/getting-started/install) for installation instructions. Yarn 2+ handles package management differently than Yarn 1. One of the core changes in Yarn 2+ is the [Plug'n'Play (PnP)](https://yarnpkg.com/features/pnp) node linking model that does not work with React Native. By default, a project created with `create-expo-app` and Yarn 2+ uses [`nodeLinker`](https://yarnpkg.com/features/linkers#nodelinker-node-modules) with its value set to `node-modules` to install dependencies. #### EAS installation Yarn Modern on EAS requires adding [`eas-build-pre-install` hook](https://docs.expo.dev/build-reference/npm-hooks). In your project's package.json, add the following configuration: `{ "scripts": { "eas-build-pre-install": "corepack enable && yarn set version 4" } }` ### pnpm #### Local installation Requires installing Node.js. See [pnpm documentation](https://pnpm.io/installation) for installation instructions. By default, a project created with `create-expo-app` and pnpm uses [`node-linker`](https://pnpm.io/npmrc#node-linker) with its value set to `hoisted` to install dependencies. > From SDK 54, Expo supports isolated installations, and you can delete the `node-linker` setting if you prefer to use isolated dependencies. #### EAS installation Supported by default if the project directory contains pnpm-lock.yaml. ### Bun See [Bun](https://docs.expo.dev/guides/using-bun) guide for details on creating a new Expo project with `bun`, migration from another package manager, and usage with EAS. --- # expo-cli The Expo CLI is a command-line tool that is the primary interface between a developer and other Expo tools. [](https://github.com/expo/expo/edit/main/docs/pages/more/expo-cli.mdx) The `expo` package provides a small and powerful CLI tool `npx expo` which is designed to keep you moving fast during app development. ## Highlights * [Start a server](https://docs.expo.dev/more/expo-cli#develop) for developing your app: `npx expo start`. * [Generate the native Android and iOS directories](https://docs.expo.dev/more/expo-cli#prebuild) for your project: `npx expo prebuild`. * [Build and run](https://docs.expo.dev/more/expo-cli#compiling) the native apps locally: `npx expo run:ios` and `npx expo run:android`. * [Install and update packages](https://docs.expo.dev/more/expo-cli#install) that work with the version of `react-native` in your project: `npx expo install package-name`. * `npx expo` can be used with `npx react-native` simultaneously. To view a list of available commands in Expo CLI, run the following in your project: > You can also run `yarn expo -h` if you prefer to use yarn as the package manager. The output should look something like below: `Usage $ npx expo Commands start, export run:ios, run:android, prebuild install, customize, config login, logout, whoami, register Options --version, -v Version number --help, -h Usage info` You can run any command with the `--help` or `-h` flag to learn more about it: ## Installation Expo CLI is included in the `expo` package. You can install it with npm or yarn: > Projects that are not using [Expo Prebuild](https://docs.expo.dev/more/expo-cli#prebuild) (also referred to as _Bare projects_) will need to perform additional setup to ensure all custom Expo bundling features work: [Metro: Bare workflow setup](https://docs.expo.dev/versions/latest/config/metro#bare-workflow-setup). ## Develop Start a development server to work on your project by running: > You can also run `npx expo` as an alias to `npx expo start`. This command starts a server on `http://localhost:8081` that a client can use to interact with the bundler. The default bundler is [Metro](https://metrobundler.dev/). The UI that shows up in the process is referred to as the Terminal UI. It contains a QR code (for the dev server URL) and a list of keyboard shortcuts you can press: ### Launch target The `npx expo start` command automatically launches the app in a development build if `expo-dev-client` is installed in the project. Otherwise, it launches the app in Expo Go. Alternatively, you can force the launch target by passing the following flags to the command: * `--dev-client`: Always launch the app in a development build. * `--go`: Always launch the app in Expo Go. You can also switch the launch target during runtime by pressing S in the Terminal UI. The `run` commands also use `--dev-client` after compiling the development build, by default. ### Server URL By default, the project is served over a LAN connection. You can change this behavior to localhost-only by using the flag `npx expo start --localhost`. Other available options are: * `--port`: Port to start the dev server on (does not apply to webpack or [tunnel URLs](https://docs.expo.dev/more/expo-cli#tunneling)). Use `--port 0` to automatically use the first available port. Default: 8081. * `--https`: (Deprecated in favor of `--tunnel`) Start the dev server using a secure origin. This is currently only supported on web. You can force the URL to be any value with the `EXPO_PACKAGER_PROXY_URL` environment variable. For example: `-` `export EXPO_PACKAGER_PROXY_URL=http://expo.dev` `npx expo start` Will open apps to: `exp://expo.dev:80` (the `:80` is a temporary workaround for Android WebSockets). #### Tunneling Restrictive network conditions (common for public Wi-Fi), firewalls (common for Windows users), or Emulator misconfiguration can make it difficult to connect a remote device to your dev server over lan/localhost. Sometimes it's easier to connect to a dev server over a proxy URL that's accessible from any device with internet access, this is referred to as tunneling. `npx expo start` provides built-in support for tunneling via [ngrok](https://ngrok.com/). To enable tunneling, first install `@expo/ngrok`: Then run the following to start your dev server from a _tunnel_ URL: `npx expo start --tunnel` This will serve your app from a public URL like: `https://xxxxxxx.bacon.19000.exp.direct:80`. Use the `EXPO_TUNNEL_SUBDOMAIN` environment variable to experimentally set the subdomain for the tunnel URL. This is useful for testing universal links on iOS. This may cause unexpected issues with `expo-linking` and Expo Go. Select the exact subdomain to use by passing a `string` value that is not one of: `true`, `false`, `1`, `0`. Drawbacks * Tunneling is slower than local connections because requests must be forwarded to a public URL. * Tunnel URLs are public and can be accessed by any device with a network connection. Expo CLI mitigates the risk of exposure by adding entropy to the beginning of the URL. Entropy can be reset by clearing the .expo directory in your project. * Tunnels require a network connection on both devices, meaning this feature cannot be used with the `--offline` flag. Tunneling requires a third-party hosting service, this means it may sometimes experience intermittent issues like `ngrok tunnel took too long to connect` or `Tunnel connection has been closed. This is often related to intermittent connection problems with the Ngrok servers...`. Be sure to check for [Ngrok outages](https://status.ngrok.com/) before reporting an issue. Some Windows users have also reported needing to modify their antivirus settings to allow Ngrok to work correctly. #### Offline You can develop without a network connection by using the `--offline` flag: `npx expo start --offline` Offline will prevent the CLI from making network requests. If you don't use the flag and your computer has no internet connection, then offline support will automatically be enabled, it will just take a bit longer to verify the reachability. Expo CLI makes network requests to sign manifests with your user credentials to ensure sensitive information is sandboxed in reusable runtimes like Expo Go. ### .expo directory When you start the development server in a project for the first time, a .expo directory is created at the root of that project. It contains two files: * devices.json: Contains information about devices that have opened this project recently. * settings.json: Contains information about server configuration that is used to serve the project's manifest. Both of these files have information that is specific to your local computer. This is the reason why .expo directory is included in the .gitignore file, by default, when a new project is created. It is not meant to be shared with other developers. ## Building A React Native app consists of two parts: a native runtime ([compiling](https://docs.expo.dev/more/expo-cli#compiling)), and static files like JavaScript bundles and assets ([exporting](https://docs.expo.dev/more/expo-cli#exporting)). Expo CLI provides commands for performing both tasks. ### Compiling You can compile your app locally with the `run` commands: `# Build for iOS` `npx expo run:ios` `# Build for Android` `npx expo run:android` Highlights * Build directly on connected devices with no global side effects using the `--device` flag. Supports locked devices, letting you retry instantly instead of needing to rebuild. * Automatically codesign iOS apps for development from the CLI without having to open Xcode. * Smart log parsing shows warnings and errors from your project source code, unlike Xcode which surfaces hundreds of benign warnings from your node modules. * Fatal errors causing your app to crash will be surfaced in the terminal preventing the need to reproduce in Xcode. `npx expo run:ios` can only be run on a Mac, and Xcode must be installed. You can build the app in the cloud from any computer using `eas build -p ios`. Similarly, `npx expo run:android` requires Android Studio and Java to be installed and configured on your computer. Building locally is useful for developing native modules and [debugging complex native issues](https://docs.expo.dev/debugging/runtime-issues#native-debugging). Building remotely with `eas build` is a much more resilient option due to the pre-configured cloud environment. If your project does not have the corresponding native directories, the `npx expo prebuild` command will run once to generate the respective directory before building. For example, if your project does not have an ios directory in the root of your project, then `npx expo run:ios` will first run `npx expo prebuild -p ios` before compiling your app. For more information on this process, see [Expo Prebuild](https://docs.expo.dev/workflow/prebuild). Cross-platform arguments * `--no-build-cache`: Clear the native cache before building. On iOS, this is the derived data directory. Cache clearing is useful for profiling your build times. * `--no-install`: Skip installing dependencies. On iOS, this will also skip running `npx pod-install` if the `dependencies` field in the project's `package.json` has changed. * `--no-bundler`: Skip starting the dev server. Enabled automatically if the dev server is already serving the app from a different process. * `-d, --device [device]`: Device name or ID to build the app on. You can pass `--device` without arguments to select a device from a list of available options. This supports connected devices as well as virtual devices. * `-p, --port `: Port to start the development server. Default: 8081. This is only relevant for development builds. Production builds will [export](https://docs.expo.dev/more/expo-cli#exporting) the project and embed the files in the native binary before installing them on a device. * `--binary `: File path to the binary to install on the device. When this is provided, the build process will be skipped and the binary will attempt to be installed directly. If the binary was not built for the correct device, for example, it is built for the simulator or installed on the device, then the command will fail. #### Compiling Android Android apps can have multiple different variants which are defined in the project's `build.gradle` file. Variants can be selected with the `--variant` flag: ##### `debug` variant Use the `debug` variant for a debug build: `npx expo run:android --variant debug` ##### `debugOptimized` variant > `debugOptimized` is available in SDK 54 and later. Use the `debugOptimized` variant for faster development with performance close to release builds while keeping the overall build in a debug-friendly mode: `npx expo run:android --variant debugOptimized` When using this variant, keep the following in mind: * Optimizes C++ libraries as in release builds, improving runtime performance * In EAS Build, use a matching Gradle command like [`:app:assembleDebugOptimized` in eas.json](https://docs.expo.dev/build-reference/apk#configuring-a-profile-to-build-apks) * Limitation: C++ debugging is disabled and C++ crashes may have less readable stack traces ##### `release` variant You can compile the Android app for production by running: `npx expo run:android --variant release` This build is not automatically code-signed for submission to the Google Play Store. This command should be used to test bugs that may only show up in production builds. To generate a production build that is code signed for the Play Store, we recommend using [EAS Build](https://docs.expo.dev/build/introduction). ##### Debugging native Android project You can debug the native Android project using native debugging tools by opening the android directory in Android Studio: `-` `open -a /Applications/Android Studio.app android` If you have a customized Android project using different product flavors, you can configure both the flavor and application ID using the `--variant` and `--app-id` flags: `npx expo run:android --variant freeDebug --app-id dev.expo.myapp.free` For more information, see the [Local builds using Android product flavors](https://docs.expo.dev/guides/local-app-development#local-builds-using-android-product-flavors) guide. #### Compiling iOS An iOS app can have multiple schemes for representing different sub-apps like App Clips, watchOS apps, Safari Extensions, and so on. By default, `npx expo run:ios` will choose the scheme for your iOS app. You can pick a custom scheme with the `--scheme ` argument. If you pass in the `--scheme` argument alone, then Expo CLI will prompt you to choose a scheme from the list of available options in your Xcode project. The scheme you select will filter out which `--device` options show up in the selection prompt, for example, selecting an Apple TV scheme will only show available Apple TV devices. You can compile an iOS app for production by running: `npx expo run:ios --configuration Release` This build is not automatically code signed for submission to the Apple App Store. `npx expo run:ios` should mostly be used to test bugs that only show up in production builds. Native code signing requires several network requests and is prone to many different types of errors from the Apple servers. To generate a production build that is code signed for the App Store, we recommend using [EAS Build](https://docs.expo.dev/build/introduction). When you compile your app onto a Simulator, the Simulator's native error logs will be piped to the Expo CLI process in the terminal. This is useful for quickly seeing bugs that may cause a fatal error. For example, missing permission messages. Error piping is not available for physical iOS devices. You can debug using `lldb` and all of the native Apple debugging tools by opening the project in Xcode and rebuilding from Xcode: Building from Xcode is useful because you can set native breakpoints and profile any part of the application. Be sure to track changes in source control (git) in case you need to regenerate the native app with `npx expo prebuild -p ios --clean`. iOS development signing If you want to see how your app will run on your device, all you have to do is connect it, run `npx expo run:ios --device`, and select your connected device. Expo CLI will automatically sign the device for development, install the app, and launch it. If you don't have any developer profiles setup on your computer then you'll need to set them up manually outside of Expo CLI by following this guide: [Setup Xcode signing](https://expo.fyi/setup-xcode-signing). ### Exporting You can export the JavaScript and assets for your app using Metro bundler by running: This is done automatically when using `eas update` or when compiling the native runtime. The `export` command works similar to most web frameworks: * A bundler transpiles and bundles your application code for production environments, stripping all code guarded by the `__DEV__` boolean. * All static files are copied into a static dist directory which can be served from a static host. * Contents of the public directory are copied into the dist directory as-is. The following options are provided: * `--platform `: Choose the platform to compile for: 'ios', 'android', 'all'. Default: all. 'web' is also available if configured in the app config. For more information, see [Customizing Metro](https://docs.expo.dev/guides/customizing-metro). * `--dev`: Bundle for development environments without minifying code or stripping the `__DEV__` boolean. * `--output-dir `: The directory to export the static files to. Default: dist * `--max-workers `: Maximum number of tasks to allow the bundler to spawn. Setting this to `0` will run all transpilation on the same process, meaning you can easily debug Babel transpilation. * `-c, --clear`: Clear the bundler cache before exporting. * `--no-minify`: Skip minifying JavaScript and CSS assets. * `--no-bytecode`: Skip generating Hermes bytecode for native platforms. Only use this for analyzing bundle sizes and never ship UTF-8 bundles to native platforms as this will lead to drastically longer startup times. * `--no-ssg`: Skip exporting static HTML files for web routes. This option only generates server code inside the dist directory. Useful for [API routes](https://docs.expo.dev/router/reference/api-routes). #### Hosting with sub-paths > Experimental functionality. You can configure the prefix for static assets by setting the `experiments.baseUrl` field in your [app config](https://docs.expo.dev/workflow/configuration): `{ "expo": { "experiments": { "baseUrl": "/my-root" } } }` This will export the website with all resources prefixed with `/my-root`. For example, an image at `assets/image.png` will be expected to be hosted at /my-root/assets/image.png. The actual file will be located in the same file system location as the entire directory is expected to be hosted at `/my-root` on the server. Expo Router has built-in support for `baseUrl`. When using the `Link` and `router` APIs, the `baseUrl` will be automatically prepended to the URL. `import { Link } from 'expo-router'; export default function Blog() { return Go to blog post; }` This will export to the following: `Go to blog post` If you use ``, React Navigation, or the `Linking` API directly, you'll need to manually prepend the `baseUrl`. The `baseUrl` functionality is production-only and must be set before exporting the website. If you change the value, you must re-export the website. Images and other assets will work automatically if you `require` or `import` them. If you directly reference a resource URL then you will need to append the baseUrl manually. `import { Image } from 'expo-image'; export default function Blog() { return ; }` This will export to the following: `` Manually passing a URL will need to be manually prefixed: `export default function Blog() { return ; }` ### Exporting with webpack > Deprecated: In SDK 50 and later, Expo Webpack has been deprecated in favor of universal Metro (`npx expo export`). Learn more in [migrating from Webpack to Expo Router](https://docs.expo.dev/router/migrate/from-expo-webpack). You can export the JavaScript and assets for your web app using webpack by running the following: * `--dev`: Bundle in 'development' mode without minifying code or stripping the `__DEV__` boolean. * `-c, --clear`: Clear the bundler cache before exporting. This command will be disabled if your project is configured to use `metro` for bundling web projects in the `app.json` via the `expo.web.bundler: 'metro'` field. ## Prebuild Native source code must be generated before a native app can compile. Expo CLI provides a unique and powerful system called _prebuild_, that generates the native code for your project. To learn more, read the [Expo Prebuild docs](https://docs.expo.dev/workflow/prebuild). ## Lint Linting helps enforce best practices and ensure your code is consistent. The `npx expo lint` command will set up ESLint with Expo-specific settings and run the `npx eslint` command with options that are optimized for the Expo framework. By running `npx expo lint --fix`, linting issues can be fixed automatically. Running `npx expo lint` targets all files in the src, app, and components directories by default. You can also pass custom files or directories to the lint command as arguments. For example: `npx expo lint ./utils constants.ts` All files matching `.js, .jsx, .ts, .tsx, .mjs, .cjs` extensions will be linted by default. You can customize the extensions by passing the `--ext` flag. For example, to lint only `.ts` and `.tsx` files, you can use the `--ext` option: `npx expo lint --ext .ts,.tsx` or `npx expo lint --ext .js --tsx .tsx`. If you need additional customization, you can pass extra arguments using the `--` operator. For example, to pass the `--no-error-on-unmatched-pattern` flag to ESLint, you can run: `npx expo lint -- --no-error-on-unmatched-pattern` If you need more customization, you can use `npx eslint` directly. [ Using ESLint Learn more about ensuring best practices with ESLint in an Expo project. ](https://docs.expo.dev/guides/using-eslint) ## Config Evaluate the app config (app.json, or app.config.js) by running: * `--full`: Include all project config data. * `--json`: Output in JSON format, useful for converting an app.config.js to an app.config.json. * `-t, --type`: [Type of config](https://docs.expo.dev/more/expo-cli#config-type) to show. ### Config type There are three different config types that are generated from the app config: * `public`: The manifest file to use with OTA updates. Think of this like an `index.html` file's `` element but for native apps. * `prebuild`: The config that is used for [Expo Prebuild](https://docs.expo.dev/workflow/prebuild) including async modifiers. This is the only time the config is not serializable. * `introspect`: A subset of the `prebuild` config that only shows in-memory modifications like `Info.plist` or AndroidManifest.xml changes. Learn more about [introspection](https://docs.expo.dev/config-plugins/development-and-debugging#introspection). ## Install Unlike the web, React Native is not backwards compatible. This means that npm packages often need to be the exact right version for the currently installed copy of `react-native` in your project. Expo CLI provides a best-effort tool for doing this using a list of popular packages and the known working version combinations. Simply use the `install` command as a drop-in replacement for `npm install`: `npx expo install expo-camera` Running a single instance of this command, you can also install multiple packages: `npx expo install typescript expo-sms` You can directly pass arguments to the underlying package manager by using the `--` operator: `-` `yarn expo install typescript -- -D` `# yarn add typescript -D` ### Version validation You can perform validation and correction with the `--check` and `--fix` flags: * `--check`: Check which installed packages need to be updated. * `--fix`: Automatically update any invalid package versions. Example: `# Check all packages for incorrect versions, prompt to fix locally` `npx expo install --check` `npx expo install --check` prompts you about packages that are installed incorrectly. It also prompts about installing these packages to their compatible versions locally. It exits with non-zero in Continuous Integration (CI). This means you can use this to do continuous immutable validation. In contrast, `npx expo install --fix` will always fix packages if needed, regardless of the environment. You can validate specific packages by passing them: `# Check only react-native and expo-sms` `npx expo install react-native expo-sms --check` The command `npx expo install expo-camera` and `npx expo install expo-camera --fix` serve the same purpose, the `--fix` command is useful for upgrading all packages in your project like: ### Configuring dependency validation There may be circumstances where you want to use a version of a package that is different from the version recommended by `npx expo install`. In this case, you can exclude specific packages from version checking by using the [`expo.install.exclude`](https://docs.expo.dev/versions/latest/config/package-json#exclude) property in your project's package.json. ### Install package managers `npx expo install` has support for `bun`, `npm`, `pnpm`, and `yarn`. You can force the package manager using a named argument: * `--bun`: Use `bun` to install dependencies. Default when bun.lockb or bun.lock exists. * `--npm`: Use `npm` to install dependencies. Default when package-lock.json exists. * `--pnpm`: Use `pnpm` to install dependencies. Default when pnpm-lock.yaml exists. * `--yarn`: Use `yarn` to install dependencies. Default when yarn.lock exists. ## Authentication Expo CLI provides authentication methods to use with the `npx expo start` command. Authentication is used to "code sign" manifests for secure OTA usage. Think of this like HTTPS on the web. 1. Register an account with `npx expo register`. 2. Login to your account with `npx expo login`. 3. Check which account is currently authenticated with `npx expo whoami`. 4. Logout with `npx expo logout`. These credentials are shared across Expo CLI and EAS CLI. ## Customizing Sometimes you may want to customize a project file that would otherwise be generated in memory by Expo CLI. When utilizing tools other than Expo CLI, you'll need to have the default config files present, otherwise your app may not work as expected. You can generate files by running: From here, you can choose to generate basic project files like: * babel.config.js -- The Babel configuration. This is required to be present if you plan to use tooling other than Expo CLI to bundle your project. * webpack.config.js -- The default webpack config for web development. * metro.config.js -- The default Metro config for universal development. This is required for usage with `npx react-native`. * tsconfig.json -- Create a TypeScript config file and install the required dependencies. ## Environment Variables ## Telemetry Expo dev tools collect anonymous data about general usage. This helps us know when a feature is not working as expected. Telemetry is completely optional, you can opt out by using the `EXPO_NO_TELEMETRY=1` environment variable. --- # glossary-of-terms List of non-obvious terms used within the documentation, related to Expo or cross-platform development in general. [](https://github.com/expo/expo/edit/main/docs/pages/more/glossary-of-terms.mdx) ### Android The mobile operating system that is sponsored by Google for use with Android devices. ### App config A file named app.json, app.config.json, app.config.js, or app.config.ts in the root project directory. For more information, see [app config configuration](https://docs.expo.dev/workflow/configuration). This file is used for the following purposes: * To configure how [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli) works. * Generate a project's public [manifest](https://docs.expo.dev/more/glossary-of-terms#manifest) in EAS Update (think index.html but for native apps). * List Expo [config plugins](https://docs.expo.dev/more/glossary-of-terms#config-plugin) which influence how `npx expo prebuild` generates native code. ### app.json An [app config](https://docs.expo.dev/more/glossary-of-terms#app-config) file. ### Apple capabilities Cloud services that are provided by Apple. These services must be enabled for an application in the [Apple Developer Portal](https://docs.expo.dev/more/glossary-of-terms#apple-developer-portal). ### Apple Developer Portal Apple's [official website](https://developer.apple.com/) for managing application code signing. EAS Credentials automate most of the common reasons a developer might visit this website when developing an app. ### Auto capability signing A feature of EAS Build that automatically enables or disables [Apple capabilities](https://docs.expo.dev/more/glossary-of-terms#apple-capabilities) based on the project's entitlements file. [Learn more](https://docs.expo.dev/build-reference/ios-capabilities). ### Autolinking A cross-platform tool for automatically linking native modules to native apps via native package managers. * On Android the tool is used in the android/app/build.gradle and invoked during the [Gradle](https://docs.expo.dev/more/glossary-of-terms#gradle) sync process. * On iOS the tool is used in [CocoaPods](https://docs.expo.dev/more/glossary-of-terms#cocoapods) ios/Podfile and invoked during `pod install`. There are two versions of Autolinking: [Expo Autolinking](https://docs.expo.dev/more/glossary-of-terms#expo-autolinking), and [Community Autolinking](https://docs.expo.dev/more/glossary-of-terms#community-autolinking). The default [Prebuild template](https://docs.expo.dev/more/glossary-of-terms#prebuild-template) includes support for [Expo Autolinking](https://docs.expo.dev/more/glossary-of-terms#expo-autolinking), and the [Community Autolinking](https://docs.expo.dev/more/glossary-of-terms#community-autolinking) fork. ### Babel Transpiler used for removing language features that aren't available in the runtime's [JavaScript engine](https://docs.expo.dev/more/glossary-of-terms#javascript-engine). [Metro](https://docs.expo.dev/more/glossary-of-terms#metro-bundler) uses Babel internally. Projects can configure how Babel is used by modifying the [babel.config.js](https://docs.expo.dev/versions/latest/config/babel) file in the project directory. This file is optional when using [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli). Expo projects should extend the default Babel preset [`babel-preset-expo`](https://github.com/expo/expo/tree/main/packages/babel-preset-expo). ### Bare workflow Describes the approach when the native projects (in the android and ios directories) are versioned in Git and maintained manually. It's typical for existing "bare" React Native apps where you manually make changes to the native projects. There is freedom to customize them but also high maintenance overhead. This is in contrast to using [app config and prebuild](https://docs.expo.dev/workflow/prebuild), where the native projects are not versioned. Instead, they are generated on demand using the `npx expo prebuild`, which is the [recommended approach](https://docs.expo.dev/workflow/prebuild#pitch). ### Bun A JavaScript runtime and a drop-in alternative for Node.js. Bun can also be used as a [package manager for JavaScript](https://docs.expo.dev/more/glossary-of-terms#package-manager). For more information about usage with Expo and EAS, see [using Bun](https://docs.expo.dev/guides/using-bun) guide. ### CocoaPods The iOS package manager that is used to link native modules to the native iOS project. This package manager is configured using the ios/Podfile file and updated when a user runs `pod install` in the ios directory. ### Community Autolinking This refers to the React Native community [fork](https://github.com/react-native-community/cli/issues/248#issue-422591744) of the [Expo Autolinking](https://docs.expo.dev/more/glossary-of-terms#expo-autolinking). The requirements for linking a module are different from [Expo Autolinking](https://docs.expo.dev/more/glossary-of-terms#expo-autolinking), however, the implementation is the same. ### Config introspection A process for evaluating the results of [`npx expo prebuild`](https://docs.expo.dev/more/glossary-of-terms#prebuild) in-memory without persisting any code changes. This is used in [Auto Capability Signing](https://docs.expo.dev/more/glossary-of-terms#auto-capability-signing) to determine what the entitlements file will look like without generating any native code. This process is also used in the [VS Code Expo](https://docs.expo.dev/more/glossary-of-terms#vs-code-expo) extension to debug [Config Mods](https://docs.expo.dev/more/glossary-of-terms#config-mods). ### Config Mods Async functions that are appended to the [app config](https://docs.expo.dev/more/glossary-of-terms#app-config) for use in [Prebuild](https://docs.expo.dev/more/glossary-of-terms#prebuild). These functions are given a single native file to modify such as AndroidManifest.xml or Info.plist. Config mods are chained together and come from the package `@expo/config-plugins`. For more information, see [Config plugins](https://docs.expo.dev/config-plugins/introduction). ### Config Plugin A JavaScript function that is used to append [config mods](https://docs.expo.dev/more/glossary-of-terms#config-mods) to the [app Config](https://docs.expo.dev/more/glossary-of-terms#app-config) for use in [Prebuild](https://docs.expo.dev/more/glossary-of-terms#prebuild). For more information, see [Config Plugins](https://docs.expo.dev/config-plugins/introduction). ### Continuous Native Generation (CNG) An abstract concept that describes the process of generating native projects from a set of inputs. In the context of Expo, CNG is implemented via the [`prebuild`](https://docs.expo.dev/more/glossary-of-terms#prebuild) command. See [CNG](https://docs.expo.dev/workflow/continuous-native-generation) and [Expo Prebuild](https://docs.expo.dev/workflow/prebuild) for more information. ### create-expo-app A standalone command line tool (CLI) for bootstrapping new React Native apps with the `expo` package installed. See [`create-expo-app` reference](https://docs.expo.dev/more/create-expo) for more information. ### create-react-native-app A standalone command line tool (CLI) for bootstrapping new React Native apps with the `expo` package installed and the native code generated. This CLI also enables the use of bootstrapping from an example project in [expo/examples](https://github.com/expo/examples). This package can be used by running any of the following commands: * `npx create-expo-app` * `yarn create expo-app` * `npm create expo-app` ### Dangerous mods Config [modifiers](https://docs.expo.dev/more/glossary-of-terms#config-mods) that apply unstable changes to a native project during [prebuild](https://docs.expo.dev/more/glossary-of-terms#prebuild). Using these modifiers is unpredictable and prone to breaking changes between major version bumps in [Expo SDK](https://docs.expo.dev/more/glossary-of-terms#expo-sdk). For more information, see [Using a dangerous mod](https://docs.expo.dev/config-plugins/dangerous-mods). ### Development build A development build is a debug build of your app that contains the `expo-dev-client` package. It's like an evolution of [Expo Go](https://docs.expo.dev/more/glossary-of-terms#expo-go) which doesn't have Expo Go's limitations and can be customized to your application's needs. This is the recommended approach for building production-grade apps with Expo. For more information, see [Development builds](https://docs.expo.dev/get-started/set-up-your-environment?mode=development-build). ### Dev clients `expo-dev-client` is a library that allows you to create a development build and includes useful development tools. You might also come across "custom dev client", a synonym for [Development builds](https://docs.expo.dev/more/glossary-of-terms#development-build). ### Development server A development server (or dev server) is a server that is started locally, usually by running `npx expo start` from [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli). The development server is typically hosted on `http://localhost:8081`. It hosts a [manifest](https://docs.expo.dev/more/glossary-of-terms#manifest) from `/` which the client uses to request the JavaScript bundle from the bundler. ### EAS [Expo Application Services (EAS)](https://docs.expo.dev/eas) are deeply integrated cloud services for Expo and React Native apps, such as [EAS Build](https://docs.expo.dev/build/introduction), [EAS Submit](https://docs.expo.dev/submit/introduction) and [EAS Update](https://docs.expo.dev/eas-update/introduction). ### EAS CLI The command-line tool for working with EAS. ### EAS Config The eas.json file used to configure [EAS CLI](https://docs.expo.dev/more/glossary-of-terms#eas-cli). For more information, see [Configuring EAS Build with eas.json](https://docs.expo.dev/build/eas-json). ### EAS Metadata A command-line tool for uploading and downloading Apple App Store metadata as JSON. This tool is available in the [EAS CLI](https://docs.expo.dev/more/glossary-of-terms#eas-cli) package and should be used to improve the iOS submission process. For more information, see [EAS Metadata](https://docs.expo.dev/eas/metadata). ### EAS Update 1. The cloud hosting service [EAS Update](https://docs.expo.dev/eas-update/introduction) that is used for OTA Updates. 2. The CLI command `eas update` from [EAS CLI](https://docs.expo.dev/more/glossary-of-terms#eas-cli) used to publish static files to the cloud hosting service. ### Emulator Emulator is used to describe software emulators of Android devices on your computers. Typically, iOS emulators are referred to as [Simulators](https://docs.expo.dev/more/glossary-of-terms#simulator). ### Entry point The entry point usually refers to the initial JavaScript file used to load an application. In apps using [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli), the default entry point is ./node\_modules/expo/AppEntry.js which simply imports the App.js file from the root project directory and registers it as the initial component in the native app. ### Experience A synonym for an app that usually implies something more single-use and smaller in scope, sometimes artistic and whimsical. ### Expo Autolinking The original [Autolinking](https://docs.expo.dev/more/glossary-of-terms#autolinking) system is designed for projects using `expo-modules-core`. This system links modules based on the existence of an expo-module.config.json in the library's root directory. ### Expo CLI The command-line tool for working with Expo. This term now refers to the [Local Expo CLI](https://docs.expo.dev/more/glossary-of-terms#local-expo-cli), but historically referred to the [Global Expo CLI](https://docs.expo.dev/more/glossary-of-terms#global-expo-cli). For more information, see [Expo CLI](https://docs.expo.dev/more/expo-cli). ### Expo client The former name for the [Expo Go](https://docs.expo.dev/more/glossary-of-terms#expo-go) app. ### Expo export Refers to the command `npx expo export` from [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli). This command is used to bundle the app's JavaScript and assets, and then export them into a static directory that can be uploaded to a hosting service like [EAS Update](https://docs.expo.dev/more/glossary-of-terms#eas-update), and embedded in a [native runtime](https://docs.expo.dev/more/glossary-of-terms#native-runtime) for offline use. ### Expo Go The Android and iOS app that serves as a sandbox for learning and experimenting with React Native. Due to its limitations (such as the inability to include custom native code), it's not recommended for building and distributing production apps. Instead, use a [development build](https://docs.expo.dev/more/glossary-of-terms#development-build). ### Expo install Refers to the command `npx expo install` from [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli). This command is used to install npm packages containing [native modules](https://docs.expo.dev/more/glossary-of-terms#native-module) that work with the currently installed version of `expo` in the project. Not all packages are supported. This command wraps the globally installed [package managers](https://docs.expo.dev/more/glossary-of-terms#package-manager). ### Expo Module Config A file named expo-module.config.json that lives in the root directory of a [native module](https://docs.expo.dev/more/glossary-of-terms#native-module). For more information, see [Module Config](https://docs.expo.dev/modules/module-config). ### Expo SDK A collection of [npm](https://docs.expo.dev/more/glossary-of-terms#npm) packages containing [native modules](https://docs.expo.dev/more/glossary-of-terms#native-module) that provides access to device/system functionality such as camera, push notification, contacts, file system, and more. * Each package supports Android, iOS, and web whenever possible. * The interface is completely written in [TypeScript](https://docs.expo.dev/more/glossary-of-terms#typescript). * All packages in the Expo SDK work with each other and can safely be compiled together. * Any package in the SDK can be used in any [React Native](https://docs.expo.dev/more/glossary-of-terms#react-native) app, with minimal, shared setup. [Learn more](https://docs.expo.dev/bare/installing-expo-modules). * All packages are [open source](https://github.com/expo/expo/tree/main/packages) and can be freely customized. ### Expo start Refers to the command `npx expo start` from [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli). This command is used to start a local [development server](https://docs.expo.dev/more/glossary-of-terms#development-server) that a [client](https://docs.expo.dev/more/glossary-of-terms#expo-client) connects to interact with the [Metro bundler](https://docs.expo.dev/more/glossary-of-terms#metro-bundler). ### Fabric The React Native rendering system which is used to create and manage native views. For more information, see [Fabric Renderer](https://reactnative.dev/architecture/fabric-renderer). ### Flipper A mobile app debugger used internally at Meta. It was previously recommended for use with React Native, but the integration is now deprecated and no longer supported by the React Native team [(RFC-0641)](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0641-decoupling-flipper-from-react-native-core.md). ### FYI Sometimes referred to as Expo FYI, is a collection of tailored solutions to complex issues that live at [expo.fyi](https://expo.fyi/). FYI links are utilized throughout Expo's developer tooling to help provide a better developer experience to users. ### Global Expo CLI The package `expo-cli` was installed globally on the user's machine and used across all projects. This CLI was introduced in SDK 30 (2018), and deprecated in favor of the [Local Expo CLI](https://docs.expo.dev/more/glossary-of-terms#local-expo-cli) in SDK 46 (2022). ### Gradle Gradle is a build automation tool for multi-language software development. It's used to build Android apps. It controls the development process in the tasks of compilation and packaging to testing, deployment, and publishing. ### Hermes engine A [JavaScript engine](https://docs.expo.dev/more/glossary-of-terms#javascript-engine) developed by [Meta](https://docs.expo.dev/more/glossary-of-terms#meta) specifically for use with [React Native](https://docs.expo.dev/more/glossary-of-terms#react-native). Hermes features ahead-of-time static optimization and compact bytecode to improve performance with focus on mobile devices, and is the default JS engine. ### iOS The operating system used on iPhone, iPad, and Apple TV. [Expo Go](https://docs.expo.dev/more/glossary-of-terms#expo-go) currently runs on iOS for iPhone and iPad. ### JavaScript engine A native package that can evaluate JavaScript on-device. In React Native, we predominantly use [Hermes](https://docs.expo.dev/more/glossary-of-terms#hermes-engine) by [Meta](https://docs.expo.dev/more/glossary-of-terms#meta). Other options include [JavaScriptCore](https://docs.expo.dev/more/glossary-of-terms#javascriptcore-engine) by Apple, and V8 by Google. ### JavaScriptCore engine A [JavaScript engine](https://docs.expo.dev/more/glossary-of-terms#javascript-engine) developed by Apple and built-in to [iOS](https://docs.expo.dev/more/glossary-of-terms#ios). React Native for [Android](https://docs.expo.dev/more/glossary-of-terms#android) also can use a version of JavaScriptCore for parity. Debugging with JavaScriptCore is less sophisticated than V8 or [Hermes](https://docs.expo.dev/more/glossary-of-terms#hermes-engine) which implement the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). ### Linking Linking can mean [deep linking into apps similar to how you link to websites on the web](https://docs.expo.dev/linking/overview) or [autolinking](https://docs.expo.dev/more/glossary-of-terms#autolinking). ### Local Expo CLI The package `@expo/cli` is installed with the `expo` package. This is sometimes referred to as the "Versioned Expo CLI" because it is installed inside the user's project as opposed to the now deprecated `expo-cli` which was installed globally. ### Manifest An Expo app manifest is similar to a [web app manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest). It provides information that Expo Go needs to know how to run the app and other relevant data. ### Meta Formerly Facebook, Meta is the group that develops [React Native](https://docs.expo.dev/more/glossary-of-terms#react-native), [Metro Bundler](https://docs.expo.dev/more/glossary-of-terms#metro-bundler), [Hermes Engine](https://docs.expo.dev/more/glossary-of-terms#hermes-engine), [Yoga](https://docs.expo.dev/more/glossary-of-terms#yoga) and more. The Expo team collaborates with Meta to deliver the best possible developer experience. ### Metro bundler The bundler used for converting JavaScript files and assets into a format that runs on a [native runtime](https://docs.expo.dev/more/glossary-of-terms#native-runtime). This bundler is maintained by [Meta](https://docs.expo.dev/more/glossary-of-terms#meta) and used for React Native (including web) apps. For more information, see [Metro documentation](https://metrobundler.dev/). ### Metro config The metro.config.js file used to configure [Metro bundler](https://docs.expo.dev/more/glossary-of-terms#metro-bundler). This should extend the package `@expo/metro-config` when using [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli). For more information, see [Customizing Metro](https://docs.expo.dev/guides/customizing-metro). ### Monorepo A project that has multiple sub-projects which are all linked together via the package manager. A monorepo is a great way to maintain codebase for a cross-platform app. ### Native directory The React Native ecosystem has thousands of libraries. Without a purpose-built tool, it's hard to know what the libraries are, to search through them, to determine the quality, try them out, and filter out the libraries that won't work for your project (some don't work with Expo, some don't work with Android or iOS). [React Native Directory](https://reactnative.directory/) is a website that aims to solve this problem, we recommend you use it to find packages to use in your projects. ### Native module A module written in native code that exposes native platform functionality to the JavaScript engine via the JS global. This functionality is usually accessed via `import { NativeModules } from 'react-native';`. ### Native runtime A native application containing a [JavaScript engine](https://docs.expo.dev/more/glossary-of-terms#javascript-engine), and is capable of running a React application. This includes [Expo Go](https://docs.expo.dev/more/glossary-of-terms#expo-go), [development build](https://docs.expo.dev/more/glossary-of-terms#development-build), [standalone apps](https://docs.expo.dev/more/glossary-of-terms#standalone-app), and even web browsers like Chrome. ### npm [npm](https://www.npmjs.com/) is a [package manager for JavaScript](https://docs.expo.dev/more/glossary-of-terms#package-manager) and the registry where the packages are stored. ### Package manager Automates the process of installing, upgrading, configuring, and removing libraries, also known as dependencies, from your project. See [Bun](https://docs.expo.dev/more/glossary-of-terms#bun), [npm](https://docs.expo.dev/more/glossary-of-terms#npm), [pnpm](https://docs.expo.dev/more/glossary-of-terms#pnpm), and [Yarn](https://docs.expo.dev/more/glossary-of-terms#yarn). ### Package manager workspaces The recommended [monorepo](https://docs.expo.dev/more/glossary-of-terms#monorepo) solution for Expo users. See [Working with Monorepos](https://docs.expo.dev/guides/monorepos) guide for more information on how to configure workspaces with supported package managers. ### Platform extensions Platform extensions are a feature of the [Metro bundler](https://docs.expo.dev/more/glossary-of-terms#metro-bundler) which enables users to substitute files on a per-platform basis given a specific filename. For example, if a project has a .index.js file and a .index.ios.js file, then the index.ios.js will be used when bundling for iOS, and the index.js file will be used when bundling for all other platforms. By default, platform extensions are resolved in `@expo/metro-config` using the following formula: * Android: \*.android.js, \*.native.js, \*.js * iOS: \*.ios.js, \*.native.js, \*.js * Web: \*.web.js, \*.js ### pnpm [pnpm](https://pnpm.io/) is [package manager for JavaScript](https://docs.expo.dev/more/glossary-of-terms#package-manager), focused on disk space efficiency. ### Prebuild The process of generating the temporary native android and ios directories for a React Native project based on the [app config](https://docs.expo.dev/more/glossary-of-terms#app-config). This process is performed by running the command `npx expo prebuild` from [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli) in a project directory. See [Prebuild template](https://docs.expo.dev/more/glossary-of-terms#prebuild-template) and [Autolinking](https://docs.expo.dev/more/glossary-of-terms#autolinking) for further information. ### Prebuild template The React Native project template is used as the first step of [Prebuilding](https://docs.expo.dev/more/glossary-of-terms#prebuild). This template is versioned with the [Expo SDK](https://docs.expo.dev/more/glossary-of-terms#expo-sdk), and the template is chosen based on the installed version of `expo` in a project. After the template is cloned, `npx expo prebuild` evaluates the [app config](https://docs.expo.dev/more/glossary-of-terms#app-config) and runs the [Config mods](https://docs.expo.dev/more/glossary-of-terms#config-mods) which modify various files in the template. Although the template can be changed by using the `npx expo prebuild --template /path/to/template` flag, the default prebuild template contains important initial defaults that the `npx expo prebuild` command makes assumptions about. The default template currently lives at [`expo-template-bare-minimum`](https://github.com/expo/expo/tree/main/templates/expo-template-bare-minimum). ### Publish We use the word "publish" as a synonym for "deploy". When you publish an app, it becomes available at a persistent URL from Expo Go, or in the case of [Standalone apps](https://docs.expo.dev/more/glossary-of-terms#standalone-app), it updates the app. ### React Native [React Native](https://reactnative.dev/) lets you build mobile apps using only JavaScript. It uses the same design as React, letting you compose a rich mobile UI from declarative components. ### React Native Web A high-performing abstraction on top of `react-dom` that enables core primitives from [React Native](https://docs.expo.dev/more/glossary-of-terms#react-native) to run in the browser. React Native for web (RNW) was developed at X and is currently used for their [main website](https://x.com/). [Expo SDK](https://docs.expo.dev/more/glossary-of-terms#expo-sdk) and [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli) have first-class support for RNW. ### React Navigation The preferred navigation library for React Native apps, developed and sponsored by the Expo team. ### Remote Debugging Remote Debugging is a deprecated way of debugging React Native apps. A better alternative today is to use [Hermes](https://docs.expo.dev/more/glossary-of-terms#hermes-engine), as you can connect React Native DevTools to it. Also known as Async Chrome Debugging, it was an experimental system for debugging React Native apps. The system works by executing the application JavaScript in a Chrome tab's web worker, then sending native commands over a websocket to the native device. ### Simulator An emulator for iOS devices that you can run on macOS (or in [Snack](https://docs.expo.dev/more/glossary-of-terms#snack)) to work on your app without having to have a physical device handy. ### Slug `slug` in the \[app config\]((#appjson) is a URL-friendly name for your project. It is unique across your Expo account. ### Snack [Snack](https://snack.expo.dev/) is an in-browser development environment where you can build Expo [experiences](https://docs.expo.dev/more/glossary-of-terms#experience) without installing any tools on your phone or computer. ### Software Mansion A development agency in Kraków, Poland. Maintainers of `react-native-gesture-handler`, `react-native-screens`, and `react-native-reanimated`. The platform team at Expo is composed of a number of contractors from Software Mansion. All of Software Mansion's core React Native libraries are supported in [Expo Go](https://docs.expo.dev/more/glossary-of-terms#expo-go). ### Standalone app Synonymous with "Production build". An application binary that can be submitted to the Google Play Store or Apple App Store. For more information, see [Build your project for app stores](https://docs.expo.dev/deploy/build-project) or [Run builds locally or on your own infrastructure](https://docs.expo.dev/build-reference/local-builds). ### Store config The store.config.json file used to configure [EAS Metadata](https://docs.expo.dev/more/glossary-of-terms#eas-metadata). This file can be generated from an existing App Store entry using `eas metadata:pull`. ### Sweet API The Swift and Kotlin API for writing React Native modules. This API is provided by the library `expo-modules-core` which is shipped with the `expo` package. For more information, see [Module API](https://docs.expo.dev/modules/module-api). ### TypeScript TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale. The Expo SDK is written in TypeScript, and we highly recommend using it. For more information, see our [TypeScript guide](https://docs.expo.dev/guides/typescript). ### Updates Traditionally, apps for Android and iOS are updated by submitting an updated binary to the App and Play stores. Updates allow you to push an update to your app without the overhead of submitting a new release to the stores. For more information, see [Publishing](https://docs.expo.dev/eas-update/introduction) documentation. ### VS Code Expo Tools The VS Code extension for improving the developer experience of working with app config files. This extension provides autocomplete and intellisense for the [app config](https://docs.expo.dev/more/glossary-of-terms#app-config), [Store Config](https://docs.expo.dev/more/glossary-of-terms#store-config), [Expo Module Config](https://docs.expo.dev/more/glossary-of-terms#expo-module-config), and [EAS Config](https://docs.expo.dev/more/glossary-of-terms#eas-config). For more information, see the [VS Code Expo Tools extension](https://marketplace.visualstudio.com/items?itemName=expo.vscode-expo-tools). ### Watchman The file watcher used by [Metro](https://docs.expo.dev/more/glossary-of-terms#metro-bundler) to perform hot reloads during development. Watchman contains native code and may cause issues when installed globally. Watchman is maintained by [Meta](https://docs.expo.dev/more/glossary-of-terms#meta). ### webpack The deprecated bundler used by [Expo CLI](https://docs.expo.dev/more/glossary-of-terms#expo-cli) for developing [`react-native-web`](https://docs.expo.dev/more/glossary-of-terms#react-native-web) apps. ### Yarn [Yarn](https://yarnpkg.com/) is a [package manager for JavaScript](https://docs.expo.dev/more/glossary-of-terms#package-manager), created at Meta. It has two mainline versions [Yarn v1 (Classic)](https://classic.yarnpkg.com/lang/en/) and [Yarn Berry](https://github.com/yarnpkg/berry). ### Yoga A native cross-platform library used by React Native internally to provide [CSS FlexBox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox) support to native views. React Native styles are passed to Yoga to lay out and style elements on the screen. For more information, see [Yoga](https://github.com/facebook/yoga) documentation. --- # qr-codes Reference for the QR code generator at qr.expo.dev. [](https://github.com/expo/expo/edit/main/docs/pages/more/qr-codes.mdx) qr.expo.dev is a cloud function that generates Expo-branded QR codes. This function creates QR codes for [EAS Update](https://docs.expo.dev/eas-update/introduction), which are used to preview updates in [development builds](https://docs.expo.dev/develop/development-builds/introduction) and Expo Go. For example, if you and your team have a development build, and you'd like to load the latest update on a specific build's channel, you could go to the following endpoint to generate a QR code: `https://qr.expo.dev/eas-update?projectId=your-project-id&runtimeVersion=your-runtime-version&channel=your-channel` Which would produce the following QR code SVG: This QR code represents the following URL: `exp+your-slug://expo-development-client/?url=https://u.expo.dev/your-project-id?runtime-version=your-runtime-version&channel-name=your-channel` This URL will deep link into a development build and instruct it to fetch the latest update on the specified channel. > If sharing the URL is more convenient, you can request the URL directly by adding `format=url` to the query parameters. ## General The following parameters apply to the `/eas-update` endpoint. ### Base query parameters The following base query parameters can be included with any request to `/eas-update`. ### Update by device traits Preview and production builds make requests to the EAS Update service with `runtimeVersion` and `channel` properties. You can emulate this behavior with the following query parameters: #### Example `https://qr.expo.dev/eas-update?projectId=your-project-id&runtimeVersion=your-runtime-version&channel=your-channel` ### Update by ID You can create a QR code for a specific update given its platform-specific ID. #### Example `https://qr.expo.dev/eas-update?updateId=your-update-id` ### Update by group ID You can create a QR code for an update group given the update's group ID. #### Example `https://qr.expo.dev/eas-update?projectId=your-project-id&groupId=your-update-id` ### Update by branch ID You can create a QR code with a branch's ID, which will return the latest update available on that branch. #### Example `https://qr.expo.dev/eas-update?projectId=your-project-id&branchId=your-branch-id` ### Update by channel ID You can create a QR code with a channel's ID, which will return the latest update available on the branch or branches that are mapped to that channel. #### Example `https://qr.expo.dev/eas-update?projectId=your-project-id&channelId=your-channel-id` --- # expo-sfv-0 [](https://github.com/expo/expo/edit/main/docs/pages/technical-specs/expo-sfv-0.mdx) [ Edit page ](https://github.com/expo/expo/edit/main/docs/pages/technical-specs/expo-sfv-0.mdx) Version 0 [ Edit page ](https://github.com/expo/expo/edit/main/docs/pages/technical-specs/expo-sfv-0.mdx) Structured Field Values for HTTP, [IETF RFC 8941](https://tools.ietf.org/html/rfc8941), is a proposal to formalize header syntax and facilitate nested data. Since it is still a work in progress, Expo maintains a custom version that only implements the following subset of the protocol defined in [IETF RFC 8941](https://tools.ietf.org/html/rfc8941): * All key values * String, integer, and decimal items * Dictionaries --- # expo-updates-1 Version 1 [](https://github.com/expo/expo/edit/main/docs/pages/technical-specs/expo-updates-1.mdx) ## Introduction This is the specification for Expo Updates, a protocol for delivering updates to Expo apps running on multiple platforms. ### Conformance Conforming servers and client libraries must fulfill all normative requirements. Conformance requirements are described in this document by both descriptive assertions and key words with clearly defined meanings. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative portions of this document are to be interpreted as described in [IETF RFC 2119](https://tools.ietf.org/html/rfc2119). These key words may appear in lowercase and still retain their meaning unless explicitly declared as non-normative. A conforming implementation of this protocol MAY provide additional functionality, but MUST NOT where explicitly disallowed or would otherwise result in non-conformance. Where relevant, unknown fields should be allowed and ignored by conforming clients. ### Overview Conforming servers and client libraries MUST follow the HTTP spec as described in [RFC 7231](https://tools.ietf.org/html/rfc7231) as well as the more precise guidance described in this spec. * An _update_ is defined as a [_manifest_](https://docs.expo.dev/technical-specs/expo-updates-1#manifest-body) together with the assets referenced inside the manifest. * A [_directive_](https://docs.expo.dev/technical-specs/expo-updates-1#directive-body) is defined as a message from the server that instructs clients to perform an action. Expo Updates is a protocol for assembling and delivering updates and directives to clients. The primary audiences of this spec are Expo Application Services and organizations that wish to manage their own update server to satisfy internal requirements. ## Client An app running a conformant Expo Updates client library MUST load the most recent _update_ saved in the client library's update database, possibly after filtering by the contents of the update's manifest [_metadata_](https://docs.expo.dev/technical-specs/expo-updates-1#manifest-body). The following describes how a conformant Expo Updates client library MUST retrieve a new update from a conformant server: 1. The client library MUST make a [request](https://docs.expo.dev/technical-specs/expo-updates-1#request) for the most recent update and directive, with constraints specified in the headers. 2. If a [response](https://docs.expo.dev/technical-specs/expo-updates-1#response) is received, the client library MUST process its contents: ``` * For a response containing an _update_, the client library SHALL proceed to make additional requests to download and store any new assets specified in the manifest. The manifest and assets together are considered a new _update_. The client library will edit its local state to reflect that a new update has been added to the local storage. It will also update the local state with the new `expo-manifest-filters` and `expo-server-defined-headers` found in the response [headers](https://docs.expo.dev/technical-specs/expo-updates-1#manifest-response-headers). * For a response containing a _directive_, the client library will consume the directive depending on the directive type and edit its local state accordingly. ``` ## Request A conformant client library MUST make a GET request with the headers: 1. `expo-protocol-version: 1`, to specify version 1 of this Expo Updates specification. 2. `expo-platform`, to specify the platform type the client is running on. ``` * iOS MUST be `expo-platform: ios`. * Android MUST be `expo-platform: android`. * If it is not one of these platforms, the server SHOULD return a 400 or a 404 ``` 3. `expo-runtime-version` MUST be a runtime version compatible with the client. A runtime version stipulates the native code setup a client is running. It should be set when the client is built. For example, in an iOS client, the value may be set in a plist file. 4. Any headers stipulated by a previous responses' [server defined headers](https://docs.expo.dev/technical-specs/expo-updates-1#response). A conformant client library MAY send one of `accept: application/expo+json`, `accept: application/json`, or `accept: multipart/mixed` based on the [supported response structures](https://docs.expo.dev/technical-specs/expo-updates-1#response), though it SHOULD send `accept: application/expo+json, application/json, multipart/mixed`. A conformant client library MAY express preference using "q" parameters as specified in [RFC 7231](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1), which default to `1`. A conformant client library configured to perform [code signing](https://docs.expo.dev/technical-specs/expo-updates-1#code-signing) verification MUST send a `expo-expect-signature` header to indicate that it expects the conformant server to include the `expo-signature` header in the manifest response. `expo-expect-signature` is an [Expo SFV](https://docs.expo.dev/technical-specs/expo-sfv-0) dictionary which MAY contain any of the following key value pairs: * `sig` SHOULD contain the boolean `true` to indicate that it requires a conformant server to respond with the signature in the `sig` key. * `keyid` SHOULD contain the keyId of the public key the client will use to verify the signature * `alg` SHOULD contain the algorithm the client will use to verify the signature Example: `expo-protocol-version: 1 accept: application/expo+json;q=0.9, application/json;q=0.8, multipart/mixed expo-platform: * expo-runtime-version: * expo-expect-signature: sig, keyid="root", alg="rsa-v1_5-sha256"` ## Response A conformant server MUST return a response structured in at least one of the two following response structures, MAY support either or both response structures, and when an unsupported response structure is requested the server SHOULD respond with an HTTP `406` error status. A server that wishes to respond with an incompatible response for the requested protocol version SHOULD also respond with an HTTP `406` error status instead. * For a response with `content-type: application/json` or `content-type: application/expo+json`, the [common response headers](https://docs.expo.dev/technical-specs/expo-updates-1#common-response-headers) and [other response headers](https://docs.expo.dev/technical-specs/expo-updates-1#other-response-headers) MUST be sent in the response headers and the [manifest body](https://docs.expo.dev/technical-specs/expo-updates-1#manifest-body) MUST be sent in the response body. This format of response does not support multiple response parts and therefore does not support _directives_, and SHOULD respond with an HTTP `406` error status when the most recent response to be served is not an _update_. * For a response with `content-type: multipart/mixed`, the response MUST be structured as specified in the [multipart response](https://docs.expo.dev/technical-specs/expo-updates-1#multipart-response) section. * A [multipart response](https://docs.expo.dev/technical-specs/expo-updates-1#multipart-response) with no parts MAY respond with an HTTP `204` status and no content, and thus no `content-type` response header. The choice of update and headers are dependent on the values of the request headers. A conformant server MUST respond with the most recent update, ordered by creation time, satisfying all parameters and constraints imposed by the [request headers](https://docs.expo.dev/technical-specs/expo-updates-1#request). The server MAY use any properties of the request like its headers and source IP address to choose amongst several updates that all satisfy the request's constraints. ### Common response headers `expo-protocol-version: 1 expo-sfv-version: 0 expo-manifest-filters: <expo-sfv> expo-server-defined-headers: <expo-sfv> cache-control: * content-type: *` * `expo-protocol-version` describes the version of the protocol defined in this spec and MUST be `1`. * `expo-sfv-version` MUST be `0`. * `expo-manifest-filters` is an [Expo SFV](https://docs.expo.dev/technical-specs/expo-sfv-0) dictionary. It is used to filter updates stored by the client library by the `metadata` attribute found in the [manifest](https://docs.expo.dev/technical-specs/expo-updates-1#manifest-body). If a field is mentioned in the filter, the corresponding field in the metadata must either be missing or equal for the update to be included. The client library MUST store the manifest filters until it is overwritten by a newer response. * `expo-server-defined-headers` is an [Expo SFV](https://docs.expo.dev/technical-specs/expo-sfv-0) dictionary. It defines headers that a client library MUST store until overwritten by a newer dictionary, and they MUST be included in every subsequent [update request](https://docs.expo.dev/technical-specs/expo-updates-1#request). * `cache-control` MUST be set to an appropriately short period of time. A value of `cache-control: private, max-age=0` is recommended to ensure the newest manifest is returned. Setting longer cache ages could result in stale updates. * `content-type` MUST be determined by _proactive negotiation_ as defined in [RFC 7231](https://tools.ietf.org/html/rfc7231#section-3.4.1). Since the client library is [required](https://docs.expo.dev/technical-specs/expo-updates-1#request) to send an `accept` header with each manifest request, this will always be either `application/expo+json`, `application/json`; otherwise the request would return a `406` error. ### Other response headers `expo-signature: *` * `expo-signature` SHOULD contain the signature of the manifest to be used during the validation step of [code signing](https://docs.expo.dev/technical-specs/expo-updates-1#code-signing) if the request for the manifest contained the `expo-expect-signature` header. This is an [Expo SFV](https://docs.expo.dev/technical-specs/expo-sfv-0) dictionary which MAY contain any of the following key value pairs: ``` * `sig` MUST contain the signature of the manifest. The name of this field matches that of `expo-expect-signature`. * `keyid` MAY contain the keyId of the key the server used to sign the response. The client SHOULD use the certificate that matches this `keyid` to verify the signature. * `alg` MAY contain the algorithm the server used to sign the response. The client SHOULD use this field only if it matches the algorithm defined for the certificate matching `keyid`. ``` ### Multipart response An update response of this format is defined by the `multipart/mixed` MIME type as defined by [RFC 2046](https://tools.ietf.org/html/rfc2046#section-5.1). Headers for this response format are the [common response headers](https://docs.expo.dev/technical-specs/expo-updates-1#common-response-headers), with the following exceptions: * `content-type` SHOULD have a `multipart/mixed` value as defined by [RFC 2046](https://tools.ietf.org/html/rfc2046#section-5.1) Part order is not strict. A multipart response with no parts (zero-length body) should be considered a no-op (no updates or directives available), though headers for the response SHOULD be sent nevertheless and processed by the client. Each part is defined as follows: 1. OPTIONAL `"manifest"` part: ``` * MUST have part header `content-disposition: form-data; name="manifest"`. The first parameter (`form-data`) does not need to be `form-data`, but the `name` parameter must have `manifest` as a value. * MUST have part header `content-type: application/json` or `application/expo+json`. * SHOULD have part header `expo-signature` as defined in [other response headers](https://docs.expo.dev/technical-specs/expo-updates-1#other-response-headers) if code signing is being used. * The [manifest body](https://docs.expo.dev/technical-specs/expo-updates-1#manifest-body) MUST be sent in the part body. ``` 2. OPTIONAL `"extensions"` part: ``` * MUST have part header `content-disposition: form-data; name="extensions"`. The first parameter (`form-data`) does not need to be `form-data`, but the `name` parameter must have `extensions` as a value. * MUST have part header `content-type: application/json`. * The [extensions-body](https://docs.expo.dev/technical-specs/expo-updates-1#extensions-body) MUST be sent in the part body. ``` 3. OPTIONAL `"directive"` part: ``` * MUST have part header `content-disposition: form-data; name="directive"`. The first parameter (`form-data`) does not need to be `form-data`, but the `name` parameter must have `directive` as a value. * MUST have part header `content-type: application/json` or `application/expo+json`. * SHOULD have part header `expo-signature` as defined in [other response headers](https://docs.expo.dev/technical-specs/expo-updates-1#other-response-headers) if code signing is being used. * The [directive body](https://docs.expo.dev/technical-specs/expo-updates-1#directive-body) MUST be sent in the part body. ``` ### Manifest body Defined as JSON conforming to both the following `Manifest` definition expressed in [TypeScript](https://www.typescriptlang.org/) and the detailed descriptions for each field: `type Manifest = { id: string; createdAt: string; runtimeVersion: string; launchAsset: Asset; assets: Asset[]; metadata: { [key: string]: string }; extra: { [key: string]: any }; }; type Asset = { hash?: string; key: string; contentType: string; fileExtension?: string; url: string; };` * `id`: The ID MUST uniquely specify the manifest and MUST be a UUID. ``` ``` * `createdAt`: The date and time at which the update was created is essential as the client library selects the most recent update (subject to any constraints supplied by the `expo-manifest-filters` header). The datetime should be formatted according to [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). ``` ``` * `runtimeVersion`: Can be any string defined by the developer. It stipulates what native code setup is required to run the associated update. ``` ``` * `launchAsset`: A special asset that is the entry point of the application code. The `fileExtension` field will be ignored for this asset and SHOULD be omitted. ``` ``` * `assets`: An array of assets used by the update bundle, such as JavaScript, pictures, and fonts. All assets (including the `launchAsset`) should be downloaded to disk before executing the update, and a mapping of asset `key`s to locations on disk should be provided to application code. ``` ``` * Properties of each asset object: ``` * `hash`: Base64URL-encoded SHA-256 hash of the file to guarantee integrity. Base64URL encoding is defined by [IETF RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648#section-5). * `key`: Key used to reference this asset from the update's application code. This key, for example, may be generated by a separate build step that processes the application code, such as a bundler. * `contentType`: The MIME type of the file as defined by [RFC 2045](https://tools.ietf.org/html/rfc2045). For example, `application/javascript`, `image/jpeg`. * `fileExtension`: The suggested extension to use when a file is saved on a client. Some platforms, such as iOS, require certain file types to be saved with an extension. The extension MUST be prefixed with a `.`. For example, .jpeg. In some cases, such as the launchAsset, this field will be ignored in favor of a locally determined extension. If the field is omitted and there is no locally stipulated extension, the asset will be saved without an extension. For example, `./filename` with no `.` at the end. A conforming client SHOULD prefix a file extension with a `.` if a file extension is not empty and missing the `.` prefix. * `url`: Location at which the file may be fetched. ``` * `metadata`: The metadata associated with an update. It is a string-valued dictionary. The server MAY send back anything it wishes to be used for filtering the updates. The metadata MUST pass the filter defined in the accompanying `expo-manifest-filters` header. ``` ``` * `extra`: For storage of optional "extra" information such as third-party configuration. For example, if the update is hosted on Expo Application Services (EAS), the EAS project ID may be included: ``` `"extra": { "eas": { "projectId": "00000000-0000-0000-0000-000000000000" } }` ``` ### Extensions body Defined as JSON conforming to both the following `Extensions` definition expressed in [TypeScript](https://www.typescriptlang.org/) and the detailed descriptions for each field: `type Extensions = { assetRequestHeaders: ExpoAssetHeaderDictionary; ... } type ExpoAssetHeaderDictionary = { [assetKey: string]: { [headerName: string]: string, }; }` * `assetRequestHeaders`: MAY contain a dictionary of header (key, value) pairs to include with asset requests. Key and value MUST both be strings. ### Directive body Defined as JSON conforming to both the following `Directive` definition expressed in [TypeScript](https://www.typescriptlang.org/) and the detailed descriptions for each field: `type Directive = { type: string; parameters?: { [key: string]: any }; extra?: { [key: string]: any }; };` * `type`: The type of directive. * `parameters`: MAY contain any extra information specific to the `type`. * `extra`: For storage of optional "extra" information such as third-party information. For example, if the update is hosted on Expo Application Services (EAS), the EAS project ID may be included. A conformant client library and server MAY specify and implement directive types specific to the needs of the application. For example, Expo Application Services makes use of one type thus far, `rollBackToEmbedded`, which directs the expo-updates library to use the update embedded in the host application instead of any other downloaded updates. ## Asset request A conformant client library MUST make a GET request to the asset URLs specified by the manifest. The client library SHOULD include a header accepting the asset's content type as specified in the manifest. Additionally, the client library SHOULD specify the compression encoding the client library is capable of handling. Example headers: `accept: image/jpeg, */* accept-encoding: br, gzip` A conformant client library MUST also include any header (key, value) pairs included in [`assetRequestHeaders`](https://docs.expo.dev/technical-specs/expo-updates-1#manifest-extensions) for this asset key. ## Asset response An asset located at a particular URL MUST NOT be changed or removed since client libraries may fetch assets for any update at any time. A conformant client MUST verify that the base64url-encoded SHA-256 hash of the asset matches the `hash` field for the asset from the manifest. ### Asset response headers The asset MUST be encoded using a compression format that the client supports according to the request's `accept-encoding` header. The server MAY serve uncompressed assets. The response MUST include a `content-type` header with the MIME type of the asset. For example: `content-encoding: br content-type: application/javascript` An asset is RECOMMENDED to be served with a `cache-control` header set to a long duration as an asset located at a given URL must not change. For example: `cache-control: public, max-age=31536000, immutable` ### Compression Assets SHOULD be capable of being served with [Gzip](https://www.gnu.org/software/gzip/) and [Brotli](https://github.com/google/brotli) compression. ## Code signing Expo Updates supports code signing the manifest and directive bodies. Code signing the manifest also transitively signs the assets since their hashes are present in the manifest and verified by a conformant client. A conformant client MAY request the manifest or directive be signed using a private key, and then MUST verify the signature of the manifest or directive using the corresponding code signing certificate before it is used or any corresponding manifest assets are downloaded. The client MUST verify that the signing certificate is either a self-signed, trusted root certificate or is in a certificate chain signed by a trusted root certificate. In either case, the root certificate MUST be embedded in the application or device's operating system. --- # app A reference of available properties in Expo app config. The following is a list of properties that are available for you under the `"expo"` key in app.json or app.config.json. These properties can be passed to the top level object of app.config.js or app.config.ts. `name` Type: `string` The name of your app as it appears both within Expo Go and on your home screen as a standalone app. Bare Workflow `description` Type: `string` A short description of what your app is and why it is great. `slug` Type: `string` A URL-friendly name for your project that is unique across your account. `owner` Type: `string` The name of the Expo account that owns the project. This is useful for teams collaborating on a project. If not provided, the owner defaults to the username of the current user. `currentFullName` Type: `string` The auto generated Expo account name and slug used for display purposes. It is not meant to be set directly. Formatted like `@username/slug`. When unauthenticated, the username is `@anonymous`. For published projects, this value may change when a project is transferred between accounts or renamed. `originalFullName` Type: `string` The auto generated Expo account name and slug used for services like Notifications and AuthSession proxy. It is not meant to be set directly. Formatted like `@username/slug`. When unauthenticated, the username is `@anonymous`. For published projects, this value will not change when a project is transferred between accounts or renamed. `sdkVersion` Type: `string` The Expo sdkVersion to run the project on. This should line up with the version specified in your package.json. `runtimeVersion` One of types: * `string` matching the following pattern: `^[a-zA-Z\d][a-zA-Z\d._+()-]{0,254}$` * `string` matching the following pattern: `^exposdk:((\d+\.\d+\.\d+)|(UNVERSIONED))$` * An `object` with the following properties: ``` `policy` Type: `enum` Path: `runtimeVersion.policy` Valid values: `nativeVersion`, `sdkVersion`, `appVersion`, `fingerprint`. ``` Property indicating compatibility between a build's native code and an OTA update. `version` Type: `string` Your app version. In addition to this field, you'll also use `ios.buildNumber` and `android.versionCode` — read more about how to version your app [here](https://docs.expo.dev/distribution/app-stores/#versioning-your-app). On iOS this corresponds to `CFBundleShortVersionString`, and on Android, this corresponds to `versionName`. The required format can be found [here](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring). Bare Workflow `platforms` Type: `array` Platforms that your project explicitly supports. If not specified, it defaults to `["ios", "android"]`. Example `[ "ios", "android", "web" ]` `githubUrl` Type: `string` If you would like to share the source code of your app on Github, enter the URL for the repository here and it will be linked to from your Expo project page. Example `"https://github.com/expo/expo"` `orientation` Type: `enum` Locks your app to a specific orientation with portrait or landscape. Defaults to no lock. Valid values: `default`, `portrait`, `landscape` `userInterfaceStyle` Type: `enum` Configuration to force the app to always use the light or dark user-interface appearance, such as "dark mode", or make it automatically adapt to the system preferences. If not provided, defaults to `light`. Requires `expo-system-ui` be installed in your project to work on Android. `backgroundColor` Type: `string` The background color for your app, behind any of your React views. This is also known as the root view background color. Requires `expo-system-ui` be installed in your project to work on iOS. 6 character long hex color string, for example, `'#000000'`. Default is white: `'#ffffff'` `primaryColor` Type: `string` On Android, this will determine the color of your app in the multitasker. Currently this is not used on iOS, but it may be used for other purposes in the future. 6 character long hex color string, for example, `'#000000'` `icon` Type: `string` Local path or remote URL to an image to use for your app's icon. We recommend that you use a 1024x1024 png file. This icon will appear on the home screen and within the Expo Go app. Bare Workflow `notification` Type: `object` @deprecated in favor of the expo-notifications config plugin. This field will be removed in SDK 55. Configuration for remote (push) notifications. `icon` Type: `string` Path: `notification.icon` (Android only) Local path or remote URL to an image to use as the icon for push notifications. 96x96 png grayscale with transparency. We recommend following [Google's design guidelines](https://material.io/design/iconography/product-icons.html#design-principles). If not provided, defaults to your app icon. `color` Type: `string` Path: `notification.color` (Android only) Tint color for the push notification image when it appears in the notification tray. Defaults to `#ffffff` 6 character long hex color string, for example, `'#000000'` `iosDisplayInForeground` Type: `boolean` Path: `notification.iosDisplayInForeground` Whether or not to display notifications when the app is in the foreground on iOS. `_displayInForeground` option in the individual push notification message overrides this option. [Learn more.](https://docs.expo.dev/push-notifications/receiving-notifications/#foreground-notification-behavior) Defaults to `false`. `androidMode` Type: `enum` Path: `notification.androidMode` Show each push notification individually (`default`) or collapse into one (`collapse`). `androidCollapsedTitle` Type: `string` Path: `notification.androidCollapsedTitle` If `androidMode` is set to `collapse`, this title is used for the collapsed notification message. For example, `'#{unread_notifications} new interactions'`. `androidStatusBar` Type: `object` Configuration for the status bar on Android. For more details navigate to [Configuring StatusBar](https://docs.expo.dev/guides/configuring-statusbar/). `barStyle` Type: `enum` Path: `androidStatusBar.barStyle` Configures the status bar icons to have a light or dark color. Valid values: `light-content`, `dark-content`. Defaults to `dark-content` `backgroundColor` Type: `string` Path: `androidStatusBar.backgroundColor` Specifies the background color of the status bar. Defaults to `#00000000` (transparent) for `dark-content` bar style and `#00000088` (semi-transparent black) for `light-content` bar style 6 character long hex color string `'#RRGGBB'`, for example, `'#000000'` for black. Or 8 character long hex color string `'#RRGGBBAA'`, for example, `'#00000088'` for semi-transparent black. `hidden` Type: `boolean` Path: `androidStatusBar.hidden` Instructs the system whether the status bar should be visible or not. Defaults to `false` `translucent` Type: `boolean` Path: `androidStatusBar.translucent` When false, the system status bar pushes the content of your app down (similar to `position: relative`). When true, the status bar floats above the content in your app (similar to `position: absolute`). Defaults to `true` to match the iOS status bar behavior (which can only float above content). Explicitly setting this property to `true` will add `android:windowTranslucentStatus` to `styles.xml` and may cause unexpected keyboard behavior on Android when using the `softwareKeyboardLayoutMode` set to `resize`. In this case you will have to use `KeyboardAvoidingView` to manage the keyboard layout. `androidNavigationBar` Type: `object` Configuration for the bottom navigation bar on Android. Can be used to configure the `expo-navigation-bar` module in EAS Build. `visible` Type: `enum` Path: `androidNavigationBar.visible` Determines how and when the navigation bar is shown. [Learn more](https://developer.android.com/training/system-ui/immersive). Requires `expo-navigation-bar` be installed in your project. Valid values: `leanback`, `immersive`, `sticky-immersive` `leanback` results in the navigation bar being hidden until the first touch gesture is registered. `immersive` results in the navigation bar being hidden until the user swipes up from the edge where the navigation bar is hidden. `sticky-immersive` is identical to `'immersive'` except that the navigation bar will be semi-transparent and will be hidden again after a short period of time. `barStyle` Type: `enum` Path: `androidNavigationBar.barStyle` Configure the navigation bar icons to have a light or dark color. Supported on Android Oreo and newer. Valid values: `'light-content'`, `'dark-content'` `backgroundColor` Type: `string` Path: `androidNavigationBar.backgroundColor` Specifies the background color of the navigation bar. 6 character long hex color string, for example, `'#000000'` `developmentClient` Type: `object` Settings that apply specifically to running this app in a development client `silentLaunch` Type: `boolean` Path: `developmentClient.silentLaunch` If true, the app will launch in a development client with no additional dialogs or progress indicators, just like in a standalone app. `scheme` One of types: * `string` matching the following pattern: `^[a-z][a-z0-9+.-]*$` `{ "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9+.-]*$" } }` URL scheme(s) to link into your app. For example, if we set this to `'demo'`, then demo:// URLs would open your app when tapped. This is a build-time configuration, it has no effect in Expo Go. String beginning with a lowercase letter followed by any combination of lowercase letters, digits, "+", "." or "-" Bare Workflow `extra` Type: `object` Any extra fields you want to pass to your experience. Values are accessible via `Constants.expoConfig.extra` ([Learn more](https://docs.expo.dev/versions/latest/sdk/constants/#constantsmanifest)) `updates` Type: `object` Configuration for the expo-updates library `enabled` Type: `boolean` Path: `updates.enabled` Whether the updates system will run. Defaults to true. If set to false, builds will only use code and assets bundled at time of build. `checkAutomatically` Type: `enum` Path: `updates.checkAutomatically` By default, expo-updates will check for updates every time the app is loaded. Set this to `ON_ERROR_RECOVERY` to disable automatic checking unless recovering from an error. Set this to `NEVER` to disable automatic checking. Valid values: `ON_LOAD` (default value), `ON_ERROR_RECOVERY`, `WIFI_ONLY`, `NEVER` `useEmbeddedUpdate` Type: `boolean` Path: `updates.useEmbeddedUpdate` Whether to load the embedded update. Defaults to true. If set to false, an update will be fetched at launch. When set to false, ensure that `checkAutomatically` is set to `ON_LOAD` and `fallbackToCacheTimeout` is large enough for the initial remote update to download. This should not be used in production. `fallbackToCacheTimeout` Type: `number` Path: `updates.fallbackToCacheTimeout` How long (in ms) to wait for the app to check for and fetch a new update upon launch before falling back to the most recent update already present on the device. Defaults to 0. Must be between 0 and 300000 (5 minutes). If the startup update check takes longer than this value, any update downloaded during the check will be applied upon the next app launch. `url` Type: `string` Path: `updates.url` URL from which expo-updates will fetch update manifests `codeSigningCertificate` Type: `string` Path: `updates.codeSigningCertificate` Local path of a PEM-formatted X.509 certificate used for verifying codesigned updates. When provided, all updates downloaded by expo-updates must be signed. `codeSigningMetadata` Type: `object` Path: `updates.codeSigningMetadata` Metadata for `codeSigningCertificate` `alg` Type: `enum` Path: `updates.codeSigningMetadata.alg` Algorithm used to generate manifest code signing signature. Valid values: `rsa-v1_5-sha256` `keyid` Type: `string` Path: `updates.codeSigningMetadata.keyid` Identifier for the key in the certificate. Used to instruct signing mechanisms when signing or verifying signatures. `requestHeaders` Type: `object` Path: `updates.requestHeaders` Extra HTTP headers to include in HTTP requests made by `expo-updates` when fetching manifests or assets. These may override preset headers. `assetPatternsToBeBundled` Type: `array` Path: `updates.assetPatternsToBeBundled` Array of glob patterns specifying which files should be included in updates. Glob patterns are relative to the project root. A value of `['**']` will match all asset files within the project root. When not supplied all asset files will be included. Example: Given a value of `['app/images/**/*.png', 'app/fonts/**/*.woff']` all `.png` files in all subdirectories of `app/images` and all `.woff` files in all subdirectories of `app/fonts` will be included in updates. `disableAntiBrickingMeasures` Type: `boolean` Path: `updates.disableAntiBrickingMeasures` Whether to disable the built-in expo-updates anti-bricking measures. Defaults to false. If set to true, this will allow overriding certain configuration options from the JS API, which is liable to leave an app in a bricked state if not done carefully. This should not be used in production. `useNativeDebug` Type: `boolean` Path: `updates.useNativeDebug` Enable debugging of native code with updates enabled. Defaults to false. If set to true, the EX\_UPDATES\_NATIVE\_DEBUG environment variable will be set in Podfile.properties.json and gradle.properties. This causes Xcode and Android Studio debug builds to be built with expo-updates enabled, and JS debugging (with dev client or packager) disabled. This should not be used in production. `locales` Type: `object` Provide overrides by locale for System Dialog prompts like Permissions Boxes Bare Workflow `plugins` Type: `array` Config plugins for adding extra functionality to your project. [Learn more](https://docs.expo.dev/guides/config-plugins/). Bare Workflow `splash` Type: `object` Configuration for loading and splash screen for standalone apps. Bare Workflow `backgroundColor` Type: `string` Path: `splash.backgroundColor` Color to fill the loading screen background 6 character long hex color string, for example, `'#000000'` Bare Workflow `resizeMode` Type: `enum` Path: `splash.resizeMode` Determines how the `image` will be displayed in the splash loading screen. Must be one of `cover` or `contain`, defaults to `contain`. `image` Type: `string` Path: `splash.image` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `jsEngine` Type: `enum` @deprecated This field will be removed in a future release. When it is removed, you can continue using JavaScriptCore instead of Hermes by following the instructions in [@react-native-community/javascriptcore](https://github.com/react-native-community/javascriptcore). Specifies the JavaScript engine for Android apps. Defaults to `hermes`. Valid values: `hermes`, `jsc`. Bare Workflow `newArchEnabled` Type: `boolean` A Boolean value that indicates whether the app should use the new architecture. Defaults to true. `buildCacheProvider` Type: `undefined` Enable downloading cached builds from remote. `ios` Type: `object` Configuration that is specific to the iOS platform. `appleTeamId` Type: `string` Path: `ios.appleTeamId` The Apple development team ID to use for all native targets. You can find your team ID in [the Apple Developer Portal](https://developer.apple.com/help/account/manage-your-team/locate-your-team-id/). `publishManifestPath` Type: `string` Path: `ios.publishManifestPath` The manifest for the iOS version of your app will be written to this path during publish. `publishBundlePath` Type: `string` Path: `ios.publishBundlePath` The bundle for the iOS version of your app will be written to this path during publish. `bundleIdentifier` Type: `string` Path: `ios.bundleIdentifier` The bundle identifier for your iOS standalone app. You make it up, but it needs to be unique on the App Store. See [this StackOverflow question](http://stackoverflow.com/questions/11347470/what-does-bundle-identifier-mean-in-the-ios-project). iOS bundle identifier notation unique name for your app. For example, `host.exp.expo`, where `exp.host` is our domain and `expo` is our app name. Bare Workflow `buildNumber` Type: `string` Path: `ios.buildNumber` Build number for your iOS standalone app. Corresponds to `CFBundleVersion` and must match Apple's [specified format](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion). (Note: Transporter will pull the value for `Version Number` from `expo.version` and NOT from `expo.ios.buildNumber`.) Bare Workflow `backgroundColor` Type: `string` Path: `ios.backgroundColor` The background color for your iOS app, behind any of your React views. Overrides the top-level `backgroundColor` key if it is present. Requires `expo-system-ui` be installed in your project to work on iOS. 6 character long hex color string, for example, `'#000000'` `scheme` One of types: * `string` matching the following pattern: `^[a-z][a-z0-9+.-]*$` `{ "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9+.-]*$" } }` URL scheme(s) to link into your iOS app. Schemes added to this field will be merged with the schemes in the `scheme` key at the top level of the config. String beginning with a lowercase letter followed by any combination of lowercase letters, digits, "+", "." or "-" Bare Workflow `icon` One of types: * `string` matching the following pattern: `\.icon$` * `string` * An `object` with the following properties: ``` `light` Type: `string` Path: `ios.icon.light` The light icon. It will appear when neither dark nor tinted icons are used, or if they are not provided. `dark` Type: `string` Path: `ios.icon.dark` The dark icon. It will appear for the app when the user's system appearance is dark. See Apple's [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/app-icons#iOS-iPadOS) for more information. `tinted` Type: `string` Path: `ios.icon.tinted` The tinted icon. It will appear for the app when the user's system appearance is tinted. See Apple's [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/app-icons#iOS-iPadOS) for more information. ``` Local path or remote URL to an image to use for your app's icon on iOS. Alternatively, an object specifying different icons for various system appearances (e.g., dark, tinted) can be provided. You can also provide a path to a .icon directory. If specified, this overrides the top-level `icon` key. Use a 1024x1024 icon which follows Apple's interface guidelines for icons, including color profile and transparency. Expo will generate the other required sizes. This icon will appear on the home screen and within the Expo Go app. `appStoreUrl` Type: `string` Path: `ios.appStoreUrl` URL to your app on the Apple App Store, if you have deployed it there. This is used to link to your store page from your Expo project page if your app is public. Example `"https://apps.apple.com/us/app/expo-client/id982107779"` `bitcode` Type: `undefined` Path: `ios.bitcode` Enable iOS Bitcode optimizations in the native build. Accepts the name of an iOS build configuration to enable for a single configuration and disable for all others, e.g. Debug, Release. Not available in Expo Go. Defaults to `undefined` which uses the template's predefined settings. `config` Type: `object` Path: `ios.config` Note: This property key is not included in the production manifest and will evaluate to `undefined`. It is used internally only in the build process, because it contains API keys that some may want to keep private. `branch` Type: `object` Path: `ios.config.branch` [Branch](https://branch.io/) key to hook up Branch linking services. `apiKey` Type: `string` Path: `ios.config.branch.apiKey` Your Branch API key `usesNonExemptEncryption` Type: `boolean` Path: `ios.config.usesNonExemptEncryption` Sets `ITSAppUsesNonExemptEncryption` in the standalone ipa's Info.plist to the given boolean value. `googleMapsApiKey` Type: `string` Path: `ios.config.googleMapsApiKey` [Google Maps iOS SDK](https://developers.google.com/maps/documentation/ios-sdk/start) key for your standalone app. `googleServicesFile` Type: `string` Path: `ios.googleServicesFile` [Firebase Configuration File](https://support.google.com/firebase/answer/7015592) Location of the `GoogleService-Info.plist` file for configuring Firebase. `supportsTablet` Type: `boolean` Path: `ios.supportsTablet` Whether your standalone iOS app supports tablet screen sizes. Defaults to `false`. Bare Workflow `isTabletOnly` Type: `boolean` Path: `ios.isTabletOnly` If true, indicates that your standalone iOS app does not support handsets, and only supports tablets. Bare Workflow `requireFullScreen` Type: `boolean` Path: `ios.requireFullScreen` If true, indicates that your standalone iOS app does not support Slide Over and Split View on iPad. Defaults to `false` Bare Workflow `userInterfaceStyle` Type: `enum` Path: `ios.userInterfaceStyle` Configuration to force the app to always use the light or dark user-interface appearance, such as "dark mode", or make it automatically adapt to the system preferences. If not provided, defaults to `light`. `infoPlist` Type: `object` Path: `ios.infoPlist` Dictionary of arbitrary configuration to add to your standalone app's native Info.plist. Applied prior to all other Expo-specific configuration. No other validation is performed, so use this at your own risk of rejection from the App Store. `entitlements` Type: `object` Path: `ios.entitlements` Dictionary of arbitrary configuration to add to your standalone app's native \*.entitlements (plist). Applied prior to all other Expo-specific configuration. No other validation is performed, so use this at your own risk of rejection from the App Store. `privacyManifests` Type: `object` Path: `ios.privacyManifests` Dictionary of privacy manifest definitions to add to your app's native PrivacyInfo.xcprivacy file. [Learn more](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files) `NSPrivacyAccessedAPITypes` Type: `array` Path: `ios.privacyManifests.NSPrivacyAccessedAPITypes` A list of required reasons of why your app uses restricted API categories. [Learn more](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api) `NSPrivacyAccessedAPIType` Type: `string` Path: `ios.privacyManifests.NSPrivacyAccessedAPITypes.NSPrivacyAccessedAPIType` A string that identifies the category of required reason APIs your app uses `NSPrivacyAccessedAPITypeReasons` Type: `array` Path: `ios.privacyManifests.NSPrivacyAccessedAPITypes.NSPrivacyAccessedAPITypeReasons` A list of reasons for a specific category. `NSPrivacyTrackingDomains` Type: `array` Path: `ios.privacyManifests.NSPrivacyTrackingDomains` A list of domains that your app uses for tracking. `NSPrivacyTracking` Type: `boolean` Path: `ios.privacyManifests.NSPrivacyTracking` A Boolean that indicates whether your app or third-party SDK uses data for tracking. `NSPrivacyCollectedDataTypes` Type: `array` Path: `ios.privacyManifests.NSPrivacyCollectedDataTypes` A list of collected data types that your app uses. `NSPrivacyCollectedDataType` Type: `string` Path: `ios.privacyManifests.NSPrivacyCollectedDataTypes.NSPrivacyCollectedDataType` `NSPrivacyCollectedDataTypeLinked` Type: `boolean` Path: `ios.privacyManifests.NSPrivacyCollectedDataTypes.NSPrivacyCollectedDataTypeLinked` `NSPrivacyCollectedDataTypeTracking` Type: `boolean` Path: `ios.privacyManifests.NSPrivacyCollectedDataTypes.NSPrivacyCollectedDataTypeTracking` `NSPrivacyCollectedDataTypePurposes` Type: `array` Path: `ios.privacyManifests.NSPrivacyCollectedDataTypes.NSPrivacyCollectedDataTypePurposes` `associatedDomains` Type: `array` Path: `ios.associatedDomains` An array that contains Associated Domains for the standalone app. [Learn more](https://developer.apple.com/documentation/safariservices/supporting_associated_domains). Entries must follow the format `applinks:[:port number]`. [Learn more](https://developer.apple.com/documentation/safariservices/supporting_associated_domains). Bare Workflow `usesIcloudStorage` Type: `boolean` Path: `ios.usesIcloudStorage` A boolean indicating if the app uses iCloud Storage for `DocumentPicker`. See `DocumentPicker` docs for details. Bare Workflow `usesAppleSignIn` Type: `boolean` Path: `ios.usesAppleSignIn` A boolean indicating if the app uses Apple Sign-In. See `AppleAuthentication` docs for details. `usesBroadcastPushNotifications` Type: `boolean` Path: `ios.usesBroadcastPushNotifications` A boolean indicating if the app uses Push Notifications Broadcast option for Push Notifications capability. If true, EAS CLI will use the value during capability syncing. If EAS CLI is not used, this configuration will not have any effect unless another tool is used to operate on it, so enable the capability manually on the Apple Developer Portal in that case. `accessesContactNotes` Type: `boolean` Path: `ios.accessesContactNotes` A Boolean value that indicates whether the app may access the notes stored in contacts. You must [receive permission from Apple](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_contacts_notes) before you can submit your app for review with this capability. `splash` Type: `object` Path: `ios.splash` Configuration for loading and splash screen for standalone iOS apps. `backgroundColor` Type: `string` Path: `ios.splash.backgroundColor` Color to fill the loading screen background 6 character long hex color string, for example, `'#000000'` `resizeMode` Type: `enum` Path: `ios.splash.resizeMode` Determines how the `image` will be displayed in the splash loading screen. Must be one of `cover` or `contain`, defaults to `contain`. `image` Type: `string` Path: `ios.splash.image` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `tabletImage` Type: `string` Path: `ios.splash.tabletImage` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `dark` Type: `object` Path: `ios.splash.dark` Configuration for loading and splash screen for standalone iOS apps in dark mode. `backgroundColor` Type: `string` Path: `ios.splash.dark.backgroundColor` Color to fill the loading screen background 6 character long hex color string, for example, `'#000000'` `resizeMode` Type: `enum` Path: `ios.splash.dark.resizeMode` Determines how the `image` will be displayed in the splash loading screen. Must be one of `cover` or `contain`, defaults to `contain`. `image` Type: `string` Path: `ios.splash.dark.image` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `tabletImage` Type: `string` Path: `ios.splash.dark.tabletImage` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `jsEngine` Type: `enum` Path: `ios.jsEngine` @deprecated This field will be removed in a future release. When it is removed, you can continue using JavaScriptCore instead of Hermes by following the instructions in [@react-native-community/javascriptcore](https://github.com/react-native-community/javascriptcore). Specifies the JavaScript engine for iOS apps. Not supported in Expo Go. Defaults to `hermes`. Valid values: `hermes`, `jsc`. Bare Workflow `newArchEnabled` Type: `boolean` Path: `ios.newArchEnabled` A Boolean value that indicates whether the iOS app should use the new architecture. `runtimeVersion` One of types: * `string` matching the following pattern: `^[a-zA-Z\d][a-zA-Z\d._+()-]{0,254}$` * `string` matching the following pattern: `^exposdk:((\d+\.\d+\.\d+)|(UNVERSIONED))$` * An `object` with the following properties: ``` `policy` Type: `enum` Path: `ios.runtimeVersion.policy` Valid values: `nativeVersion`, `sdkVersion`, `appVersion`, `fingerprint`. ``` Property indicating compatibility between an iOS build's native code and an OTA update for the iOS platform. If provided, this will override the value of the top level `runtimeVersion` key on iOS. `version` Type: `string` Path: `ios.version` Your iOS app version. Takes precedence over the root `version` field. In addition to this field, you'll also use `ios.buildNumber` — read more about how to version your app [here](https://docs.expo.dev/distribution/app-stores/#versioning-your-app). This corresponds to `CFBundleShortVersionString`. The required format can be found [here](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring). Bare Workflow `android` Type: `object` Configuration that is specific to the Android platform. `publishManifestPath` Type: `string` Path: `android.publishManifestPath` The manifest for the Android version of your app will be written to this path during publish. `publishBundlePath` Type: `string` Path: `android.publishBundlePath` The bundle for the Android version of your app will be written to this path during publish. `package` Type: `string` Path: `android.package` The package name for your Android standalone app. You make it up, but it needs to be unique on the Play Store. See [this StackOverflow question](http://stackoverflow.com/questions/6273892/android-package-name-convention). Reverse DNS notation unique name for your app. Valid Android Application ID. For example, `com.example.app`, where `com.example` is our domain and `app` is our app. The name may only contain lowercase and uppercase letters (a-z, A-Z), numbers (0-9) and underscores (\_), separated by periods (.). Each component of the name should start with a lowercase letter. Bare Workflow `versionCode` Type: `integer` Path: `android.versionCode` Version number required by Google Play. Increment by one for each release. Must be a positive integer. [Learn more](https://developer.android.com/studio/publish/versioning.html) Bare Workflow `backgroundColor` Type: `string` Path: `android.backgroundColor` The background color for your Android app, behind any of your React views. Overrides the top-level `backgroundColor` key if it is present. 6 character long hex color string, for example, `'#000000'` Bare Workflow `userInterfaceStyle` Type: `enum` Path: `android.userInterfaceStyle` Configuration to force the app to always use the light or dark user-interface appearance, such as "dark mode", or make it automatically adapt to the system preferences. If not provided, defaults to `light`. Requires `expo-system-ui` be installed in your project to work on Android. `scheme` One of types: * `string` matching the following pattern: `^[a-z][a-z0-9+.-]*$` `{ "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9+.-]*$" } }` URL scheme(s) to link into your Android app. Schemes added to this field will be merged with the schemes in the `scheme` key at the top level of the config. String beginning with a lowercase letter followed by any combination of lowercase letters, digits, "+", "." or "-" Bare Workflow `icon` Type: `string` Path: `android.icon` Local path or remote URL to an image to use for your app's icon on Android. If specified, this overrides the top-level `icon` key. We recommend that you use a 1024x1024 png file (transparency is recommended for the Google Play Store). This icon will appear on the home screen and within the Expo Go app. `adaptiveIcon` Type: `object` Path: `android.adaptiveIcon` Settings for an Adaptive Launcher Icon on Android. [Learn more](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive) `foregroundImage` Type: `string` Path: `android.adaptiveIcon.foregroundImage` Local path or remote URL to an image to use for your app's icon on Android. If specified, this overrides the top-level `icon` and the `android.icon` keys. Should follow the [specified guidelines](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive). This icon will appear on the home screen. `monochromeImage` Type: `string` Path: `android.adaptiveIcon.monochromeImage` Local path or remote URL to an image representing the Android 13+ monochromatic icon. Should follow the [specified guidelines](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive). This icon will appear on the home screen when the user enables 'Themed icons' in system settings on a device running Android 13+. `backgroundImage` Type: `string` Path: `android.adaptiveIcon.backgroundImage` Local path or remote URL to a background image for your app's Adaptive Icon on Android. If specified, this overrides the `backgroundColor` key. Must have the same dimensions as `foregroundImage`, and has no effect if `foregroundImage` is not specified. Should follow the [specified guidelines](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive). `backgroundColor` Type: `string` Path: `android.adaptiveIcon.backgroundColor` Color to use as the background for your app's Adaptive Icon on Android. Defaults to white, `#FFFFFF`. Has no effect if `foregroundImage` is not specified. 6 character long hex color string, for example, `'#000000'` `playStoreUrl` Type: `string` Path: `android.playStoreUrl` URL to your app on the Google Play Store, if you have deployed it there. This is used to link to your store page from your Expo project page if your app is public. Example `"https://play.google.com/store/apps/details?id=host.exp.exponent"` `permissions` Type: `array` Path: `android.permissions` A list of permissions to add to the app `AndroidManifest.xml` during prebuild. For example: `['android.permission.SCHEDULE_EXACT_ALARM']` Bare Workflow `blockedPermissions` Type: `array` Path: `android.blockedPermissions` List of permissions to block in the final `AndroidManifest.xml`. This is useful for removing permissions that are added by native package `AndroidManifest.xml` files which are merged into the final manifest. Internally this feature uses the `tools:node="remove"` XML attribute to remove permissions. Not available in Expo Go. `googleServicesFile` Type: `string` Path: `android.googleServicesFile` [Firebase Configuration File](https://support.google.com/firebase/answer/7015592) Location of the `google-services.json` file for configuring Firebase. Including this key automatically enables FCM in your standalone app. Bare Workflow `config` Type: `object` Path: `android.config` Note: This property key is not included in the production manifest and will evaluate to `undefined`. It is used internally only in the build process, because it contains API keys that some may want to keep private. `branch` Type: `object` Path: `android.config.branch` [Branch](https://branch.io/) key to hook up Branch linking services. `apiKey` Type: `string` Path: `android.config.branch.apiKey` Your Branch API key `googleMaps` Type: `object` Path: `android.config.googleMaps` [Google Maps Android SDK](https://developers.google.com/maps/documentation/android-api/signup) configuration for your standalone app. `apiKey` Type: `string` Path: `android.config.googleMaps.apiKey` Your Google Maps Android SDK API key `googleMobileAdsAppId` Type: `string` Path: `android.config.googleMobileAdsAppId` [Google Mobile Ads App ID](https://support.google.com/admob/answer/6232340) Google AdMob App ID. `googleMobileAdsAutoInit` Type: `boolean` Path: `android.config.googleMobileAdsAutoInit` A boolean indicating whether to initialize Google App Measurement and begin sending user-level event data to Google immediately when the app starts. The default in Expo (Client and in standalone apps) is `false`. [Sets the opposite of the given value to the following key in `Info.plist`](https://developers.google.com/admob/ios/eu-consent#delay_app_measurement_optional) `splash` Type: `object` Path: `android.splash` Configuration for loading and splash screen for managed and standalone Android apps. `backgroundColor` Type: `string` Path: `android.splash.backgroundColor` Color to fill the loading screen background 6 character long hex color string, for example, `'#000000'` `resizeMode` Type: `enum` Path: `android.splash.resizeMode` Determines how the `image` will be displayed in the splash loading screen. Must be one of `cover`, `contain` or `native`, defaults to `contain`. `image` Type: `string` Path: `android.splash.image` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `mdpi` Type: `string` Path: `android.splash.mdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Natural sized image (baseline)` `hdpi` Type: `string` Path: `android.splash.hdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 1.5x` `xhdpi` Type: `string` Path: `android.splash.xhdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 2x` `xxhdpi` Type: `string` Path: `android.splash.xxhdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 3x` `xxxhdpi` Type: `string` Path: `android.splash.xxxhdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 4x` `dark` Type: `object` Path: `android.splash.dark` Configuration for loading and splash screen for managed and standalone Android apps in dark mode. `backgroundColor` Type: `string` Path: `android.splash.dark.backgroundColor` Color to fill the loading screen background 6 character long hex color string, for example, `'#000000'` `resizeMode` Type: `enum` Path: `android.splash.dark.resizeMode` Determines how the `image` will be displayed in the splash loading screen. Must be one of `cover`, `contain` or `native`, defaults to `contain`. `image` Type: `string` Path: `android.splash.dark.image` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `mdpi` Type: `string` Path: `android.splash.dark.mdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Natural sized image (baseline)` `hdpi` Type: `string` Path: `android.splash.dark.hdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 1.5x` `xhdpi` Type: `string` Path: `android.splash.dark.xhdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 2x` `xxhdpi` Type: `string` Path: `android.splash.dark.xxhdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 3x` `xxxhdpi` Type: `string` Path: `android.splash.dark.xxxhdpi` Local path or remote URL to an image to fill the background of the loading screen in "native" mode. Image size and aspect ratio are up to you. [Learn more](https://developer.android.com/training/multiscreen/screendensities) `Scale 4x` `intentFilters` Type: `array` Path: `android.intentFilters` Configuration for setting an array of custom intent filters in Android manifest. [Learn more](https://developer.android.com/guide/components/intents-filters) Bare Workflow Example `[ { "autoVerify": true, "action": "VIEW", "data": { "scheme": "https", "host": "*.example.com" }, "category": [ "BROWSABLE", "DEFAULT" ] } ]` `autoVerify` Type: `boolean` Path: `android.intentFilters.autoVerify` You may also use an intent filter to set your app as the default handler for links (without showing the user a dialog with options). To do so use `true` and then configure your server to serve a JSON file verifying that you own the domain. [Learn more](https://developer.android.com/training/app-links) `action` Type: `string` Path: `android.intentFilters.action` `data` Type: `undefined` Path: `android.intentFilters.data` `category` Type: `undefined` Path: `android.intentFilters.category` `allowBackup` Type: `boolean` Path: `android.allowBackup` Allows your user's app data to be automatically backed up to their Google Drive. If this is set to false, no backup or restore of the application will ever be performed (this is useful if your app deals with sensitive information). Defaults to the Android default, which is `true`. `softwareKeyboardLayoutMode` Type: `enum` Path: `android.softwareKeyboardLayoutMode` Determines how the software keyboard will impact the layout of your application. This maps to the `android:windowSoftInputMode` property. Defaults to `resize`. Valid values: `resize`, `pan`. `jsEngine` Type: `enum` Path: `android.jsEngine` @deprecated This field will be removed in a future release. When it is removed, you can continue using JavaScriptCore instead of Hermes by following the instructions in [@react-native-community/javascriptcore](https://github.com/react-native-community/javascriptcore). Specifies the JavaScript engine for Android apps. Defaults to `hermes`. Valid values: `hermes`, `jsc`. Bare Workflow `newArchEnabled` Type: `boolean` Path: `android.newArchEnabled` A Boolean value that indicates whether the Android app should use the new architecture. `runtimeVersion` One of types: * `string` matching the following pattern: `^[a-zA-Z\d][a-zA-Z\d._+()-]{0,254}$` * `string` matching the following pattern: `^exposdk:((\d+\.\d+\.\d+)|(UNVERSIONED))$` * An `object` with the following properties: ``` `policy` Type: `enum` Path: `android.runtimeVersion.policy` Valid values: `nativeVersion`, `sdkVersion`, `appVersion`, `fingerprint`. ``` Property indicating compatibility between a Android build's native code and an OTA update for the Android platform. If provided, this will override the value of top level `runtimeVersion` key on Android. `version` Type: `string` Path: `android.version` Your android app version. Takes precedence over the root `version` field. In addition to this field, you'll also use `android.versionCode` — read more about how to version your app [here](https://docs.expo.dev/distribution/app-stores/#versioning-your-app). This corresponds to `versionName`. The required format can be found [here](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring). Bare Workflow `edgeToEdgeEnabled` Type: `boolean` Path: `android.edgeToEdgeEnabled` Enable your app to run in [edge-to-edge](https://developer.android.com/develop/ui/views/layout/edge-to-edge) mode. Default to false. Bare Workflow `predictiveBackGestureEnabled` Type: `boolean` Path: `android.predictiveBackGestureEnabled` Enable your app to use the [predictive back gesture](https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture) on Android 13 (API level 33) and later. Default to false. Bare Workflow `web` Type: `object` Configuration that is specific to the web platform. `output` Type: `enum` Path: `web.output` Sets the export method for the web app for both `expo start` and `expo export`. `static` statically renders HTML files for every route in the `app/` directory, which is available only in Expo Router apps. `single` outputs a Single Page Application (SPA), with a single `index.html` in the output folder, and has no statically indexable HTML. `server` outputs static HTML, and API Routes for hosting with a custom Node.js server. Defaults to `single`. `favicon` Type: `string` Path: `web.favicon` Relative path of an image to use for your app's favicon. `name` Type: `string` Path: `web.name` Defines the title of the document, defaults to the outer level name `shortName` Type: `string` Path: `web.shortName` A short version of the app's name, 12 characters or fewer. Used in app launcher and new tab pages. Maps to `short_name` in the PWA manifest.json. Defaults to the `name` property. Maximum 12 characters long `lang` Type: `string` Path: `web.lang` Specifies the primary language for the values in the name and short\_name members. This value is a string containing a single language tag. `scope` Type: `string` Path: `web.scope` Defines the navigation scope of this website's context. This restricts what web pages can be viewed while the manifest is applied. If the user navigates outside the scope, it returns to a normal web page inside a browser tab/window. If the scope is a relative URL, the base URL will be the URL of the manifest. `themeColor` Type: `string` Path: `web.themeColor` Defines the color of the Android tool bar, and may be reflected in the app's preview in task switchers. 6 character long hex color string, for example, `'#000000'` `description` Type: `string` Path: `web.description` Provides a general description of what the pinned website does. `dir` Type: `enum` Path: `web.dir` Specifies the primary text direction for the name, short\_name, and description members. Together with the lang member, it helps the correct display of right-to-left languages. `display` Type: `enum` Path: `web.display` Defines the developers’ preferred display mode for the website. `startUrl` Type: `string` Path: `web.startUrl` The URL that loads when a user launches the application (e.g., when added to home screen), typically the index. Note: This has to be a relative URL, relative to the manifest URL. `orientation` Type: `enum` Path: `web.orientation` Defines the default orientation for all the website's top level browsing contexts. `backgroundColor` Type: `string` Path: `web.backgroundColor` Defines the expected “background color” for the website. This value repeats what is already available in the site’s CSS, but can be used by browsers to draw the background color of a shortcut when the manifest is available before the stylesheet has loaded. This creates a smooth transition between launching the web application and loading the site's content. 6 character long hex color string, for example, `'#000000'` `barStyle` Type: `enum` Path: `web.barStyle` If content is set to default, the status bar appears normal. If set to black, the status bar has a black background. If set to black-translucent, the status bar is black and translucent. If set to default or black, the web content is displayed below the status bar. If set to black-translucent, the web content is displayed on the entire screen, partially obscured by the status bar. `preferRelatedApplications` Type: `boolean` Path: `web.preferRelatedApplications` Hints for the user agent to indicate to the user that the specified native applications (defined in expo.ios and expo.android) are recommended over the website. `dangerous` Type: `object` Path: `web.dangerous` Experimental features. These will break without deprecation notice. `splash` Type: `object` Path: `web.splash` Configuration for PWA splash screens. Bare Workflow `backgroundColor` Type: `string` Path: `web.splash.backgroundColor` Color to fill the loading screen background 6 character long hex color string, for example, `'#000000'` `resizeMode` Type: `enum` Path: `web.splash.resizeMode` Determines how the `image` will be displayed in the splash loading screen. Must be one of `cover` or `contain`, defaults to `contain`. `image` Type: `string` Path: `web.splash.image` Local path or remote URL to an image to fill the background of the loading screen. Image size and aspect ratio are up to you. Must be a .png. `config` Type: `object` Path: `web.config` Firebase web configuration. Used by the expo-firebase packages on both web and native. [Learn more](https://firebase.google.com/docs/reference/js/firebase.html#initializeapp) `firebase` Type: `object` Path: `web.config.firebase` `apiKey` Type: `string` Path: `web.config.firebase.apiKey` `authDomain` Type: `string` Path: `web.config.firebase.authDomain` `databaseURL` Type: `string` Path: `web.config.firebase.databaseURL` `projectId` Type: `string` Path: `web.config.firebase.projectId` `storageBucket` Type: `string` Path: `web.config.firebase.storageBucket` `messagingSenderId` Type: `string` Path: `web.config.firebase.messagingSenderId` `appId` Type: `string` Path: `web.config.firebase.appId` `measurementId` Type: `string` Path: `web.config.firebase.measurementId` `bundler` Type: `enum` Path: `web.bundler` Sets the bundler to use for the web platform. Only supported in the local CLI `npx expo`. Defaults to `webpack` if the `@expo/webpack-config` package is installed, if not, it defaults to `metro`. `experiments` Type: `object` Enable experimental features that may be unstable, unsupported, or removed without deprecation notices. `baseUrl` Type: `string` Path: `experiments.baseUrl` Export a website relative to a subpath of a domain. The path will be prepended as-is to links to all bundled resources. Prefix the path with a `/` (recommended) to load all resources relative to the server root. If the path does not start with a `/` then resources will be loaded relative to the code that requests them, this could lead to unexpected behavior. Example '/subpath'. Defaults to '' (empty string). `buildCacheProvider` Type: `undefined` Path: `experiments.buildCacheProvider` @deprecated This field is not longer marked as experimental and will be removed in a future release, use the `buildCacheProvider` field instead. `supportsTVOnly` Type: `boolean` Path: `experiments.supportsTVOnly` If true, indicates that this project does not support tablets or handsets, and only supports Apple TV and Android TV `tsconfigPaths` Type: `boolean` Path: `experiments.tsconfigPaths` Enable tsconfig/jsconfig `compilerOptions.paths` and `compilerOptions.baseUrl` support for import aliases in Metro. `typedRoutes` Type: `boolean` Path: `experiments.typedRoutes` Enable support for statically typed links in Expo Router. This feature requires TypeScript be set up in your Expo Router v2 project. `turboModules` Type: `boolean` Path: `experiments.turboModules` Enables Turbo Modules, which are a type of native modules that use a different way of communicating between JS and platform code. When installing a Turbo Module you will need to enable this experimental option (the library still needs to be a part of Expo SDK already, like react-native-reanimated v2). Turbo Modules do not support remote debugging and enabling this option will disable remote debugging. `reactCanary` Type: `boolean` Path: `experiments.reactCanary` Experimentally use a vendored canary build of React for testing upcoming features. `reactCompiler` Type: `boolean` Path: `experiments.reactCompiler` Experimentally enable React Compiler. `reactServerComponentRoutes` Type: `boolean` Path: `experiments.reactServerComponentRoutes` Experimentally enable React Server Components by default in Expo Router and concurrent routing for transitions. `reactServerFunctions` Type: `boolean` Path: `experiments.reactServerFunctions` Experimentally enable React Server Functions support in Expo CLI and Expo Router. `_internal` Type: `object` Internal properties for developer tools `pluginHistory` Type: `object` Path: `_internal.pluginHistory` List of plugins already run on the config --- # babel A reference for Babel configuration file. [](https://github.com/expo/expo/edit/main/docs/pages/versions/unversioned/config/babel.mdx) Babel is used as the JavaScript compiler to transform modern JavaScript (ES6+) into a version compatible with the JavaScript engine on mobile devices. Each new Expo project created using `npx create-expo-app` configures Babel automatically and uses [`babel-preset-expo`](https://github.com/expo/expo/tree/main/packages/babel-preset-expo) as the default preset. There is no need to create a babel.config.js file unless you need to customize the Babel configuration. ## Create babel.config.js If your project requires a custom Babel configuration, you need to create the babel.config.js file in your project by following the steps below: 1. Navigate to the root of your project and run the following command inside a terminal. This will generate a babel.config.js file in the root of your project. `npx expo customize babel.config.js` 2. The babel.config.js file contains the following default configuration: `module.exports = function (api) { api.cache(true); return { presets: ['babel-preset-expo'], }; };` 3. If you make a change to the babel.config.js file, you need to restart the Metro bundler to apply the changes and use `--clear` option from Expo CLI to clear the Metro bundler cache: ## babel-preset-expo [`babel-preset-expo`](https://github.com/expo/expo/tree/main/packages/babel-preset-expo) is the default preset used in Expo projects. It extends the default React Native preset (`@react-native/babel-preset`) and adds support for decorators, tree-shaking web libraries, and loading font icons. --- # metro A reference of available configurations in Metro. [](https://github.com/expo/expo/edit/main/docs/pages/versions/unversioned/config/metro.mdx) See more information about metro.config.js in the [customizing Metro guide](https://docs.expo.dev/guides/customizing-metro). ## Environment variables Expo CLI can load environment variables from .env files. Learn more about how to use environment variables in Expo CLI in the [environment variables guide](https://docs.expo.dev/guides/environment-variables). EAS CLI uses a different mechanism for environment variables, except when it invokes Expo CLI for compiling and bundling. Learn more about [environment variables in EAS](https://docs.expo.dev/build-reference/variables). If you are migrating an older project, then you should ignore local env files by adding the following to your .gitignore: `# local env files .env*.local` ### Disabling dotenv files Dotenv file loading can be fully disabled in Expo CLI by enabling the `EXPO_NO_DOTENV` environment variable, before invoking any Expo CLI command. `# All users can run cross-env, followed by the Expo CLI command` `npx cross-env EXPO_NO_DOTENV=1 expo start` `# Alternatively, macOS and Linux users can define the environment variable, then run npx, followed by the Expo CLI command` `-` `EXPO_NO_DOTENV=1 npx expo start` ### Disabling `EXPO_PUBLIC_`\-prefixed client environment variables Environment variables prefixed with `EXPO_PUBLIC_` will be exposed to the app at build-time. For example, `EXPO_PUBLIC_API_KEY` will be available as `process.env.EXPO_PUBLIC_API_KEY`. Client environment variable inlining can be disabled with the environment variable `EXPO_NO_CLIENT_ENV_VARS=1`, this must be defined before any bundling is performed. `# All users can run cross-env, followed by the Expo CLI command` `npx cross-env EXPO_NO_CLIENT_ENV_VARS=1 expo start` `# Alternatively, macOS and Linux users can define the environment variable, then run npx, followed by the Expo CLI command` `-` `EXPO_NO_CLIENT_ENV_VARS=1 npx expo start` ## CSS > CSS support is under development and currently only works on web. Expo supports CSS in your project. You can import CSS files from any component. CSS Modules are also supported. CSS support is enabled by default. You can disable the feature by setting `isCSSEnabled` in the Metro config. `/** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname, { // Disable CSS support. isCSSEnabled: false, });` ### Global CSS > Global styles are web-only, usage will cause your application to diverge visually on native. You can import a CSS file from any component. The CSS will be applied to the entire page. Here, we'll define a global style for the class name `.container`: `.container { background-color: red; }` We can then use the class name in our component by importing the stylesheet and using `.container`: ``import './styles.css'; import { View } from 'react-native'; export default function App() { return ( <> {/* Use `className` to assign the style with React DOM components. */}
Hello World
{/* Use `style` with the following syntax to append class names in React Native for web. */} Hello World ); }`` You can also import stylesheets that are vendored in libraries, just like you would any node module: `// Applies the styles app-wide. import 'emoji-mart/css/emoji-mart.css';` * On native, all global stylesheets are automatically ignored. * Hot reloading is supported for global stylesheets, simply save the file and the changes will be applied. ### CSS Modules > CSS Modules for native are under development and currently only work on web. CSS Modules are a way to scope CSS to a specific component. This is useful for avoiding naming collisions and for ensuring that styles are only applied to the intended component. In Expo, CSS Modules are defined by creating a file with the `.module.css` extension. The file can be imported from any component. The exported value is an object with the class names as keys and the web-only scoped names as the values. The import `unstable_styles` can be used to access `react-native-web`\-safe styles. CSS Modules support platform extensions to allow you to define different styles for different platforms. For example, you can define a `module.ios.css` and `module.android.css` file to define styles for Android and iOS respectively. You'll need to import without the extension, for example: ``// Importing `./App.module.ios.css`: - import styles from './App.module.css'; + import styles from './App.module';`` Flipping the extension, for example, `App.ios.module.css` will not work and result in a universal module named `App.ios.module`. > You cannot pass styles to the `className` prop of a React Native or React Native for web component. Instead, you must use the `style` prop. `import styles, { unstable_styles } from './App.module.css'; export default function Page() { return ( <> Hello World Hello World {/* Web-only usage: */}

Hello World

); }` * On web, all CSS values are available. CSS is not processed or auto-prefixed like it is with the React Native Web `StyleSheet` API. You can use `postcss.config.js` to autoprefix your CSS. * CSS Modules use [lightningcss](https://github.com/parcel-bundler/lightningcss) under the hood, check [the issues](https://github.com/parcel-bundler/lightningcss/issues) for unsupported features. ### PostCSS [PostCSS](https://github.com/postcss/postcss) can be customized by adding a `postcss.config.json` file to the root of your project. This file should export a function that returns a PostCSS configuration object. For example: `{ "plugins": { "tailwindcss": {} } }` Both `postcss.config.json` and `postcss.config.js` are supported, but `postcss.config.json` enables better caching. Expo CLI automatically handles CSS vendor prefixes with built-in support for [browserslist](https://browsersl.ist/). Avoid adding `autoprefixer` as this duplicates the functionality and slows down bundling. #### Resetting cache after updates Changing the Post CSS or `browserslist` config will require you to clear the Metro cache: `npx expo start --clear` `npx expo export --clear` ### browserslist Expo has automatic [browserslist](https://browsersl.ist/) support via the Rust-based CSS parser. You can customize the CSS vendor prefixes and browser support by adding a browserslist field to your package.json file. For example: `{ "browserslist": [">0.2%", "not dead", "not op_mini all"] }` ### SASS Expo Metro has _partial_ support for SCSS/SASS. To setup, install the `sass` package in your project: Then, ensure [CSS is setup](https://docs.expo.dev/versions/latest/config/metro#css) in the metro.config.js file. * When `sass` is installed, then modules without extensions will be resolved in the following order: `scss`, `sass`, `css`. * Only use the intended syntax with `sass` files. * Importing other files from inside a scss/sass file is not currently supported. ### Tailwind > Standard Tailwind CSS supports only web platform. For universal support, use a library such as [NativeWind](https://www.nativewind.dev/), which allows creating styled React Native components with Tailwind CSS. [ Tailwind CSS Learn how to configure and use Tailwind CSS in your Expo project. ](https://docs.expo.dev/guides/tailwind) ## Extending the Babel transformer Expo's Metro config uses a custom `transformer.babelTransformerPath` value to ensure `expo-babel-preset` is always used and web/Node.js environments are supported. If you want to extend the Babel transformer, import the upstream transformer from `@expo/metro-config/babel-transformer` instead of `metro-react-native-babel-transformer`. For example: `const upstreamTransformer = require('@expo/metro-config/babel-transformer'); module.exports.transform = async ({ src, filename, options }) => { // Do something custom for SVG files... if (filename.endsWith('.svg')) { src = '...'; } // Pass the source through the upstream Expo transformer. return upstreamTransformer.transform({ src, filename, options }); };` ## Custom resolving Expo CLI extends the default Metro resolver to add features like Web, Server, and tsconfig aliases support. You can similarly customize the default resolution behavior of Metro by chaining the `config.resolver.resolveRequest` function. `const { getDefaultConfig } = require('expo/metro-config'); /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname); config.resolver.resolveRequest = (context, moduleName, platform) => { if (moduleName.startsWith('my-custom-resolver:')) { // Logic to resolve the module name to a file path... // NOTE: Throw an error if there is no resolution. return { filePath: 'path/to/file', type: 'sourceFile', }; } // Ensure you call the default resolver. return context.resolveRequest(context, moduleName, platform); }; module.exports = config;` Unlike traditional bundlers, Metro shared the same resolver function across all platforms. As a result, you can mutate the resolution settings dynamically on each request with the `context` object. ### Mocking modules If you want a module to be empty for a given platform, you can return a `type: 'empty'` object from the resolver. The following example will cause `lodash` to be empty on web: `const { getDefaultConfig } = require('expo/metro-config'); /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname); config.resolver.resolveRequest = (context, moduleName, platform) => { if (platform === 'web' && moduleName === 'lodash') { return { type: 'empty', }; } // Ensure you call the default resolver. return context.resolveRequest(context, moduleName, platform); }; module.exports = config;` This technique is equivalent to using empty externals in Webpack or Vite, but with the added benefit of being able to target specific platforms. ### Virtual modules Metro doesn't support virtual modules at the moment. One technique you can use to obtain similar behavior is to create a module in the `node_modules/.cache/...` directory and redirect the resolution to that file. The following example will create a module at `node_modules/.cache/virtual/virtual-module.js` and redirect the resolution of `virtual:my-module` to that file: `const path = require('path'); const fs = require('fs'); const { getDefaultConfig } = require('expo/metro-config'); /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname); const virtualPath = path.resolve(__dirname, 'node_modules/.cache/virtual/virtual-module.js'); // Create the virtual module in a generated directory... fs.mkdirSync(path.dirname(virtualPath), { recursive: true }); fs.writeFileSync(virtualPath, 'export default "Hello World";'); config.resolver.resolveRequest = (context, moduleName, platform) => { if (moduleName === 'virtual:my-module') { return { filePath: virtualPath, type: 'sourceFile', }; } // Ensure you call the default resolver. return context.resolveRequest(context, moduleName, platform); }; module.exports = config;` This can be used to emulate `externals` with custom imports. For example, if you want to redirect `require('expo')` to something custom like `SystemJS.require('expo')`, you can create a virtual module that exports `SystemJS.require('expo')` and redirect the resolution of `expo` to that file. ## Custom transforming > Transformations are heavily cached in Metro. If you update something, use the `--clear` flag to see updates. For example, `npx expo start --clear`. Metro doesn't have a very expressive plugin system for transforming files, instead opt to use the [babel.config.js](https://docs.expo.dev/versions/latest/config/babel) and caller object to customize the transformation. ``module.exports = function (api) { // Get the platform that Expo CLI is transforming for. const platform = api.caller(caller => (caller ? caller.platform : 'ios')); // Detect if the bundling operation is for Hermes engine or not, e.g. `'hermes'` | `undefined`. const engine = api.caller(caller => (caller ? caller.engine : null)); // Is bundling for a server environment, e.g. API Routes. const isServer = api.caller(caller => (caller ? caller.isServer : false)); // Is bundling for development or production. const isDev = api.caller(caller => caller ? caller.isDev : process.env.BABEL_ENV === 'development' || process.env.NODE_ENV === 'development' ); // Ensure the config is not cached otherwise the platform will not be updated. api.cache(false); // You can alternatively provide a more robust CONFIG cache invalidation: // api.cache.invalidate(() => platform); return { presets: ['babel-preset-expo'], plugins: [ // Add a plugin based on the platform... platform === 'web' && 'my-plugin', // Ensure you filter out falsy values. ].filter(Boolean), }; };`` If the caller doesn't have `engine`, `platform`, `bundler`, and so on, then ensure you are using `@expo/metro-config/babel-transformer` for the transformer. If you're using a custom transformer then it may need to extend the Expo transformer. Always try to implement custom logic in the resolver if possible, caching is much simpler and easier to reason about. For example, if you need to remap an import, it's simpler and faster to resolve to a static file with the resolver than to parse all possible import methods and remap them with the transformer. Always use `babel-preset-expo` as the default Babel preset, this ensures the transformation is always compatible with Expo runtimes. `babel-preset-expo` uses all of the caller inputs internally to optimize for a given platform, engine, and environment. ## Node.js built-ins When bundling for a server environment, Expo's Metro config automatically supports externalizing Node.js built-in modules (`fs`, `path`, `node:crypto`, and more) based on the current Node.js version. If the CLI is bundling for a browser environment, then built-ins will first check if the module is installed locally, then fallback on an empty shim. For example, if you install `path` for use in the browser, this can be used, otherwise, the module will automatically be skipped. ## Environment settings > These environment variables will not be defined in test environments. Expo's Metro config injects build settings that can be used in the client bundle via environment variables. All variables will be inlined and cannot be used dynamically. For example, `process.env["EXPO_BASE_URL"]` won't work. * `process.env.EXPO_BASE_URL` exposes the base URL defined in `experiments.baseUrl`. This is used in Expo Router to respect the production base URL for deployment. ## Bundle splitting Expo CLI automatically splits web bundles into multiple chunks based on async imports in production. This feature requires `@expo/metro-runtime` to be installed and imported somewhere in the entry bundle (available by default in Expo Router). Shared dependencies of async bundles are merged into a single chunk to reduce the number of requests. For example, if you have two async bundles that import `lodash`, then the library is merged into a single initial chunk. The chunk splitting heuristic cannot be customized. For example: `export function add(a, b) { return a + b; }` `import '@expo/metro-runtime'; // This will be split into a separate chunk. import('./math').then(math => { console.log(math.add(1, 2)); });` When you run `npx expo export -p web`, the bundles are split into multiple files, and the entry bundle is added to the main HTML file. `@expo/metro-runtime` adds the runtime code that loads and evaluates the async bundles. ## Source map debug ID If a bundle is exported with an external source map, a [Debug ID](https://sentry.engineering/blog/the-case-for-debug-ids) annotation will be added to the end of the file, along with a matching `debugId` in the source map for corresponding the files together. If no source maps are exported, or inline source maps are used then this annotation will not be added. `// //# debugId=` The associated `*.js.map` or `*.hbc.map` source map will be a JSON file containing an equivalent `debugId` property. The `debugId` will be injected before hermes bytecode generation to ensure matching in all cases. The `debugId` is a deterministic hash of the bundle's contents without the external bundle splitting references. This is the same value used to create a chunks filename but formatted as a UUID. For example, `431b98e2-c997-4975-a3d9-2987710abd44`. `@expo/metro-config` injects `debugId` during `npx expo export` and `npx expo export:embed`. Any additional optimization steps in `npx expo export:embed` like Hermes bytecode generation will need to have the `debugId` injected manually. ## Metro require runtime You can optionally enable a custom Metro `require` implementation with the environment variable `EXPO_USE_METRO_REQUIRE=1`. This runtime has the following features: * String module IDs that are human-readable and make missing module errors easier to follow. * Deterministic IDs that are the same between runs and across modules (required for React Server Components in development). * Removed support for legacy RAM bundles. ## Magic import comments > Available from SDK 52 on all platforms. Server environments such as Workers, and Node.js support import arbitrary files at runtime, so you may want to keep `import` syntax in-tact instead of using Metro's require system. You can opt-out dynamic imports with the `/* @metro-ignore */` comment in `import()` statements. ``// Manually ensure `./my-module.js` is included in the correct spot relative to the module. const myModule = await import(/* @metro-ignore */ './my-module.js');`` Expo CLI will skip the `./my-module.js` dependency and assume that the developer has manually added it to the output bundle. Internally, this is used for exporting custom server code that dynamically switches between files based on the request. Avoid using this syntax for native bundles since `import()` is generally not available in React Native with Hermes enabled. Many React libraries shipped the Webpack `/* webpackIgnore: true */` comment to achieve similar behavior. To bridge the gap, we've also added support for Webpack's comment but recommend using the Metro equivalent in your app. ## ES Module resolution > This sections applies from SDK 53 on all platforms. Metro resolves ES Module `import` and CommonJS `require` with separate resolution strategies. Previously, Metro applied the classic Node.js module resolution strategy (which matches Node.js versions before v12), with some additions to support ES Modules. In this resolution strategy, Metro resolves modules from `node_modules`, JS files, optionally while omitting extensions, such as `.js`, and uses `package.json` fields such as `main`, `module`, and `react-native`. Now, with the modern ES Modules resolution strategy, Metro instead resolves modules from `node_modules`, then matches different `package.json` fields, such as `exports`, [a nested map of sub-paths a package exposes](https://nodejs.org/api/packages.html#conditional-exports), and `main`. Depending on how a package is imported, one of these two resolution strategies will be used. Typically, a file that is imported with `import` from a Node module (rather than `require`), will use the ES Modules resolution strategy, and fall back on regular classic Node.js resolution. A file that wasn't resolved with ES Modules resolution or has been imported with CommonJS `require` will use the classic resolution strategy. ### `package.json:exports` When performing ES Modules resolution, Metro will look at the `package.json:exports` conditions map. This is a mapping of import subpaths and conditions to files in the Node module package. For example, a package that always exposes an index.js file, and matches Metro's classic CommonJS module resolution, may specify a map with the `default` condition. `{ "exports": { "default": "./index.js" } }` However, a package providing both a CommonJS and ES Modules entrypoint may provide a mapping with the `import` and `require` conditions. `{ "exports": { "import": "./index.mjs", "require": "./index.cjs" } }` By default, Metro will match different conditions depending on the platform and whether the resolution has started from a CommonJS `require` call, or an ES Modules `import` statement and will change the condition accordingly. For native platforms, the condition `react-native` is added, for web exports, the `browser` condition is added, and for server exports (such as API routes or React Server functions), the `node`, `react-server`, and `workerd` conditions are added. These conditions aren't matched in the order they're defined in. Instead, they're matched against the order of properties in the `package.json:exports` map. TypeScript performs ES Module resolution separately from Metro and will also respect `package.json:exports` maps, when its `compilerOptions.moduleResolution` configuration option has either been set to `"bundler"` (which matches Metro's behaviour more closely) or to `"node16"` / `"nodenext"`. TypeScript will however also match the `types` condition. As such, types may not resolve properly when a package doesn't put the `types` condition first in its exports map. Since an exports map may contain subpaths, a package import may not have to match a file in the package's modules folder any longer, but may be a "redirected" import. Importing `'package/submodule'` may match a different file than node\_modules/package/submodule.js if it's specified in `package.json:exports`. `{ "exports": { ".": "./index.js", "./submodule": "./submodule/submodule.js" } }` If you're encountering packages that are incompatible or unprepared for the new ES Modules resolution strategy, you may be able to resolve problems by patching its `package.json` file and add or correct its `package.json:exports` conditions map. However, it's also possible to prevent Metro from using `package.json:exports` maps in its resolution by disabling the `unstable_enablePackageExports` option. `const { getDefaultConfig } = require('expo/metro-config'); /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname); config.resolver.unstable_enablePackageExports = false; module.exports = config;` ## Asset imports When assets are imported, a virtual module is created to represent the data required for importing the asset. On native platforms, an asset will be a numeric ID: `1`, `2`, `3`, and so on, which can be looked up using `require("@react-native/assets-registry/registry").getAssetByID()`. On web and server platforms, the asset will change depending on the file type. If the file is an image, then the asset will be `{ uri: string, width?: number, height?: number }`, otherwise the asset will be a `string` representing the remote URL for the asset. The assets can be used as follows: `import { Image } from 'react-native'; import asset from './img.png'; function Demo() { return ; }` In API routes, you can always assume the type of the asset will not be a number: `import asset from './img.png'; export async function GET(req: Request) { const ImageData = await fetch( new URL( // Access the asset URI. asset.uri, // Append to the current request URL origin. req.url ) ).then(res => res.arrayBuffer()); return new Response(ImageData, { headers: { 'Content-Type': 'image/png', }, }); }` ## Web workers > This feature is experimental and subject to breaking changes. `new Worker(new URL('./worker', window.location.href));` Expo Metro has experimental web worker support. This feature is currently web-only and does not work on native, usage on native will trigger an error "Property 'Worker' doesn't exist". Web workers can be used to offload work to a separate thread on web, allowing the main thread to remain responsive. This is useful for computationally expensive tasks, such as image processing, cryptography, or other tasks that would otherwise block the main thread. Workers can be generated inline using `Blob`, but sometimes you may want to leverage modern features like TypeScript or importing other modules. Web workers depend on Expo bundle splitting support, which means you need to either use Expo Router or install and import `@expo/metro-runtime`. You also cannot use the environment `EXPO_NO_METRO_LAZY=1` with web workers. Consider the following example of a worker that doubles a number: `self.onmessage = ({ data }) => { const result = data * 2; // Example: double the number self.postMessage(result); };` This worker file can be imported as a `Worker` in the main app: ``// worker is of type `Worker` const worker = new Worker(new URL('./worker', window.location.href)); worker.onmessage = ({ data }) => { console.log(`Worker responded: ${data}`); }; worker.postMessage(5);`` Behind the scenes, Expo CLI is generating code like this: `const worker = new Worker( new URL('/worker.bundle?platform=web&dev=true&etc', window.location.href) );` The generated bundle URL changes based on development/production to ensure the worker is loaded and bundled correctly. Unlike traditional bundle splitting, a worker file needs to contain its own copy of all modules and cannot depend on common modules in the main bundle. The native API `Worker` is traditionally unavailable in React Native and not provided by the Expo SDK, so even though this bundling feature technically works for all platforms, it's only useful on web. You could theoretically write a native Expo module that polyfills the `Worker` API if you want to support native platforms too. Alternatively, you can use the "worklet" API in React Native Reanimated to offload work to a separate thread on native. Alternatively, you can import Workers using the public path by first putting a transformed JS file in the public directory, then referencing it in the worker import with a variable: `// Will avoid the transform and use the public path directly. const worker = new Worker('/worker.js'); // The variable breaks the transform causing the literal path to be used instead of the transformed path. const path = '/worker.js'; const anotherWorker = new Worker(new URL(path, window.location.href));` Using a variable in the `Worker` constructor is not supported for bundling. To inspect the internal URL, you may use the internal syntax `require.unstable_resolveWorker('./path/to/worker.js')` to get the URL fragment. ## Bare workflow setup > This guide is versioned and will need to be revisited when upgrading/downgrading Expo. Alternatively, use [Expo Prebuild](https://docs.expo.dev/workflow/prebuild) for fully automated setup. Projects that don't use [Expo Prebuild](https://docs.expo.dev/workflow/prebuild) must configure native files to ensure the Expo Metro config is always used to bundle the project. These modifications are meant to replace `npx react-native bundle` and `npx react-native start` with `npx expo export:embed` and `npx expo start` respectively. ### metro.config.js Ensure the metro.config.js extends `expo/metro-config`: `const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); module.exports = config;` ### `android/app/build.gradle` The Android app/build.gradle must be configured to use Expo CLI for production bundling. Modify the `react` config object: `react { ... + // Use Expo CLI to bundle the app, this ensures the Metro config + // works correctly with Expo projects. + cliFile = new File(["node", "--print", "require.resolve('@expo/cli')"].execute(null, rootDir).text.trim()) + bundleCommand = "export:embed" }` ### `ios/.xcodeproj/project.pbxproj` In your ios/.xcodeproj/project.pbxproj file, replace the following scripts: #### "Start Packager" script Remove the "Start Packager" script. The dev server must be started with `npx expo` before/after running the app. ``- FD10A7F022414F080027D42C /* Start Packager */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Start Packager"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\nexport RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > `$NODE_BINARY --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/.packager.env'\"`\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open `$NODE_BINARY --print \"require('path').dirname(require.resolve('expo/package.json')) + '/scripts/launchPackager.command'\"` || echo \"Can't start packager automatically\"\n fi\nfi\n"; - showEnvVarsInLog = 0; - };`` #### "Bundle React Native code and images" script ``+ shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli')\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";`` Alternatively, in the Xcode project, select the "Bundle React Native code and images" build phase and add the following modifications: `` if [[ -f "$PODS_ROOT/../.xcode.env" ]]; then source "$PODS_ROOT/../.xcode.env" fi if [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then source "$PODS_ROOT/../.xcode.env.local" fi # The project root by default is one level up from the ios directory export PROJECT_ROOT="$PROJECT_DIR"/.. if [[ "$CONFIGURATION" = *Debug* ]]; then export SKIP_BUNDLING=1 fi + if [[ -z "$ENTRY_FILE" ]]; then + # Set the entry JS file using the bundler's entry resolution. + export ENTRY_FILE="$("$NODE_BINARY" -e "require('expo/scripts/resolveAppEntry')" "$PROJECT_ROOT" ios absolute | tail -n 1)" + fi + if [[ -z "$CLI_PATH" ]]; then + # Use Expo CLI + export CLI_PATH="$("$NODE_BINARY" --print "require.resolve('@expo/cli')")" + fi + if [[ -z "$BUNDLE_COMMAND" ]]; then + # Default Expo CLI command for bundling + export BUNDLE_COMMAND="export:embed" + fi `"$NODE_BINARY" --print "require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'"` `` > You can set `CLI_PATH`, `BUNDLE_COMMAND`, and `ENTRY_FILE` environment variables to overwrite these defaults. ### Custom entry file By default, React Native only supports using a root `index.js` file as the entry file (or platform-specific variation like `index.ios.js`). Expo projects allow using any entry file, but this requires addition bare setup. #### Development Development mode entry files can be enabled by using the [`expo-dev-client`](https://docs.expo.dev/versions/latest/sdk/dev-client) package. Alternatively you can add the following configuration: `- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif }` `@Override protected String getJSMainModuleName() { - return "index"; + return ".expo/.virtual-metro-entry"; }` #### Production In your ios/.xcodeproj/project.pbxproj file, replace the "Bundle React Native code and images" script to set `$ENTRY_FILE` according using Metro: ``+ shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli')\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";`` The Android app/build.gradle must be configured to use Metro module resolution to find the root entry file. Modify the `react` config object: `+ def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() react { + entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim()) }` --- # package-json A reference for Expo-specific properties that can be used in the package.json file. [](https://github.com/expo/expo/edit/main/docs/pages/versions/unversioned/config/package-json.mdx) package.json is a JSON file that contains the metadata for a JavaScript project. This is a reference to Expo-specific properties that can be used in the package.json file. ## `install.exclude` The following commands perform a version check for the libraries installed in a project and give a warning when a library's version is different from the version recommended by Expo: * `npx expo start` and `npx expo-doctor` * `npx expo install` (when installing a new version of that library or using `--check` or `--fix` options) By specifying the library under the `install.exclude` array in the package.json file, you can exclude it from the version checks: `{ "expo": { "install": { "exclude": ["expo-updates", "expo-splash-screen"] } } }` ## `autolinking` Allows configuring module resolution behavior by using `autolinking` property in package.json. For complete reference, see [Autolinking configuration](https://docs.expo.dev/modules/autolinking#configuration). ## `doctor` Allows configuring the behavior of the [`npx expo-doctor`](https://docs.expo.dev/develop/tools#expo-doctor) command. ### `reactNativeDirectoryCheck` By default, Expo Doctor validates your project's packages against the [React Native directory](https://reactnative.directory/). This check throws a warning with a list of packages that are not included in the React Native Directory. You can customize this check by adding the following configuration in your project's package.json file: `{ "expo": { "doctor": { "reactNativeDirectoryCheck": { "enabled": true, "exclude": ["/foo/", "bar"], "listUnknownPackages": true } } } }` By default, the check is enabled and unknown packages are listed. ### `appConfigFieldsNotSyncedCheck` Expo Doctor checks if your project includes native project directories such as android or ios. If these directories exist but are not listed in your .gitignore or [.easignore](https://docs.expo.dev/build-reference/easignore) files, Expo Doctor verifies the presence of an app config file. If this file exists, it means your project is configured to use [Prebuild](https://docs.expo.dev/workflow/prebuild). When the android or ios directories are present, EAS Build does not sync app config properties to the native projects. Expo Doctor throws a warning if these conditions are true. You can disable or enable this check by adding the following configuration to your project's package.json file: `{ "expo": { "doctor": { "appConfigFieldsNotSyncedCheck": { "enabled": false } } } }` --- # accelerometer A library that provides access to the device's accelerometer sensor. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-sensors)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-sensors/CHANGELOG.md)[](https://www.npmjs.com/package/expo-sensors) `Accelerometer` from `expo-sensors` provides access to the device accelerometer sensor(s) and associated listeners to respond to changes in acceleration in three-dimensional space, meaning any movement or vibration. ## Installation `npx expo install expo-sensors` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Usage `import { useState, useEffect } from 'react'; import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { Accelerometer } from 'expo-sensors'; export default function App() { const [{ x, y, z }, setData] = useState({ x: 0, y: 0, z: 0, }); const [subscription, setSubscription] = useState(null); const _slow = () => Accelerometer.setUpdateInterval(1000); const _fast = () => Accelerometer.setUpdateInterval(16); const _subscribe = () => { setSubscription(Accelerometer.addListener(setData)); }; const _unsubscribe = () => { subscription && subscription.remove(); setSubscription(null); }; useEffect(() => { _subscribe(); return () => _unsubscribe(); }, []); return ( Accelerometer: (in gs where 1g = 9.81 m/s^2) x: {x} y: {y} z: {z} {subscription ? 'On' : 'Off'} Slow Fast ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingHorizontal: 20, }, text: { textAlign: 'center', }, buttonContainer: { flexDirection: 'row', alignItems: 'stretch', marginTop: 15, }, button: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#eee', padding: 10, }, middleButton: { borderLeftWidth: 1, borderRightWidth: 1, borderColor: '#ccc', }, });` ## API `import { Accelerometer } from 'expo-sensors';` ## Classes ### `Accelerometer` Type: Class extends `[DeviceSensor](https://docs.expo.dev/versions/latest/sdk/sensors)<[AccelerometerMeasurement](#accelerometermeasurement)>` A base class for subscribable sensors. The events emitted by this class are measurements specified by the parameter type `Measurement`. Accelerometer Methods ### `addListener(listener)` Subscribe for updates to the accelerometer. A subscription that you can call `remove()` on when you would like to unsubscribe the listener. ### `getListenerCount()` Returns the registered listeners count. ### `getPermissionsAsync()` Checks user's permissions for accessing sensor. ### `hasListeners()` Returns boolean which signifies if sensor has any listeners registered. ### `isAvailableAsync()` > You should always check the sensor availability before attempting to use it. Returns whether the accelerometer is enabled on the device. On mobile web, you must first invoke `Accelerometer.requestPermissionsAsync()` in a user interaction (i.e. touch event) before you can use this module. If the `status` is not equal to `granted` then you should inform the end user that they may have to open settings. On web this starts a timer and waits to see if an event is fired. This should predict if the iOS device has the device orientation API disabled in Settings > Safari > Motion & Orientation Access. Some devices will also not fire if the site isn't hosted with HTTPS as `DeviceMotion` is now considered a secure API. There is no formal API for detecting the status of `DeviceMotion` so this API can sometimes be unreliable on web. A promise that resolves to a `boolean` denoting the availability of the accelerometer. ### `removeAllListeners()` Removes all registered listeners. ### `removeSubscription(subscription)` Removes the given subscription. ### `requestPermissionsAsync()` Asks the user to grant permissions for accessing sensor. ### `setUpdateInterval(intervalMs)` Set the sensor update interval. ## Interfaces ### `Subscription` A subscription object that allows to conveniently remove an event listener from the emitter. Subscription Methods ### `remove()` Removes an event listener for which the subscription has been created. After calling this function, the listener will no longer receive any events from the emitter. ## Types ### `AccelerometerMeasurement` Each of these keys represents the acceleration along that particular axis in g-force (measured in `g`s). A `g` is a unit of gravitational force equal to that exerted by the earth’s gravitational field (`9.81 m/s^2`). ### `PermissionExpiration` Literal Type: `union` Permission expiration time. Currently, all permissions are granted permanently. Acceptable values are: `'never'` | `number` ### `PermissionResponse` An object obtained by permissions get and request functions. ## Enums ### `PermissionStatus` #### `DENIED` `PermissionStatus.DENIED = "denied"` User has denied the permission. #### `GRANTED` `PermissionStatus.GRANTED = "granted"` User has granted the permission. #### `UNDETERMINED` `PermissionStatus.UNDETERMINED = "undetermined"` User hasn't granted or denied the permission yet. --- # app-integrity A library that provides access to Google's Play Integrity API on Android and Apple's App Attest service on iOS. [](https://github.com/expo/expo/tree/main/packages/expo-app-integrity)[](https://github.com/expo/expo/tree/main/packages/expo-app-integrity/CHANGELOG.md)[](https://www.npmjs.com/package/@expo/app-integrity) `@expo/app-integrity` provides APIs to help ensure your backend resources are accessed only by legitimate installations of your app running on genuine devices. It uses Google's [Play Integrity APIs](https://developer.android.com/google/play/integrity) on Android and Apple's [App Attest service](https://developer.apple.com/documentation/devicecheck/establishing-your-app-s-integrity) on iOS to verify app authenticity, helping prevent unauthorized clients, modified apps, or automated scripts from making requests to your server. Generally, `@expo/app-integrity` helps your server tell the difference between: * Your real app running on a real device * Anything else (modified apps, scripts, emulators) It does this by using the platform-recommended app attestation services. ## Installation `npx expo install @expo/app-integrity` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Usage on Android `@expo/app-integrity` uses Play Integrity's [Standard request flow](https://developer.android.com/google/play/integrity/standard) for integrity checks. ### Configuration Refer to the [Play Integrity setup guide](https://developer.android.com/google/play/integrity/setup#set-integrity-responses) for instructions to enable integrity APIs in your app. ### Prepare the integrity token provider (one time) You need to prepare the integrity token provider before you make integrity check requests. You can do this when your app launches or in the background before the integrity check is needed. `import * as AppIntegrity from '@expo/app-integrity'; const cloudProjectNumber = 'your-cloud-project-number'; await AppIntegrity.prepareIntegrityTokenProviderAsync(cloudProjectNumber);` ### Request an integrity token (on demand) Whenever your app makes a server request that you want to check is genuine, you request an integrity token and send it to your app's backend server for decryption and verification. Then, your backend server can determine how to act. `const requestHash = '2cp24z...'; const result = await AppIntegrity.requestIntegrityCheckAsync(requestHash);` Before calling [`requestIntegrityCheckAsync`](https://docs.expo.dev/versions/latest/sdk/app-integrity#appintegrityrequestintegritycheckasyncrequesthash), ensure that [`prepareIntegrityTokenProviderAsync`](https://docs.expo.dev/versions/latest/sdk/app-integrity#appintegrityprepareintegritytokenproviderasynccloudprojectnumber) was called successfully. In this example, `requestHash` is a hash unique to the specific user action being verified. You can call [`requestIntegrityCheckAsync`](https://docs.expo.dev/versions/latest/sdk/app-integrity#appintegrityprepareintegritytokenproviderasynccloudprojectnumber) multiple times with different hashes for different user actions. On success, send the result to your server for verification. > Note: If your app uses the same token provider for too long, the token provider can expire which results in the `ERR_APP_INTEGRITY_PROVIDER_INVALID` error on the next token request. You should handle this error by requesting a new provider by calling `prepareIntegrityTokenProviderAsync` again. ### Decrypt and verify the integrity verdict Refer [Play Integrity's guide](https://developer.android.com/google/play/integrity/standard#decrypt-and) to verify the integrity token in your server. ### Additional resources * [Google Pay Integrity documentation](https://developer.android.com/google/play/integrity/overview): Refer to Google's official guide to understand the APIs and verification flow that power `@expo/app-integrity`. ``` ``` * [Play Integrity Standard request flow](https://developer.android.com/google/play/integrity/standard): This page describes making standard API requests for integrity verdicts, which are supported on Android 5.0 (API level 21) or higher. You can make a standard API request for an integrity verdict whenever your app is making a server call to check whether the interaction is genuine. ``` ``` * [About Integrity verdicts](https://developer.android.com/google/play/integrity/verdicts): The integrity verdict communicates information about the validity of devices, apps, and accounts. Your app's server can use the resulting payload in a decrypted, verified verdict to determine how best to proceed with a particular action or request in your app. ``` ``` * [Handling error codes](https://developer.android.com/google/play/integrity/reference/com/google/android/play/core/integrity/model/StandardIntegrityErrorCode): If your app makes a Play Integrity API request and the call fails, your app receives an error code. These errors can happen for various reasons, such as environmental issues like a weak network connection, problems with your API integration, or malicious activity and active attacks. ``` ``` ## Usage on iOS ### Configuration In Xcode, go to Signing & Capabilities, click \+ Capability, add App Attest. Xcode will automatically add the required entitlement to your app. > Note: To use the App Attest service, your app must have an App ID that you register on the Apple Developer website. For verification logic on your server, see [Validating apps that connect to your server](https://developer.apple.com/documentation/devicecheck/validating-apps-that-connect-to-your-server). ### Check if the device supports app attestation Not all devices can use the App Attest service, so it's important to have your app run a compatibility check before accessing the service. If the user's app doesn't pass the compatibility check, gracefully bypass the service. You can check for availability by reading the `isSupported` property. `import * as AppIntegrity from '@expo/app-integrity'; if (AppIntegrity.isSupported) { // Perform key generation and attestation. } // Continue with your server API access.` > Note: App Attest is not supported on iOS Simulator. > Most app extensions don't support App Attest. Generally, when executing code in these extensions, bypass key generation and attestation, even if the `isSupported` method property is `true`. The only app extensions that support App Attest are watchOS extensions in watchOS 9 or later. For these extensions, you can use the results from `isSupported` to indicate whether your WatchKit extension bypasses attestation. ### Create a key pair For each user account on each device running your app, generate a unique, hardware-based, cryptographic key pair by calling the `generateKey` method. `const keyId = await AppIntegrity.generateKeyAsync();` On success, the method returns a key identifier (`keyId`) that you use later to access the key. Record the identifier in persistent storage because there's no way to use the key without the identifier and no way to get the identifier later. The device automatically stores the associated private key in the Secure Enclave, from where the App Attest service can use it to create signatures, but from where no process can ever directly read or modify it, ensuring its security. > If you create a key pair in an App Clip, use the same key pair in the corresponding app. To support this, be sure to store the identifier in a shared container accessible from your full app. See Expo’s guide on sharing a database between apps/extensions using [expo-sqlite](https://docs.expo.dev/versions/latest/sdk/sqlite/#sharing-a-database-between-appsextensions-ios), or use React Native MMKV's [App Groups / extensions](https://github.com/mrousavy/react-native-mmkv?tab=readme-ov-file#app-groups-or-extensions) shared storage to persist the identifier across both targets. Don't reuse a key among multiple users on a device because this weakens security protections. In particular, it becomes hard to detect an attack that uses a single compromised device to serve multiple remote users running a compromised version of your app. For more information, see [Assessing fraud risk](https://developer.apple.com/documentation/devicecheck/assessing-fraud-risk). ### Get a challenge from your server Request a unique, one-time challenge from your server. This challenge will be embedded in the attestation step below, ensuring it can't be reused by an attacker. The challenge should be at least 16 bytes long to provide enough entropy so that guessing it is infeasible. ### Certify the key pairs as valid Pass the `keyId` alongwith the challenge from your server created in the previous steps in `attestKey` method as shown below: `const attestationObject = await AppIntegrity.attestKeyAsync(keyId, challenge);` On success, send the received `attestationObject` and the `keyId` to your server for verification. If the method returns `ERR_APP_INTEGRITY_SERVER_UNAVAILABLE` error, try attestation again later with the same key. For any other error, discard the key identifier and create a new key when you want to try again. > If your app already has millions of daily active users and you want to start calling the `attestKey` method to initiate attestation from your app, review the [Preparing to use the app attest service](https://developer.apple.com/documentation/DeviceCheck/preparing-to-use-the-app-attest-service) for guidance on safely ramping your users. Your server deems the app instance to be valid if it can successfully verify the attestation object. In this case, be sure to persistently store the key identifier — not the attestation object — in your app to sign server requests in the future. ### Generate assertions on sensitive requests After successfully verifying a key's attestation, your server can require the app to assert its legitimacy for any or all future server requests. The app does this by signing the request. In the app, obtain a unique, one-time challenge from the server. You use a challenge here, like for attestation, to avoid replay attacks. `const challenge = 'A string from your server'; const request = { action: 'getGameLevel', levelId: '1234', challenge: challenge, }; const assertion = await AppIntegrity.generateAssertionAsync(keyId, JSON.stringify(request));` On success, pass the assertion object, along with the client data, to the server. If the assertion object fails verification, it's your responsibility to decide how to handle the request. There's no restriction on the number of assertions that you can make with a key. Nevertheless, you typically reserve assertions for requests made at sensitive moments in your app's life cycle, like when the app downloads premium content. ### Start over on reinstallation The keys that you generate remain valid through regular app updates, but don't survive app reinstallation, device migration, or restoration of a device from a backup. In these cases, you need to start the process from the beginning and generate a new key. Try to limit new key generation to only these events, or to the addition of new users. Keeping the key count low on a device helps when trying to detect certain kinds of fraud. ### Additional resources * [Apple's App Attest documentation](https://developer.apple.com/documentation/devicecheck/establishing-your-app-s-integrity): Refer to Apple's official guide to understand the APIs and verification flow that power `@expo/app-integrity`. ``` ``` * [Validating apps that connect to your server](https://developer.apple.com/documentation/devicecheck/validating-apps-that-connect-to-your-server): Verify the app attestation and assertion on your server. ``` ``` * [Assessing fraud risk](https://developer.apple.com/documentation/devicecheck/assessing-fraud-risk): Request and analyze risk data using server-to-server calls. ``` ``` * [Preparing to use the app attest service](https://developer.apple.com/documentation/devicecheck/preparing-to-use-the-app-attest-service): Test your implementation in a development environment and onboard users gradually. ``` ``` ## API `import * as AppIntegrity from '@expo/app-integrity';` ## Constants ### `AppIntegrity.isSupported` Type: `boolean` A boolean value that indicates whether a particular device provides the [App Attest](https://developer.apple.com/documentation/devicecheck/establishing-your-app-s-integrity) service. Not all device types support the App Attest service, so check for support before using the service. ## Methods ### `AppIntegrity.attestKeyAsync(keyId, challenge)` Asks Apple to attest to the validity of a generated cryptographic key. A Promise that is fulfilled with a string that contains the attestation data. A statement from Apple about the validity of the key associated with keyId. Send this to your server for processing. ### `AppIntegrity.generateAssertionAsync(keyId, challenge)` Creates a block of data that demonstrates the legitimacy of an instance of your app running on a device. A Promise that is fulfilled with a string that contains the assertion object. A data structure that you send to your server for processing. ### `AppIntegrity.generateHardwareAttestedKeyAsync(keyAlias, challenge)` Generates a hardware-attested key pair in the Android Keystore. This key can be used for attestation on GrapheneOS and other secure Android distributions. A Promise that resolves when the key is generated successfully. ### `AppIntegrity.generateKeyAsync()` Creates a new cryptographic key for use with the App Attest service. A Promise that is fulfilled with a string that contains the key identifier. The key itself is stored securely in the Secure Enclave. ### `AppIntegrity.getAttestationCertificateChainAsync(keyAlias)` Retrieves the attestation certificate chain for a hardware-attested key. The certificate chain can be validated on your server to verify device integrity. A Promise that is fulfilled with an array of base64-encoded X.509 certificates. ### `AppIntegrity.isHardwareAttestationSupportedAsync()` Checks if hardware attestation is supported on this device. A Promise that is fulfilled with a boolean indicating support. ### `AppIntegrity.prepareIntegrityTokenProviderAsync(cloudProjectNumber)` Prepares the integrity token provider for the given cloud project number. A Promise that is fulfilled if the integrity token provider is prepared successfully. ### `AppIntegrity.requestIntegrityCheckAsync(requestHash)` Requests an integrity verdict for the given request hash from Google Play. A Promise that is fulfilled with a string that contains the integrity check result. --- # apple-authentication A library that provides Sign-in with Apple capability for iOS. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-apple-authentication)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-apple-authentication/CHANGELOG.md)[](https://www.npmjs.com/package/expo-apple-authentication) `expo-apple-authentication` provides Apple authentication for iOS. It does not yet support Android or web. Any app that includes third-party authentication options must provide Apple authentication as an option to comply with App Store Review guidelines. For more information, see Apple authentication on the [Sign In with Apple](https://developer.apple.com/sign-in-with-apple/) website. ## Installation `npx expo install expo-apple-authentication` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Configuration in app config You can configure `expo-apple-authentication` using its built-in [config plugin](https://docs.expo.dev/config-plugins/introduction) if you use config plugins in your project ([Continuous Native Generation (CNG)](https://docs.expo.dev/workflow/continuous-native-generation)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library. ### Setup iOS project To enable the Sign In with Apple capability in your app, set the [`ios.usesAppleSignIn`](https://docs.expo.dev/versions/latest/config/app#usesapplesignin) property to `true` in your project's app config: `{ "expo": { "ios": { "usesAppleSignIn": true } } }` ### Example app.json with config plugin Running [EAS Build](https://docs.expo.dev/build/introduction) locally will use [iOS capabilities signing](https://docs.expo.dev/build-reference/ios-capabilities) to enable the required capabilities before building. `{ "expo": { "plugins": ["expo-apple-authentication"] } }` Are you using this library in an existing React Native app? ## Usage `import * as AppleAuthentication from 'expo-apple-authentication'; import { View, StyleSheet } from 'react-native'; export default function App() { return ( { try { const credential = await AppleAuthentication.signInAsync({ requestedScopes: [ AppleAuthentication.AppleAuthenticationScope.FULL_NAME, AppleAuthentication.AppleAuthenticationScope.EMAIL, ], }); // signed in } catch (e) { if (e.code === 'ERR_REQUEST_CANCELED') { // handle that the user canceled the sign-in flow } else { // handle other errors } } }} /> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, button: { width: 200, height: 44, }, });` ## Development and testing You can test this library in Expo Go on iOS without following any of the instructions above. However, you'll need to add the config plugin to use this library if you are using EAS Build. When you sign into Expo Go, the identifiers and values you receive will likely be different than what you'll receive in standalone apps. You can do limited testing of this library on the iOS Simulator. However, not all methods will behave the same as on a device, so we highly recommend testing on a real device when possible while developing. ## Verifying the Response from Apple Apple's response includes a signed JWT with information about the user. To ensure that the response came from Apple, you can cryptographically verify the signature with Apple's public key, which is published at [https://appleid.apple.com/auth/keys](https://appleid.apple.com/auth/keys). This process is not specific to Expo. ## API `import * as AppleAuthentication from 'expo-apple-authentication';` ## Component ### `AppleAuthenticationButton` Type: `React.Element<[AppleAuthenticationButtonProps](#appleauthenticationbuttonprops)>` This component displays the proprietary "Sign In with Apple" / "Continue with Apple" button on your screen. The App Store Guidelines require you to use this component to start the authentication process instead of a custom button. Limited customization of the button is available via the provided properties. You should only attempt to render this if [`AppleAuthentication.isAvailableAsync()`](#appleauthenticationisavailableasync) resolves to `true`. This component will render nothing if it is not available, and you will get a warning in development mode (`__DEV__ === true`). The properties of this component extend from `View`; however, you should not attempt to set `backgroundColor` or `borderRadius` with the `style` property. This will not work and is against the App Store Guidelines. Instead, you should use the `buttonStyle` property to choose one of the predefined color styles and the `cornerRadius` property to change the border radius of the button. Make sure to attach height and width via the style props as without these styles, the button will not appear on the screen. > See: [Apple Documentation](https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidbutton) for more details. AppleAuthenticationButtonProps ### `buttonStyle` Type: `[AppleAuthenticationButtonStyle](#appleauthenticationbuttonstyle)` The Apple-defined color scheme to use to display the button. ### `buttonType` Type: `[AppleAuthenticationButtonType](#appleauthenticationbuttontype)` The type of button text to display ("Sign In with Apple" vs. "Continue with Apple"). ### `cornerRadius` The border radius to use when rendering the button. This works similarly to `style.borderRadius` in other Views. ### `onPress` The method to call when the user presses the button. You should call [`AppleAuthentication.signInAsync`](#appleauthenticationisavailableasync) in here. ### `style` Optional Type: `StyleProp<[Omit](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys)<[ViewStyle](https://reactnative.dev/docs/view-style-props), 'backgroundColor' | 'borderRadius'>>` The custom style to apply to the button. Should not include `backgroundColor` or `borderRadius` properties. #### Inherited Props ## Methods ### `AppleAuthentication.formatFullName(fullName, formatStyle)` Creates a locale-aware string representation of a person's name from an object representing the tokenized portions of a user's full name A locale-aware string representation of a person's name ### `AppleAuthentication.getCredentialStateAsync(user)` Queries the current state of a user credential, to determine if it is still valid or if it has been revoked. > Note: This method must be tested on a real device. On the iOS simulator it always throws an error. A promise that fulfills with an [`AppleAuthenticationCredentialState`](#appleauthenticationcredentialstate) value depending on the state of the credential. ### `AppleAuthentication.isAvailableAsync()` Determine if the current device's operating system supports Apple authentication. A promise that fulfills with `true` if the system supports Apple authentication, and `false` otherwise. ### `AppleAuthentication.refreshAsync(options)` An operation that refreshes the logged-in user’s credentials. Calling this method will show the sign in modal before actually refreshing the user credentials. A promise that fulfills with an [`AppleAuthenticationCredential`](#appleauthenticationcredential) object after a successful authentication, and rejects with `ERR_REQUEST_CANCELED` if the user cancels the refresh operation. ### `AppleAuthentication.signInAsync(options)` Sends a request to the operating system to initiate the Apple authentication flow, which will present a modal to the user over your app and allow them to sign in. You can request access to the user's full name and email address in this method, which allows you to personalize your UI for signed in users. However, users can deny access to either or both of these options at runtime. Additionally, you will only receive Apple Authentication Credentials the first time users sign into your app, so you must store it for later use. It's best to store this information either server-side, or using [SecureStore](https://docs.expo.dev/versions/latest/sdk/securestore), so that the data persists across app installs. You can use [`AppleAuthenticationCredential.user`](#appleauthenticationcredential) to identify the user, since this remains the same for apps released by the same developer. A promise that fulfills with an [`AppleAuthenticationCredential`](#appleauthenticationcredential) object after a successful authentication, and rejects with `ERR_REQUEST_CANCELED` if the user cancels the sign-in operation. ### `AppleAuthentication.signOutAsync(options)` An operation that ends the authenticated session. Calling this method will show the sign in modal before actually signing the user out. It is not recommended to use this method to sign out the user as it works counterintuitively. Instead of using this method it is recommended to simply clear all the user's data collected from using [`signInAsync`](#appleauthenticationsigninasyncoptions) or [`refreshAsync`](#appleauthenticationrefreshasyncoptions) methods. A promise that fulfills with an [`AppleAuthenticationCredential`](#appleauthenticationcredential) object after a successful authentication, and rejects with `ERR_REQUEST_CANCELED` if the user cancels the sign-out operation. ## Event Subscriptions ### `AppleAuthentication.addRevokeListener(listener)` ## Interfaces ### `Subscription` A subscription object that allows to conveniently remove an event listener from the emitter. Subscription Methods ### `remove()` Removes an event listener for which the subscription has been created. After calling this function, the listener will no longer receive any events from the emitter. ## Types ### `AppleAuthenticationCredential` The object type returned from a successful call to [`AppleAuthentication.signInAsync()`](#appleauthenticationsigninasyncoptions), [`AppleAuthentication.refreshAsync()`](#appleauthenticationrefreshasyncoptions), or [`AppleAuthentication.signOutAsync()`](#appleauthenticationsignoutasyncoptions) which contains all of the pertinent user and credential information. > See: [Apple Documentation](https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidcredential) for more details. ### `AppleAuthenticationFullName` An object representing the tokenized portions of the user's full name. Any of all of the fields may be `null`. Only applicable fields that the user has allowed your app to access will be nonnull. ### `AppleAuthenticationFullNameFormatStyle` Literal Type: `string` Acceptable values are: `'default'` | `'short'` | `'medium'` | `'long'` | `'abbreviated'` ### `AppleAuthenticationRefreshOptions` The options you can supply when making a call to [`AppleAuthentication.refreshAsync()`](#appleauthenticationrefreshasyncoptions). You must include the ID string of the user whose credentials you'd like to refresh. > See: [Apple Documentation](https://developer.apple.com/documentation/authenticationservices/asauthorizationopenidrequest) for more details. ### `AppleAuthenticationSignInOptions` The options you can supply when making a call to [`AppleAuthentication.signInAsync()`](#appleauthenticationsigninasyncoptions). None of these options are required. > See: [Apple Documentation](https://developer.apple.com/documentation/authenticationservices/asauthorizationopenidrequest) for more details. ### `AppleAuthenticationSignOutOptions` The options you can supply when making a call to [`AppleAuthentication.signOutAsync()`](#appleauthenticationsignoutasyncoptions). You must include the ID string of the user to sign out. > See: [Apple Documentation](https://developer.apple.com/documentation/authenticationservices/asauthorizationopenidrequest) for more details. ## Enums ### `AppleAuthenticationButtonStyle` An enum whose values control which pre-defined color scheme to use when rendering an [`AppleAuthenticationButton`](#appleauthenticationbutton). #### `WHITE` `AppleAuthenticationButtonStyle.WHITE = 0` White button with black text. #### `WHITE_OUTLINE` `AppleAuthenticationButtonStyle.WHITE_OUTLINE = 1` White button with a black outline and black text. #### `BLACK` `AppleAuthenticationButtonStyle.BLACK = 2` Black button with white text. ### `AppleAuthenticationButtonType` An enum whose values control which pre-defined text to use when rendering an [`AppleAuthenticationButton`](#appleauthenticationbutton). #### `SIGN_IN` `AppleAuthenticationButtonType.SIGN_IN = 0` "Sign in with Apple" #### `CONTINUE` `AppleAuthenticationButtonType.CONTINUE = 1` "Continue with Apple" #### `SIGN_UP` `AppleAuthenticationButtonType.SIGN_UP = 2` "Sign up with Apple" ### `AppleAuthenticationCredentialState` #### `REVOKED` `AppleAuthenticationCredentialState.REVOKED = 0` #### `AUTHORIZED` `AppleAuthenticationCredentialState.AUTHORIZED = 1` #### `NOT_FOUND` `AppleAuthenticationCredentialState.NOT_FOUND = 2` #### `TRANSFERRED` `AppleAuthenticationCredentialState.TRANSFERRED = 3` ### `AppleAuthenticationOperation` #### `IMPLICIT` `AppleAuthenticationOperation.IMPLICIT = 0` An operation that depends on the particular kind of credential provider. #### `LOGIN` `AppleAuthenticationOperation.LOGIN = 1` #### `REFRESH` `AppleAuthenticationOperation.REFRESH = 2` #### `LOGOUT` `AppleAuthenticationOperation.LOGOUT = 3` ### `AppleAuthenticationScope` An enum whose values specify scopes you can request when calling [`AppleAuthentication.signInAsync()`](#appleauthenticationsigninasyncoptions). > Note that it is possible that you will not be granted all of the scopes which you request. You will still need to handle null values for any fields you request. > See: [Apple Documentation](https://developer.apple.com/documentation/authenticationservices/asauthorizationscope) for more details. #### `FULL_NAME` `AppleAuthenticationScope.FULL_NAME = 0` #### `EMAIL` `AppleAuthenticationScope.EMAIL = 1` ### `AppleAuthenticationUserDetectionStatus` An enum whose values specify the system's best guess for how likely the current user is a real person. > See: [Apple Documentation](https://developer.apple.com/documentation/authenticationservices/asuserdetectionstatus) for more details. #### `UNSUPPORTED` `AppleAuthenticationUserDetectionStatus.UNSUPPORTED = 0` The system does not support this determination and there is no data. #### `UNKNOWN` `AppleAuthenticationUserDetectionStatus.UNKNOWN = 1` The system has not determined whether the user might be a real person. #### `LIKELY_REAL` `AppleAuthenticationUserDetectionStatus.LIKELY_REAL = 2` The user appears to be a real person. ## Error codes Most of the error codes match the official [Apple Authorization errors](https://developer.apple.com/documentation/authenticationservices/asauthorizationerror/code). --- # application ## Expo Application A universal library that provides information about the native application's ID, app name, and build version at runtime. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-application)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-application/CHANGELOG.md)[](https://www.npmjs.com/package/expo-application) `expo-application` provides useful information about the native application's ID, app name, and build version at runtime. ## Installation `npx expo install expo-application` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## API `import * as Application from 'expo-application';` ## Constants ### `Application.applicationId` Type: `string | null` The ID of the application. On Android, this is the application ID. On iOS, this is the bundle ID. On web, this is `null`. Example `"com.cocoacasts.scribbles"`, `"com.apple.Pages"` ### `Application.applicationName` Type: `string | null` The human-readable name of the application that is displayed with the app's icon on the device's home screen or desktop. On Android and iOS, this value is a `string` unless the name could not be retrieved, in which case this value will be `null`. On web this value is `null`. Example `"Expo"`, `"Yelp"`, `"Instagram"` ### `Application.nativeApplicationVersion` Type: `string | null` The human-readable version of the native application that may be displayed in the app store. At time when native app is built, on Android, this is the version name set by `version` in app config, and on iOS, the `Info.plist` value for `CFBundleShortVersionString`. On web, this value is `null`. ### `Application.nativeBuildVersion` Type: `string | null` The internal build version of the native application that the app stores may use to distinguish between different binaries. At the time when native app is built, On Android, this is the version code set by `android.versionCode` in app config, and on iOS, the `Info.plist` value for `CFBundleVersion` (set with `ios.buildNumber` value in app config in a standalone app). On web, this value is `null`. The return type on Android and iOS is `string`. ## Methods ### `Application.getAndroidId()` Gets the value of [`Settings.Secure.ANDROID_ID`](https://developer.android.com/reference/android/provider/Settings.Secure.html#ANDROID_ID). This is a hexadecimal `string` unique to each combination of app-signing key, user, and device. The value may change if a factory reset is performed on the device or if an APK signing key changes. For more information about how the platform handles `ANDROID_ID` in Android 8.0 (API level 26) and higher, see [Android 8.0 Behavior Changes](https://developer.android.com/about/versions/oreo/android-8.0-changes.html#privacy-all). On iOS and web, this function is unavailable. > In versions of the platform lower than Android 8.0 (API level 26), this value remains constant for the lifetime of the user's device. See the [ANDROID\_ID](https://developer.android.com/reference/android/provider/Settings.Secure.html#ANDROID_ID) official docs for more information. Example `Application.getAndroidId(); // "dd96dec43fb81c97"` ### `Application.getInstallationTimeAsync()` Gets the time the app was installed onto the device, not counting subsequent updates. If the app is uninstalled and reinstalled, this method returns the time the app was reinstalled. * On Android, this method uses [`PackageInfo.firstInstallTime`](https://developer.android.com/reference/android/content/pm/PackageInfo.html#firstInstallTime). * On iOS, this method uses the [`NSFileCreationDate`](https://developer.apple.com/documentation/foundation/nsfilecreationdate?language=objc) of the app's document root directory. * On web, this method returns `null`. A `Promise` that fulfills with a `Date` object that specifies the time the app was installed on the device. Example `await Application.getInstallationTimeAsync(); // 2019-07-18T18:08:26.121Z` ### `Application.getInstallReferrerAsync()` Gets the referrer URL of the installed app with the [`Install Referrer API`](https://developer.android.com/google/play/installreferrer) from the Google Play Store. In practice, the referrer URL may not be a complete, absolute URL. A `Promise` that fulfills with a `string` of the referrer URL of the installed app. Example `await Application.getInstallReferrerAsync(); // "utm_source=google-play&utm_medium=organic"` ### `Application.getIosApplicationReleaseTypeAsync()` Gets the iOS application release type. A `Promise` which fulfills with an [`ApplicationReleaseType`](#applicationreleasetype). ### `Application.getIosIdForVendorAsync()` Gets the iOS "identifier for vendor" ([IDFV](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor)) value, a string ID that uniquely identifies a device to the app’s vendor. This method may sometimes return `nil`, in which case wait and call the method again later. This might happen when the device has been restarted before the user has unlocked the device. The OS will change the vendor identifier if all apps from the current app's vendor have been uninstalled. A `Promise` that fulfills with a `string` specifying the app's vendor ID. Apps from the same vendor will return the same ID. See Apple's documentation for more information about the vendor ID's semantics. Example `await Application.getIosIdForVendorAsync(); // "68753A44-4D6F-1226-9C60-0050E4C00067"` ### `Application.getIosPushNotificationServiceEnvironmentAsync()` Gets the current [Apple Push Notification (APN)](https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment?language=objc) service environment. A `Promise` that fulfills with the string, either `'development'` or `'production'`, based on the current APN environment, or `null` on the simulator as it does not support registering with APNs. ### `Application.getLastUpdateTimeAsync()` Gets the last time the app was updated from the Google Play Store. A `Promise` that fulfills with a `Date` object that specifies the last time the app was updated via the Google Play Store. Example `await Application.getLastUpdateTimeAsync(); // 2019-07-18T21:20:16.887Z` ## Types ### `PushNotificationServiceEnvironment` Literal Type: `union` Maps to the [`aps-environment`](https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment) key in the native target's registered entitlements. Acceptable values are: `'development'` | `'production'` | `null` ## Enums ### `ApplicationReleaseType` #### `UNKNOWN` `ApplicationReleaseType.UNKNOWN = 0` #### `SIMULATOR` `ApplicationReleaseType.SIMULATOR = 1` #### `ENTERPRISE` `ApplicationReleaseType.ENTERPRISE = 2` #### `DEVELOPMENT` `ApplicationReleaseType.DEVELOPMENT = 3` #### `AD_HOC` `ApplicationReleaseType.AD_HOC = 4` #### `APP_STORE` `ApplicationReleaseType.APP_STORE = 5` Error codes --------------------------- --- # asset ## Expo Asset A universal library that allows downloading assets and using them with other libraries. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-asset)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-asset/CHANGELOG.md)[](https://www.npmjs.com/package/expo-asset) `expo-asset` provides an interface to Expo's asset system. An asset is any file that lives alongside the source code of your app that the app needs at runtime. Examples include images, fonts, and sounds. Expo's asset system integrates with React Native's, so that you can refer to files with `require('path/to/file')`. This is how you refer to static image files in React Native for use in an `Image` component, for example. Check out React Native's [documentation on static image resources](https://reactnative.dev/docs/images#static-image-resources) for more information. This method of referring to static image resources works out of the box with Expo. ## Installation `npx expo install expo-asset` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Configuration in app config You can configure `expo-asset` using its built-in [config plugin](https://docs.expo.dev/config-plugins/introduction) if you use config plugins in your project ([Continuous Native Generation (CNG)](https://docs.expo.dev/workflow/continuous-native-generation)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library. ### Example app.json with config plugin `{ "expo": { "plugins": [ [ "expo-asset", { "assets": ["path/to/file.png", "path/to/directory"] } ] ] } }` ### Configurable properties ### Usage Learn more about how to use the `expo-asset` config plugin to embed an asset file in your project in [Load an asset at build time](https://docs.expo.dev/develop/user-interface/assets#load-an-asset-at-build-time). ## API `import { Asset } from 'expo-asset';` ## Hooks ### `useAssets(moduleIds)` Downloads and stores one or more assets locally. After the assets are loaded, this hook returns a list of asset instances. If something went wrong when loading the assets, an error is returned. > Note, the assets are not "reloaded" when you dynamically change the asset list. Returns an array containing: * on the first position, a list of all loaded assets. If they aren't loaded yet, this value is `undefined`. * on the second position, an error which encountered when loading the assets. If there was no error, this value is `undefined`. Example `const [assets, error] = useAssets([require('path/to/asset.jpg'), require('path/to/other.png')]); return assets ? : null;` ## Classes ### `Asset` The `Asset` class represents an asset in your app. It gives metadata about the asset (such as its name and type) and provides facilities to load the asset data. Asset Properties ### `downloaded` Type: `boolean` Default: `false` Whether the asset has finished downloading from a call to [`downloadAsync()`](#downloadasync). ### `hash` Read Only Literal type: `union` Default: `null` The MD5 hash of the asset's data. Acceptable values are: `null` | `string` ### `height` Literal type: `union` Default: `null` If the asset is an image, the height of the image data divided by the scale factor. The scale factor is the number after `@` in the filename, or `1` if not present. Acceptable values are: `null` | `number` ### `localUri` Literal type: `union` Default: `null` If the asset has been downloaded (by calling [`downloadAsync()`](#downloadasync)), the `file://` URI pointing to the local file on the device that contains the asset data. Acceptable values are: `null` | `string` ### `name` The name of the asset file without the extension. Also without the part from `@` onward in the filename (used to specify scale factor for images). ### `type` The extension of the asset filename. ### `uri` A URI that points to the asset's data on the remote server. When running the published version of your app, this refers to the location on Expo's asset server where Expo has stored your asset. When running the app from Expo CLI during development, this URI points to Expo CLI's server running on your computer and the asset is served directly from your computer. If you are not using Classic Updates (legacy), this field should be ignored as we ensure your assets are on device before running your application logic. ### `width` Literal type: `union` Default: `null` If the asset is an image, the width of the image data divided by the scale factor. The scale factor is the number after `@` in the filename, or `1` if not present. Acceptable values are: `null` | `number` Asset Methods ### `downloadAsync()` Downloads the asset data to a local file in the device's cache directory. Once the returned promise is fulfilled without error, the [`localUri`](#localuri) field of this asset points to a local file containing the asset data. The asset is only downloaded if an up-to-date local file for the asset isn't already present due to an earlier download. The downloaded `Asset` will be returned when the promise is resolved. > Note: There is no guarantee that files downloaded via `downloadAsync` persist between app sessions. `downloadAsync` stores files in the caches directory, so it's up to the OS to clear this folder at its own discretion or when the user manually purges the caches directory. Downloaded assets are stored as `ExponentAsset-{cacheFileId}.{extension}` within the cache directory. To manually clear cached assets, you can use [`expo-file-system`](https://docs.expo.dev/versions/latest/sdk/filesystem) to delete the cache directory: `Paths.cache.delete()` or use the legacy API `deleteAsync(cacheDirectory)`. Returns a Promise which fulfills with an `Asset` instance. ### `fromMetadata(meta)` ### `fromModule(virtualAssetModule)` Returns the [`Asset`](#asset) instance representing an asset given its module or URL. The [`Asset`](#asset) instance for the asset. ### `fromURI(uri)` ### `loadAsync(moduleId)` A helper that wraps `Asset.fromModule(module).downloadAsync` for convenience. Returns a Promise that fulfills with an array of `Asset`s when the asset(s) has been saved to disk. Example `const [{ localUri }] = await Asset.loadAsync(require('./assets/snack-icon.png'));` ## Types ### `AssetDescriptor` ### `AssetMetadata` Type: `[Pick](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys)<[PackagerAsset](https://github.com/facebook/react-native/blob/main/packages/assets/registry.js), 'httpServerLocation' | 'name' | 'hash' | 'type' | 'scales' | 'width' | 'height'>` extended by: --- # async-storage [](https://github.com/react-native-async-storage/async-storage) [ GitHub ](https://github.com/react-native-async-storage/async-storage) [ npm ](https://www.npmjs.com/package/@react-native-async-storage/async-storage) A library that provides an asynchronous, unencrypted, persistent, key-value storage API. [ GitHub ](https://github.com/react-native-async-storage/async-storage)[ npm ](https://www.npmjs.com/package/@react-native-async-storage/async-storage) Android iOS macOS tvOS Web Bundled version: 2.2.0 Async Storage is asynchronous, unencrypted, persistent, key-value storage solution. ## Installation Terminal `npx expo install @react-native-async-storage/async-storage` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. Then, follow the [installation instructions](https://react-native-async-storage.github.io/async-storage/docs/install#android--ios) provided in the library's README or documentation. ## Learn more [ Visit official documentation Get full information on API and its usage. ](https://react-native-async-storage.github.io/async-storage/docs/usage) --- # audio A library that provides an API to implement audio playback and recording in apps. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-audio)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-audio/CHANGELOG.md)[](https://www.npmjs.com/package/expo-audio) `expo-audio` is a cross-platform audio library for accessing the native audio capabilities of the device. Note that audio automatically stops if headphones/bluetooth audio devices are disconnected. ## Installation `npx expo install expo-audio` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Configuration in app config You can configure `expo-audio` using its built-in [config plugin](https://docs.expo.dev/config-plugins/introduction) if you use config plugins in your project ([Continuous Native Generation (CNG)](https://docs.expo.dev/workflow/continuous-native-generation)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library. ### Example app.json with config plugin `{ "expo": { "plugins": [ [ "expo-audio", { "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone." } ] ] } }` ### Configurable properties ## Usage ### Playing sounds `import { View, StyleSheet, Button } from 'react-native'; import { useAudioPlayer } from 'expo-audio'; const audioSource = require('./assets/Hello.mp3'); export default function App() { const player = useAudioPlayer(audioSource); return (
` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/button)_ ### CircularProgress `import { CircularProgress } from '@expo/ui/jetpack-compose'; ` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/progress)_ ### ContextMenu > Note: Also known as DropdownMenu. `import { ContextMenu } from '@expo/ui/jetpack-compose'; setSelectedIndex(index)} /> ` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/menu)_ ### Chip `import { Chip } from '@expo/ui/jetpack-compose'; // Assist chip with icon console.log('Opening flight booking...')} /> // Filter chip with selection handleFilterToggle('Images')} /> // Input chip with dismiss handleInputDismiss('Work')} /> // Suggestion chip console.log('Searching nearby...')} />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/chip)_ ### DateTimePicker (date) `import { DateTimePicker } from '@expo/ui/jetpack-compose'; { setSelectedDate(date); }} displayedComponents='date' initialDate={selectedDate.toISOString()} variant='picker' />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/datepickers)_ ### DateTimePicker (time) `import { DateTimePicker } from '@expo/ui/jetpack-compose'; { setSelectedDate(date); }} displayedComponents='hourAndMinute' initialDate={selectedDate.toISOString()} variant='picker' />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/time-pickers)_ ### LinearProgress ### Picker (radio) `import { Picker } from '@expo/ui/jetpack-compose'; { setSelectedIndex(index); }} variant="radio" />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/radio-button)_ ### Picker (segmented) `import { Picker } from '@expo/ui/jetpack-compose'; { setSelectedIndex(index); }} variant="segmented" />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/segmented-button)_ ### Slider `import { Slider } from '@expo/ui/jetpack-compose'; { setValue(value); }} />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/slider)_ ### Switch (toggle) > Note: also known as Toggle. `import { Switch } from '@expo/ui/jetpack-compose'; { setChecked(checked); }} color="#ff0000" label="Play music" variant="switch" />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/switch)_ ### Switch (checkbox) `import { Switch } from '@expo/ui/jetpack-compose'; { setChecked(checked); }} label="Play music" color="#ff0000" variant="checkbox" />` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/components/checkbox)_ ### TextInput `import { TextInput } from '@expo/ui/jetpack-compose'; ` _See also: [official Jetpack Compose documentation](https://developer.android.com/develop/ui/compose/text/user-input)_ ## API Full documentation is not yet available. Use TypeScript types to explore the API. `// Import from the Jetpack Compose package import { Button } from '@expo/ui/jetpack-compose';` --- # swift-ui SwiftUI components for building native iOS interfaces with @expo/ui. [](https://github.com/expo/expo/tree/main/packages/expo-ui)[](https://github.com/expo/expo/tree/main/packages/expo-ui/CHANGELOG.md)[](https://www.npmjs.com/package/@expo/ui) > This library is currently in beta and subject to breaking changes. It is not available in the Expo Go app — use [development builds](https://docs.expo.dev/develop/development-builds/introduction) to try it out. The SwiftUI components in `@expo/ui/swift-ui` allow you to build fully native iOS interfaces using SwiftUI from React Native. ## Installation `npx expo install @expo/ui` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Usage Using a component from `@expo/ui/swift-ui` requires wrapping it in a [`Host`](https://docs.expo.dev/versions/latest/sdk/ui/swift-ui#host) component. The `Host` is a container for SwiftUI views. `import { Host, Button } from '@expo/ui/swift-ui'; export function SaveButton() { return ( ); }` For an in-depth explanation of how `Host` works, see the following resources: [ Expo UI guide for Swift UI Learn about the basics of `@expo/ui/swift-ui` ](https://docs.expo.dev/guides/expo-ui-swift-ui)[ Expo UI iOS Liquid Glass Tutorial Learn how to build real SwiftUI views in your React Native app with the new Expo UI. ](https://www.youtube.com/watch?v=2wXYLWz3YEQ) ## Components ### BottomSheet `import { BottomSheet, Host, Text } from '@expo/ui/swift-ui'; import { useWindowDimensions } from 'react-native'; const { width } = useWindowDimensions(); setIsOpened(e)}> Hello, world! ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/sheet\(ispresented:ondismiss:content:\))_ ### Button > The borderless variant is not available on Apple TV. `import { Button, Host } from '@expo/ui/swift-ui'; ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/button)_ ### CircularProgress `import { CircularProgress, Host } from '@expo/ui/swift-ui'; ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/progressview)_ ### ColorPicker > This component is not available on Apple TV. `import { ColorPicker, Host } from '@expo/ui/swift-ui'; ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/colorpicker)_ ### ContextMenu > Note: Also known as DropdownMenu. `import { ContextMenu, Host } from '@expo/ui/swift-ui'; setSelectedIndex(index)} /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/contextmenu\(menuitems:\))_ ### DateTimePicker (date) > This component is not available on Apple TV. `import { DateTimePicker, Host } from '@expo/ui/swift-ui'; { setSelectedDate(date); }} displayedComponents='date' initialDate={selectedDate.toISOString()} variant='wheel' /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/datepicker)_ ### DateTimePicker (time) > This component is not available on Apple TV. `import { DateTimePicker, Host } from '@expo/ui/swift-ui'; { setSelectedDate(date); }} displayedComponents='hourAndMinute' initialDate={selectedDate.toISOString()} variant='wheel' /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/datepicker)_ ### Gauge > This component is not available on Apple TV. `import { Gauge, Host } from "@expo/ui/swift-ui"; ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/gauge)_ ### Host A component that allows you to put the other `@expo/ui/swift-ui` components in React Native. It acts like [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/svg) for DOM, [``](https://shopify.github.io/react-native-skia/docs/canvas/overview/) for [`react-native-skia`](https://shopify.github.io/react-native-skia/), which underlying uses [`UIHostingController`](https://developer.apple.com/documentation/swiftui/uihostingcontroller) to render the SwiftUI views in UIKit. Since the `Host` component is a React Native [`View`](https://reactnative.dev/docs/view), you can pass the [`style`](https://reactnative.dev/docs/style) prop to it or `matchContents` prop to make the `Host` component match the contents' size. `import { Button, Host } from '@expo/ui/swift-ui'; function Example() { return ( ); }` `import { Button, Host, VStack, Text } from '@expo/ui/swift-ui'; function Example() { return ( Hello, world! ); }` ### LinearProgress `import { LinearProgress, Host } from '@expo/ui/swift-ui'; ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/progressview)_ ### List ``import { Host, List } from '@expo/ui/swift-ui'; alert(`indexes of selected items: ${items.join(', ')}`)} moveEnabled={moveEnabled} onMoveItem={(from, to) => alert(`moved item at index ${from} to index ${to}`)} onDeleteItem={(item) => alert(`deleted item at index: ${item}`)} listStyle='automatic' deleteEnabled={deleteEnabled} selectEnabled={selectEnabled}> {data.map((item, index) => ( ))} `` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/list)_ ### Picker (segmented) `import { Host, Picker } from '@expo/ui/swift-ui'; { setSelectedIndex(index); }} variant="segmented" /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/picker#Styling-pickers)_ ### Picker (wheel) > The wheel variant is not available on Apple TV. `import { Host, Picker } from '@expo/ui/swift-ui'; { setSelectedIndex(index); }} variant="wheel" /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/pickerstyle/wheel)_ ### Slider > This component is not available on Apple TV. `import { Host, Slider } from '@expo/ui/swift-ui'; { setValue(value); }} /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/slider)_ ### Switch (toggle) > Note: Also known as Toggle. `import { Host, Switch } from '@expo/ui/swift-ui'; { setChecked(checked); }} color="#ff0000" label="Play music" variant="switch" /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/toggle)_ ### Switch (checkbox) `import { Host, Switch } from '@expo/ui/swift-ui'; { setChecked(checked); }} label="Play music" variant="checkbox" /> ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/toggle)_ ### TextField `import { Host, TextField } from '@expo/ui/swift-ui'; ` _See also: [official SwiftUI documentation](https://developer.apple.com/documentation/swiftui/textfield)_ ### More Expo UI is still in active development. We continue to add more functionality and may change the API. Some examples in the docs may not be up to date. If you want to see the latest changes, check the [examples](https://github.com/expo/expo/tree/main/apps/native-component-list/src/screens/UI). ## API Full documentation is not yet available. Use TypeScript types to explore the API. `// Import from the SwiftUI package import { BottomSheet } from '@expo/ui/swift-ui';` --- # updates ## Expo Updates A library that enables your app to manage remote updates to your application code. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-updates)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-updates/CHANGELOG.md)[](https://www.npmjs.com/package/expo-updates) `expo-updates` is a library that enables your app to manage remote updates to your application code. It communicates with the configured remote update service to get information about available updates. ## Installation The `expo-updates` library can be automatically configured using [EAS Update](https://docs.expo.dev/eas-update/introduction), which is a hosted service that manages and serves updates to your app. To get started with EAS Update, follow the instructions in the [Get started](https://docs.expo.dev/eas-update/getting-started) guide. Alternatively, it is also possible to configure the `expo-updates` library manually in cases where a different remote update service is required or configuration is only specified in native files. Manual installation, configuration, and custom remote update services ## Configuration There are build-time configuration options that control the behavior of the library. For most apps, these configuration values are set in the [app config](https://docs.expo.dev/workflow/configuration) under the [`updates` property](https://docs.expo.dev/versions/latest/config/app#updates). The two core required configuration options are: * [`updates.url`](https://docs.expo.dev/versions/latest/config/app#updates): the URL at which the library fetches remote updates * [`runtimeVersion`](https://docs.expo.dev/versions/latest/config/app#runtimeversion): a [runtime version](https://docs.expo.dev/versions/latest/sdk/updates#runtime-version) These are configured automatically when following the EAS Update [Get started](https://docs.expo.dev/eas-update/getting-started) guide. #### Runtime version Each time you build a binary for your app it includes the native code and configuration present at the time of the build as well as native configuration, and this unique combination is represented by a string called a runtime version. A remote update targets one runtime version, indicating that only binaries with a matching runtime version can load the remote update. Manual configuration Automatic configuration using runtime version policies #### Native configuration and overriding If your project does not use Continuous Native Generation, these configuration values may also be set in your app's native configuration files or overridden at during initialization in native code. Native configuration instructions ## Usage By default, `expo-updates` checks for updates when the app launches. If an update is available, it downloads the update and applies it the next time the app is restarted. You can tune this startup behavior using the `checkAutomatically` and `fallbackToCacheTimeout` configuration options above. The library also provides a variety of constants to inspect the current update and functions to customize update behavior from your application code (after startup). For example, one common alternative usage pattern is to manually check for updates after the app has started instead of doing the default check on launch. Example: Check for updates manually ## Testing Most of the methods and constants in this library can be used or tested only in release builds. In debug builds, the default behavior is to always load the latest JavaScript from a development server. It is possible to [build a debug version of your app with the same updates behavior as a release build](https://docs.expo.dev/eas-update/debug-advanced#debugging-of-native-code-while-loading-the-app-through-expo-updates). Such an app will not open the latest JavaScript from your development server — it will load published updates just as a release build does. This may be useful for debugging the behavior of your app when it is not connected to a development server. To test the content of an update in a development build, run [`eas update`](https://docs.expo.dev/eas-update/getting-started) and then browse to the update in your development build. Note that this only simulates what an update will look like in your app, and most of the [Updates API](https://docs.expo.dev/versions/latest/sdk/updates#api) is unavailable when running in a development build. To test updates in a release build, you can create a [.apk](https://docs.expo.dev/build-reference/apk) or a [simulator build](https://docs.expo.dev/build-reference/simulators), or make a release build locally with `npx expo run:android --variant release` and `npx expo run:ios --configuration Release` (you don't need to submit this build to the store to test). The full [Updates API](https://docs.expo.dev/versions/latest/sdk/updates#api) is available in a release build. To test the content of an update in Expo Go, run [`eas update`](https://docs.expo.dev/eas-update/getting-started) and then browse to the update in Expo Go. Note that this only simulates what an update will look like in your app, and most of the [Updates API](https://docs.expo.dev/versions/latest/sdk/updates#api) is unavailable when running in Expo Go. Also note that only updates using [Expo Go-compatible libraries](https://docs.expo.dev/workflow/using-libraries#determining-third-party-library-compatibility) are supported. ## API `import * as Updates from 'expo-updates';` ## Constants ### `Updates.channel` Type: `string | null` The channel name of the current build, if configured for use with EAS Update. `null` otherwise. Expo Go and development builds are not set to a specific channel and can run any updates compatible with their native runtime. Therefore, this value will always be `null` when running an update on Expo Go or a development build. ### `Updates.checkAutomatically` Type: `[UpdatesCheckAutomaticallyValue](#updatescheckautomaticallyvalue) | null` Determines if and when `expo-updates` checks for and downloads updates automatically on startup. ### `Updates.createdAt` Type: `[Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | null` If `expo-updates` is enabled, this is a `Date` object representing the creation time of the update that's currently running (whether it was embedded or downloaded at runtime). In development mode, or any other environment in which `expo-updates` is disabled, this value is null. ### `Updates.emergencyLaunchReason` Type: `null | string` If `isEmergencyLaunch` is set to true, this will contain a string error message describing what failed during initialization. ### `Updates.isEmbeddedLaunch` Type: `boolean` This will be true if the currently running update is the one embedded in the build, and not one downloaded from the updates server. ### `Updates.isEmergencyLaunch` Type: `boolean` `expo-updates` does its very best to always launch monotonically newer versions of your app so you don't need to worry about backwards compatibility when you put out an update. In very rare cases, it's possible that `expo-updates` may need to fall back to the update that's embedded in the app binary, even after newer updates have been downloaded and run (an "emergency launch"). This boolean will be `true` if the app is launching under this fallback mechanism and `false` otherwise. If you are concerned about backwards compatibility of future updates to your app, you can use this constant to provide special behavior for this rare case. ### `Updates.isEnabled` Type: `boolean` Whether `expo-updates` is enabled. This may be false in a variety of cases including: * enabled set to false in configuration * missing or invalid URL in configuration * missing runtime version or SDK version in configuration * error accessing storage on device during initialization When false, the embedded update is loaded. ### `Updates.latestContext` Type: `[UpdatesNativeStateMachineContext](#updatesnativestatemachinecontext)` ### `Updates.launchDuration` Type: `null | number` Number of milliseconds it took to launch. ### `Updates.manifest` Type: `[Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype)<[Manifest](#manifest)>` If `expo-updates` is enabled, this is the [manifest](https://docs.expo.dev/versions/latest/sdk/constants#manifest) (or [classic manifest](https://docs.expo.dev/versions/latest/sdk/constants#appmanifest)) object for the update that's currently running. In development mode, or any other environment in which `expo-updates` is disabled, this object is empty. ### `Updates.runtimeVersion` Type: `string | null` The runtime version of the current build. ### `Updates.updateId` Type: `string | null` The UUID that uniquely identifies the currently running update. The UUID is represented in its canonical string form and will always use lowercase letters. This value is `null` when running in a local development environment or any other environment where `expo-updates` is disabled. Example `"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"` ## Hooks ### `useUpdates()` Hook that obtains information on available updates and on the currently running update. the structures with information on currently running and available updates. Example `import { StatusBar } from 'expo-status-bar'; import * as Updates from 'expo-updates'; import { useEffect } from 'react'; import { Button, Text, View } from 'react-native'; export default function UpdatesDemo() { const { currentlyRunning, isUpdateAvailable, isUpdatePending } = Updates.useUpdates(); useEffect(() => { if (isUpdatePending) { // Update has successfully downloaded; apply it now Updates.reloadAsync(); } }, [isUpdatePending]); // If true, we show the button to download and run the update const showDownloadButton = isUpdateAvailable; // Show whether or not we are running embedded code or an update const runTypeMessage = currentlyRunning.isEmbeddedLaunch ? 'This app is running from built-in code' : 'This app is running an update'; return ( Updates Demo {runTypeMessage} ); }` ## Classes ## Methods ### `Updates.checkForUpdateAsync()` Checks the server to see if a newly deployed update to your project is available. Does not actually download the update. This method cannot be used in development mode, and the returned promise will be rejected if you try to do so. Checking for an update uses a device's bandwidth and battery life like any network call. Additionally, updates served by Expo may be rate limited. A good rule of thumb to check for updates judiciously is to check when the user launches or foregrounds the app. Avoid polling for updates in a frequent loop. A promise that fulfills with an [`UpdateCheckResult`](#updatecheckresult) object. The promise rejects in Expo Go or if the app is in development mode, or if there is an unexpected error or timeout communicating with the server. It also rejects when `expo-updates` is not enabled. ### `Updates.clearLogEntriesAsync()` Clears existing `expo-updates` log entries. > For now, this operation does nothing on the client. Once log persistence has been implemented, this operation will actually remove existing logs. A promise that fulfills if the clear operation was successful. The promise rejects if there is an unexpected error in clearing the logs. ### `Updates.fetchUpdateAsync()` Downloads the most recently deployed update to your project from server to the device's local storage. This method cannot be used in development mode, and the returned promise will be rejected if you try to do so. > Note: [`reloadAsync()`](#updatesreloadasync) can be called after promise resolution to reload the app using the most recently downloaded version. Otherwise, the update will be applied on the next app cold start. A promise that fulfills with an [`UpdateFetchResult`](#updatefetchresult) object. The promise rejects in Expo Go or if the app is in development mode, or if there is an unexpected error or timeout communicating with the server. It also rejects when `expo-updates` is not enabled. ### `Updates.getExtraParamsAsync()` Retrieves the current extra params. This method cannot be used in Expo Go or development mode. It also rejects when `expo-updates` is not enabled. ### `Updates.readLogEntriesAsync(maxAge)` Retrieves the most recent `expo-updates` log entries. A promise that fulfills with an array of [`UpdatesLogEntry`](#updateslogentry) objects; The promise rejects if there is an unexpected error in retrieving the logs. ### `Updates.reloadAsync(options)` Instructs the app to reload using the most recently downloaded version. This is useful for triggering a newly downloaded update to launch without the user needing to manually restart the app. Unlike `Expo.reloadAppAsync()` provided by the `expo` package, this function not only reloads the app but also changes the loaded JavaScript bundle to that of the most recently downloaded update. It is not recommended to place any meaningful logic after a call to `await Updates.reloadAsync()`. This is because the promise is resolved after verifying that the app can be reloaded, and immediately before posting an asynchronous task to the main thread to actually reload the app. It is unsafe to make any assumptions about whether any more JS code will be executed after the `Updates.reloadAsync` method call resolves, since that depends on the OS and the state of the native module and main threads. This method cannot be used in Expo Go or development mode, and the returned promise will be rejected if you try to do so. It also rejects when `expo-updates` is not enabled. A promise that fulfills right before the reload instruction is sent to the JS runtime, or rejects if it cannot find a reference to the JS runtime. If the promise is rejected in production mode, it most likely means you have installed the module incorrectly. Double check you've followed the installation instructions. In particular, on iOS ensure that you set the `bridge` property on `EXUpdatesAppController` with a pointer to the `RCTBridge` you want to reload, and on Android ensure you either call `UpdatesController.initialize` with the instance of `ReactApplication` you want to reload, or call `UpdatesController.setReactNativeHost` with the proper instance of `ReactNativeHost`. ### `Updates.setExtraParamAsync(key, value)` Sets an extra param if value is non-null, otherwise unsets the param. Extra params are sent as an [Expo Structured Field Value Dictionary](https://docs.expo.dev/technical-specs/expo-sfv-0) in the `Expo-Extra-Params` header of update requests. A compliant update server may use these params when selecting an update to serve. This method cannot be used in Expo Go or development mode. It also rejects when `expo-updates` is not enabled. ### `Updates.setUpdateRequestHeadersOverride(requestHeaders)` Overrides updates request headers in runtime from build time. This method allows you to load specific updates with custom request headers. Use this method at your own risk, as it may cause unexpected behavior. [Learn more about use cases and limitations](https://docs.expo.dev/eas-update/override/). ### `Updates.setUpdateURLAndRequestHeadersOverride(configOverride)` Overrides updates URL and reuqest headers in runtime from build time. This method allows you to load specific updates from a URL that you provide. Use this method at your own risk, as it may cause unexpected behavior. Because of the risk, this method requires `disableAntiBrickingMeasures` to be set to `true` in the app.json file. [Learn more about use cases and limitations](https://docs.expo.dev/eas-update/override/). ## Interfaces ### `ReloadScreenImageSource` Image source that can be used for the reload screen. ### `ReloadScreenOptions` Configuration options for customizing the reload screen appearance. ### `UpdatesModuleInterface` Common interface for all native module implementations (android, ios, web). ## Types ### `CurrentlyRunningInfo` Structure encapsulating information on the currently running app (either the embedded bundle or a downloaded update). ### `UpdateCheckResult` Literal Type: `union` The result of checking for a new update. Acceptable values are: `[UpdateCheckResultRollBack](#updatecheckresultrollback)` | `[UpdateCheckResultAvailable](#updatecheckresultavailable)` | `[UpdateCheckResultNotAvailable](#updatecheckresultnotavailable)` ### `UpdateCheckResultAvailable` The update check result when a new update is found on the server. ### `UpdateCheckResultNotAvailable` The update check result if no new update was found. ### `UpdateCheckResultRollBack` The update check result when a rollback directive is received. ### `UpdateFetchResult` Literal Type: `union` The result of fetching a new update. Acceptable values are: `[UpdateFetchResultSuccess](#updatefetchresultsuccess)` | `[UpdateFetchResultFailure](#updatefetchresultfailure)` | `[UpdateFetchResultRollBackToEmbedded](#updatefetchresultrollbacktoembedded)` ### `UpdateFetchResultFailure` The failed result of fetching a new update. ### `UpdateFetchResultRollBackToEmbedded` The roll back to embedded result of fetching a new update. ### `UpdateFetchResultSuccess` The successful result of fetching a new update. ### `UpdateInfo` Literal Type: `union` Combined structure representing any type of update. Acceptable values are: `[UpdateInfoNew](#updateinfonew)` | `[UpdateInfoRollback](#updateinforollback)` ### `UpdateInfoNew` Structure representing a new update. ### `UpdateInfoRollback` Structure representing a rollback directive. ### `UpdatesCheckAutomaticallyNativeValue` Literal Type: `string` Acceptable values are: `'ALWAYS'` | `'ERROR_RECOVERY_ONLY'` | `'NEVER'` | `'WIFI_ONLY'` ### `UpdatesEvents` ### `UpdatesLogEntry` An object representing a single log entry from `expo-updates` logging on the client. ### `UseUpdatesReturnType` The type returned by [`useUpdates()`](#useupdates). ## Enums ### `UpdateCheckResultNotAvailableReason` #### `NO_UPDATE_AVAILABLE_ON_SERVER` `UpdateCheckResultNotAvailableReason.NO_UPDATE_AVAILABLE_ON_SERVER = "noUpdateAvailableOnServer"` No update manifest or rollback directive received from the update server. #### `ROLLBACK_NO_EMBEDDED` `UpdateCheckResultNotAvailableReason.ROLLBACK_NO_EMBEDDED = "rollbackNoEmbeddedConfiguration"` A rollback directive was received from the update server, but this app has no embedded update. #### `ROLLBACK_REJECTED_BY_SELECTION_POLICY` `UpdateCheckResultNotAvailableReason.ROLLBACK_REJECTED_BY_SELECTION_POLICY = "rollbackRejectedBySelectionPolicy"` A rollback directive was received from the update server, but the directive does not pass the configured selection policy. #### `UPDATE_PREVIOUSLY_FAILED` `UpdateCheckResultNotAvailableReason.UPDATE_PREVIOUSLY_FAILED = "updatePreviouslyFailed"` An update manifest was received from the update server, but the update has been previously launched on this device and never successfully launched. #### `UPDATE_REJECTED_BY_SELECTION_POLICY` `UpdateCheckResultNotAvailableReason.UPDATE_REJECTED_BY_SELECTION_POLICY = "updateRejectedBySelectionPolicy"` An update manifest was received from the update server, but the update is not launchable, or does not pass the configured selection policy. ### `UpdateInfoType` The different possible types of updates. Currently, the only supported type is `UpdateInfoType.NEW`, indicating a new update that can be downloaded and launched on the device. In the future, other types of updates may be added to this list. #### `NEW` `UpdateInfoType.NEW = "new"` This is the type for new updates found on or downloaded from the update server, that are launchable on the device. #### `ROLLBACK` `UpdateInfoType.ROLLBACK = "rollback"` This type is used when an update is a directive to roll back to the embedded bundle. ### `UpdatesCheckAutomaticallyValue` The possible settings that determine if `expo-updates` will check for updates on app startup. By default, Expo will check for updates every time the app is loaded. Set this to `ON_ERROR_RECOVERY` to disable automatic checking unless recovering from an error. Set this to `NEVER` to completely disable automatic checking. #### `NEVER` `UpdatesCheckAutomaticallyValue.NEVER = "NEVER"` Automatic update checks are off, and update checks must be done through the JS API. #### `ON_ERROR_RECOVERY` `UpdatesCheckAutomaticallyValue.ON_ERROR_RECOVERY = "ON_ERROR_RECOVERY"` Only checks for updates when the app starts up after an error recovery. #### `ON_LOAD` `UpdatesCheckAutomaticallyValue.ON_LOAD = "ON_LOAD"` Checks for updates whenever the app is loaded. This is the default setting. #### `WIFI_ONLY` `UpdatesCheckAutomaticallyValue.WIFI_ONLY = "WIFI_ONLY"` Only checks for updates when the app starts and has a Wi-Fi connection. ### `UpdatesLogEntryCode` The possible code values for `expo-updates` log entries #### `ASSETS_FAILED_TO_LOAD` `UpdatesLogEntryCode.ASSETS_FAILED_TO_LOAD = "AssetsFailedToLoad"` #### `INITIALIZATION_ERROR` `UpdatesLogEntryCode.INITIALIZATION_ERROR = "InitializationError"` #### `JS_RUNTIME_ERROR` `UpdatesLogEntryCode.JS_RUNTIME_ERROR = "JSRuntimeError"` #### `NONE` `UpdatesLogEntryCode.NONE = "None"` #### `NO_UPDATES_AVAILABLE` `UpdatesLogEntryCode.NO_UPDATES_AVAILABLE = "NoUpdatesAvailable"` #### `UNKNOWN` `UpdatesLogEntryCode.UNKNOWN = "Unknown"` #### `UPDATE_ASSETS_NOT_AVAILABLE` `UpdatesLogEntryCode.UPDATE_ASSETS_NOT_AVAILABLE = "UpdateAssetsNotAvailable"` #### `UPDATE_CODE_SIGNING_ERROR` `UpdatesLogEntryCode.UPDATE_CODE_SIGNING_ERROR = "UpdateCodeSigningError"` #### `UPDATE_FAILED_TO_LOAD` `UpdatesLogEntryCode.UPDATE_FAILED_TO_LOAD = "UpdateFailedToLoad"` #### `UPDATE_HAS_INVALID_SIGNATURE` `UpdatesLogEntryCode.UPDATE_HAS_INVALID_SIGNATURE = "UpdateHasInvalidSignature"` #### `UPDATE_SERVER_UNREACHABLE` `UpdatesLogEntryCode.UPDATE_SERVER_UNREACHABLE = "UpdateServerUnreachable"` ### `UpdatesLogEntryLevel` The possible log levels for `expo-updates` log entries #### `DEBUG` `UpdatesLogEntryLevel.DEBUG = "debug"` #### `ERROR` `UpdatesLogEntryLevel.ERROR = "error"` #### `FATAL` `UpdatesLogEntryLevel.FATAL = "fatal"` #### `INFO` `UpdatesLogEntryLevel.INFO = "info"` #### `TRACE` `UpdatesLogEntryLevel.TRACE = "trace"` #### `WARN` `UpdatesLogEntryLevel.WARN = "warn"` Error codes --------------------------- --- # video A library that provides an API to implement video playback in apps. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-video)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-video/CHANGELOG.md)[](https://www.npmjs.com/package/expo-video) `expo-video` is a cross-platform, performant video component for React Native and Expo with Web support. #### Known issues  When two [`VideoView`](https://docs.expo.dev/versions/latest/sdk/video#videoview) components are overlapping and have the [`contentFit`](https://docs.expo.dev/versions/latest/sdk/video#contentfit) prop set to [`cover`](https://docs.expo.dev/versions/latest/sdk/video#videocontentfit), one of the videos may be displayed out of bounds. This is a [known upstream issue](https://github.com/androidx/media/issues/1107). To work around this issue, use the [`surfaceType`](https://docs.expo.dev/versions/latest/sdk/video#surfacetype) prop and set it to [`textureView`](https://docs.expo.dev/versions/latest/sdk/video#surfacetype-1). ## Installation `npx expo install expo-video` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Configuration in app config You can configure `expo-video` using its built-in [config plugin](https://docs.expo.dev/config-plugins/introduction) if you use config plugins in your project ([Continuous Native Generation (CNG)](https://docs.expo.dev/workflow/continuous-native-generation)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library. ### Example app.json with config plugin `{ "expo": { "plugins": [ [ "expo-video", { "supportsBackgroundPlayback": true, "supportsPictureInPicture": true } ] ], } }` ### Configurable properties ## Usage Here's a simple example of a video with a play and pause button. `import { useEvent } from 'expo'; import { useVideoPlayer, VideoView } from 'expo-video'; import { StyleSheet, View, Button } from 'react-native'; const videoSource = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'; export default function VideoScreen() { const player = useVideoPlayer(videoSource, player => { player.loop = true; player.play(); }); const { isPlaying } = useEvent(player, 'playingChange', { isPlaying: player.playing }); return ( ); } const styles = StyleSheet.create({ contentContainer: { flex: 1, padding: 10, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 50, }, video: { width: 350, height: 275, }, controlsContainer: { padding: 10, }, });` ### Receiving events The changes in properties of the [`VideoPlayer`](https://docs.expo.dev/versions/latest/sdk/video#videoplayer) do not update the React state. Therefore, to display the information about the current state of the `VideoPlayer`, it is necessary to listen to the [events](https://docs.expo.dev/versions/latest/sdk/video#videoplayerevents) it emits. The event system is based on the [`EventEmitter`](https://docs.expo.dev/versions/latest/sdk/expo#eventemitter) class and [hooks](https://docs.expo.dev/versions/latest/sdk/expo#hooks) from the [`expo`](https://docs.expo.dev/versions/latest/sdk/expo) package. There are a few ways to listen to events: #### `useEvent` hook Creates a listener that will return a stateful value that can be used in a component. It also cleans up automatically when the component unmounts. `import { useEvent } from 'expo'; // ... Other imports, definition of the component, creating the player etc. const { status, error } = useEvent(player, 'statusChange', { status: player.status }); // Rest of the component...` #### `useEventListener` hook Built around the `Player.addListener` and `Player.removeListener` methods, creates an event listener with automatic cleanup. `import { useEventListener } from 'expo'; // ...Other imports, definition of the component, creating the player etc. useEventListener(player, 'statusChange', ({ status, error }) => { setPlayerStatus(status); setPlayerError(error); console.log('Player status changed: ', status); }); // Rest of the component...` #### `Player.addListener` method Most flexible way to listen to events, but requires manual cleanup and more boilerplate code. `// ...Imports, definition of the component, creating the player etc. useEffect(() => { const subscription = player.addListener('statusChange', ({ status, error }) => { setPlayerStatus(status); setPlayerError(error); console.log('Player status changed: ', status); }); return () => { subscription.remove(); }; }, []); // Rest of the component...` ### Playing local media from the assets directory `expo-video` supports playing local media loaded using the `require` function. You can use the result as a source directly, or assign it to the `assetId` parameter of a [`VideoSource`](https://docs.expo.dev/versions/latest/sdk/video#videosource) if you also want to configure other properties. ``import { VideoSource } from 'expo-video'; const assetId = require('./assets/bigbuckbunny.mp4'); const videoSource: VideoSource = { assetId, metadata: { title: 'Big Buck Bunny', artist: 'The Open Movie Project', }, }; const player1 = useVideoPlayer(assetId); // You can use the `asset` directly as a video source const player2 = useVideoPlayer(videoSource);`` ### Preloading videos While another video is playing, a video can be loaded before showing it in the view. This allows for quicker transitions between subsequent videos and a better user experience. To preload a video, you have to create a `VideoPlayer` with a video source. Even when the player is not connected to a `VideoView`, it will fill the buffers. Once it is connected to the `VideoView`, it will be able to start playing without buffering. In some cases, it is beneficial to preload a video later in the screen lifecycle. In that case, a `VideoPlayer` with a `null` source should be created. To start preloading, replace the player source with a video source using the `replace()` function. Here is an example of how to preload a video: `import { useVideoPlayer, VideoView, VideoSource } from 'expo-video'; import { useState, useCallback } from 'react'; import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; const bigBuckBunnySource: VideoSource = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'; const elephantsDreamSource: VideoSource = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4'; export default function PreloadingVideoPlayerScreen() { const player1 = useVideoPlayer(bigBuckBunnySource, player => { player.play(); }); const player2 = useVideoPlayer(elephantsDreamSource, player => { player.currentTime = 20; }); const [currentPlayer, setCurrentPlayer] = useState(player1); const replacePlayer = useCallback(async () => { currentPlayer.pause(); if (currentPlayer === player1) { setCurrentPlayer(player2); player1.pause(); player2.play(); } else { setCurrentPlayer(player1); player2.pause(); player1.play(); } }, [player1, currentPlayer]); return ( Replace Player ); } const styles = StyleSheet.create({ contentContainer: { flex: 1, padding: 10, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 50, }, button: { alignItems: 'center', justifyContent: 'center', borderRadius: 3, paddingVertical: 8, paddingHorizontal: 12, backgroundColor: '#4630ec', }, buttonText: { fontSize: 12, fontWeight: 'bold', color: '#eeeeee', textAlign: 'center', }, video: { width: 300, height: 168.75, marginVertical: 20, }, });` ### Using the VideoPlayer directly In most cases, the [`useVideoPlayer`](https://docs.expo.dev/versions/latest/sdk/video#usevideoplayersource-setup) hook should be used to create a `VideoPlayer` instance. It manages the player's lifecycle and ensures that it is properly disposed of when the component is unmounted. However, in some advanced use cases, it might be necessary to create a `VideoPlayer` that does not get automatically destroyed when the component is unmounted. In those cases, the `VideoPlayer` can be created using the [`createVideoPlayer`](https://docs.expo.dev/versions/latest/sdk/video#videocreatevideoplayersource) function. You need be aware of the risks that come with this approach, as it is your responsibility to call the [`release()`](https://docs.expo.dev/versions/latest/sdk/expo#release) method when the player is no longer needed. If not handled properly, this approach may lead to memory leaks. `import { createVideoPlayer } from 'expo-video'; const player = createVideoPlayer(videoSource);` > On Android, mounting multiple `VideoView` components at the same time with the same `VideoPlayer` instance will not work due to a [platform limitation](https://github.com/expo/expo/issues/35012). ### Caching videos If your app frequently replays the same video, caching can be utilized to minimize network usage and enhance user experience, albeit at the cost of increased device storage usage. `expo-video` supports video caching on `Android` and `iOS` platforms. This feature can be activated by setting the [`useCaching`](https://docs.expo.dev/versions/latest/sdk/video#videosource) property of a [`VideoSource`](https://docs.expo.dev/versions/latest/sdk/video#videosource) object to `true`. The cache is persistent and will be cleared on a least-recently-used basis once the preferred size is exceeded. Furthermore, the system can clear the cache due to low storage availability, so it's not advisable to depend on the cache to store critical data. The cache functions offline. If a portion or the entirety of a video is cached, it can be played from the cache even when the device is offline until the cached data is exhausted. > Due to platform limitations, the cache cannot be used with HLS video sources on iOS. Caching DRM-protected videos is not supported on Android and iOS. ### Managing the cache * The preferred cache size in bytes can be defined using the [`setVideoCacheSizeAsync`](https://docs.expo.dev/versions/latest/sdk/video#videosetvideocachesizeasyncsizebytes) function. The default cache size is 1GB. * The [`getCurrentVideoCacheSize`](https://docs.expo.dev/versions/latest/sdk/video#videogetcurrentvideocachesize) can be used to get the current storage occupied by the cache in bytes. * All cached videos can be cleared using the [`clearVideoCacheAsync`](https://docs.expo.dev/versions/latest/sdk/video#videoclearvideocacheasync) function. ## API `import { VideoView, useVideoPlayer } from 'expo-video';` ## Components ### `VideoView` Type: `React.[PureComponent](https://react.dev/reference/react/PureComponent)<[VideoViewProps](#videoviewprops)>` VideoViewProps ### `allowsFullscreen` Optional Type: `boolean` Default: `true` Determines whether fullscreen mode is allowed or not. > Note: This option has been deprecated in favor of the `fullscreenOptions` prop and will be disabled in the future. ### `allowsPictureInPicture` Determines whether the player allows Picture in Picture (PiP) mode. > Note: The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config) has to be configured for the PiP to work. ### `allowsVideoFrameAnalysis` Optional Type: `boolean` Default: `true` Specifies whether to perform video frame analysis (Live Text in videos). Check official [Apple documentation](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/allowsvideoframeanalysis) for more details. ### `contentFit` Optional Type: `[VideoContentFit](#videocontentfit)` Default: `'contain'` Describes how the video should be scaled to fit in the container. Options are `'contain'`, `'cover'`, and `'fill'`. ### `contentPosition` Optional Type: `{ dx: number, dy: number }` Determines the position offset of the video inside the container. ### `crossOrigin` Optional Literal type: `string` Default: `undefined` Determines the [cross origin policy](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/crossorigin) used by the underlying native view on web. If `undefined` (default), does not use CORS at all. If set to `'anonymous'`, the video will be loaded with CORS enabled. Note that some videos may not play if CORS is enabled, depending on the CDN settings. If you encounter issues, consider adjusting the `crossOrigin` property. Acceptable values are: `'anonymous'` | `'use-credentials'` ### `fullscreenOptions` Optional Type: `[FullscreenOptions](#fullscreenoptions)` Determines the fullscreen mode options. ### `nativeControls` Optional Type: `boolean` Default: `true` Determines whether native controls should be displayed or not. ### `onFirstFrameRender` Optional Type: `() => void` A callback to call after the mounted `VideoPlayer` has rendered the first frame into the `VideoView`. This event can be used to hide any cover images that conceal the initial loading of the player. > Note: This event may also be called during playback when the current video track changes (for example when the player switches video quality). ### `onFullscreenEnter` Optional Type: `() => void` A callback to call after the video player enters fullscreen mode. ### `onFullscreenExit` Optional Type: `() => void` A callback to call after the video player exits fullscreen mode. ### `onPictureInPictureStart` Optional Type: `() => void` A callback to call after the video player enters Picture in Picture (PiP) mode. ### `onPictureInPictureStop` Optional Type: `() => void` A callback to call after the video player exits Picture in Picture (PiP) mode. ### `player` A video player instance. Use [`useVideoPlayer()`](#usevideoplayersource-setup) hook to create one. ### `playsInline` Determines whether a video should be played "inline", that is, within the element's playback area. ### `requiresLinearPlayback` Optional Type: `boolean` Default: `false` Determines whether the player allows the user to skip media content. ### `showsTimecodes` Optional Type: `boolean` Default: `true` Determines whether the timecodes should be displayed or not. ### `startsPictureInPictureAutomatically` Optional Type: `boolean` Default: `false` Determines whether the player should start Picture in Picture (PiP) automatically when the app is in the background. > Note: Only one player can be in Picture in Picture (PiP) mode at a time. > Note: The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config) has to be configured for the PiP to work. ### `surfaceType` Optional Type: `[SurfaceType](#surfacetype)` Default: `'surfaceView'` Determines the type of the surface used to render the video. > This prop should not be changed at runtime. ### `useExoShutter` Optional Type: `boolean` Default: `false` Determines whether the player should use the default ExoPlayer shutter that covers the `VideoView` before the first video frame is rendered. Setting this property to `false` makes the Android behavior the same as iOS. #### Inherited Props ### `VideoAirPlayButton` Type: `React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<[VideoAirPlayButtonProps](#videoairplaybuttonprops)>` A view displaying the [`AVRoutePickerView`](https://developer.apple.com/documentation/avkit/avroutepickerview). Shows a button, when pressed, an AirPlay device picker shows up, allowing users to stream the currently playing video to any available AirPlay sink. > When using this view, make sure that the [`allowsExternalPlayback`](#allowsexternalplayback) player property is set to `true`. VideoAirPlayButtonProps ### `activeTint` Optional Type: `[ColorValue](https://reactnative.dev/docs/colors)` Default: `undefined` The color of the button icon while AirPlay sharing is active. ### `onBeginPresentingRoutes` Optional Type: `() => void` A callback called when the AirPlay route selection popup is about to show. ### `onEndPresentingRoutes` Optional Type: `() => void` A callback called when the AirPlay route selection popup has disappeared. ### `prioritizeVideoDevices` Optional Type: `boolean` Default: `true` Determines whether the AirPlay device selection popup should show video outputs first. ### `tint` Optional Type: `[ColorValue](https://reactnative.dev/docs/colors)` Default: `undefined` The color of the button icon while AirPlay sharing is not active. ## Component Methods ### `enterFullscreen()` ### `exitFullscreen()` ### `startPictureInPicture()` Enters Picture in Picture (PiP) mode. Throws an exception if the device does not support PiP. > Note: Only one player can be in Picture in Picture (PiP) mode at a time. > Note: The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config) has to be configured for the PiP to work. ### `stopPictureInPicture()` Exits Picture in Picture (PiP) mode. ## Hooks ### `useVideoPlayer(source, setup)` Creates a `VideoPlayer`, which will be automatically cleaned up when the component is unmounted. ## Classes ### `VideoPlayer` Type: Class extends `[SharedObject](https://docs.expo.dev/versions/v54.0.0/sdk/expo#sharedobjecttype)<[VideoPlayerEvents](#videoplayerevents)>` A class that represents an instance of the video player. VideoPlayer Properties ### `allowsExternalPlayback` Type: `boolean` Default: `true` Determines whether the player should allow external playback. ### `audioMixingMode` Type: `[AudioMixingMode](#audiomixingmode)` Default: `'auto'` Determines how the player will interact with other audio playing in the system. ### `audioTrack` Literal type: `union` Default: `null` Specifies the audio track currently played by the player. `null` when no audio is played. Acceptable values are: `null` | `[AudioTrack](#audiotrack)` ### `availableAudioTracks` Read Only Type: `[AudioTrack[]](#audiotrack)` An array of audio tracks available for the current video. ### `availableSubtitleTracks` Read Only Type: `[SubtitleTrack[]](#subtitletrack)` An array of subtitle tracks available for the current video. ### `availableVideoTracks` Read Only Type: `[VideoTrack[]](#videotrack)` An array of video tracks available for the current video. > On iOS, when using a HLS source, make sure that the uri contains `.m3u8` extension or that the [`contentType`](#contenttype) property of the [`VideoSource`](#videosource) has been set to `'hls'`. Otherwise, the video tracks will not be available. ### `bufferedPosition` Float value indicating how far the player has buffered the video in seconds. This value is 0 when the player has not buffered up to the current playback time. When it's impossible to determine the buffer state (for example, when the player isn't playing any media), this value is -1. ### `bufferOptions` Specifies buffer options which will be used by the player when buffering the video. > You should provide a `BufferOptions` object when setting this property. Setting individual buffer properties is not supported. ### `currentLiveTimestamp` Read Only Literal type: `union` The exact timestamp when the currently displayed video frame was sent from the server, based on the `EXT-X-PROGRAM-DATE-TIME` tag in the livestream metadata. If this metadata is missing, this property will return `null`. Acceptable values are: `null` | `number` ### `currentOffsetFromLive` Read Only Literal type: `union` Float value indicating the latency of the live stream in seconds. If a livestream doesn't have the required metadata, this will return `null`. Acceptable values are: `null` | `number` ### `currentTime` Float value indicating the current playback time in seconds. If the player is not yet playing, this value indicates the time position at which playback will begin once the `play()` method is called. Setting `currentTime` to a new value seeks the player to the given time. Note that frame accurate seeking may incur additional decoding delay which can impact seeking performance. Consider using the [`seekBy`](#seekbyseconds) function if the time does not have to be set precisely. ### `duration` Float value indicating the duration of the current video in seconds. ### `isExternalPlaybackActive` Read Only Type: `boolean` Indicates whether the player is currently playing back the media to an external device via AirPlay. ### `isLive` Read Only Type: `boolean` Boolean value indicating whether the player is currently playing a live stream. ### `loop` Type: `boolean` Default: `false` Determines whether the player should automatically replay after reaching the end of the video. ### `muted` Type: `boolean` Default: `false` Boolean value whether the player is currently muted. Setting this property to `true`/`false` will mute/unmute the player. ### `playbackRate` Type: `number` Default: `1.0` Float value between `0` and `16.0` indicating the current playback speed of the player. ### `playing` Read Only Type: `boolean` Boolean value whether the player is currently playing. > Use `play` and `pause` methods to control the playback. ### `preservesPitch` Type: `boolean` Default: `true` Boolean value indicating if the player should correct audio pitch when the playback speed changes. ### `showNowPlayingNotification` Type: `boolean` Default: `false` Boolean value determining whether the player should show the now playing notification. ### `status` Read Only Type: `[VideoPlayerStatus](#videoplayerstatus)` Indicates the current status of the player. ### `staysActiveInBackground` Type: `boolean` Default: `false` Determines whether the player should continue playing after the app enters the background. ### `subtitleTrack` Literal type: `union` Default: `null` Specifies the subtitle track which is currently displayed by the player. `null` when no subtitles are displayed. > To ensure a valid subtitle track, always assign one of the subtitle tracks from the [`availableSubtitleTracks`](#availablesubtitletracks) array. Acceptable values are: `null` | `[SubtitleTrack](#subtitletrack)` ### `targetOffsetFromLive` Float value indicating the time offset from the live in seconds. ### `timeUpdateEventInterval` Type: `number` Default: `0` Float value indicating the interval in seconds at which the player will emit the [`timeUpdate`](#videoplayerevents) event. When the value is equal to `0`, the event will not be emitted. ### `videoTrack` Read Only Literal type: `union` Default: `null` Specifies the video track currently played by the player. `null` when no video is displayed. Acceptable values are: `null` | `[VideoTrack](#videotrack)` ### `volume` Type: `number` Default: `1.0` Float value between `0` and `1.0` representing the current volume. Muting the player doesn't affect the volume. In other words, when the player is muted, the volume is the same as when unmuted. Similarly, setting the volume doesn't unmute the player. VideoPlayer Methods ### `generateThumbnailsAsync(times, options)` Generates thumbnails from the currently played asset. The thumbnails are references to native images, thus they can be used as a source of the `Image` component from `expo-image`. ### `pause()` ### `play()` ### `replace(source, disableWarning)` Replaces the current source with a new one. > On iOS, this method loads the asset data synchronously on the UI thread and can block it for extended periods of time. Use `replaceAsync` to load the asset asynchronously and avoid UI lags. > This method will be deprecated in the future. ### `replaceAsync(source)` Replaces the current source with a new one, while offloading loading of the asset to a different thread. > On Android and Web, this method is equivalent to `replace`. ### `replay()` Seeks the playback to the beginning. ### `seekBy(seconds)` Seeks the playback by the given number of seconds. The time to which the player seeks may differ from the specified requested time for efficiency, depending on the encoding and what is currently buffered by the player. Use this function to implement playback controls that seek by specific amount of time, in which case, the actual time usually does not have to be precise. For frame accurate seeking, use the [`currentTime`](#currenttime) property. ### `VideoThumbnail` Type: Class extends `[SharedRef](https://docs.expo.dev/versions/v54.0.0/sdk/expo#sharedreftype)<'image'>` Represents a video thumbnail that references a native image. Instances of this class can be passed as a source to the `Image` component from `expo-image`. VideoThumbnail Properties ### `actualTime` The time in seconds at which the thumbnail was actually generated. ### `height` Height of the created thumbnail. ### `nativeRefType` The type of the native reference. ### `requestedTime` The time in seconds at which the thumbnail was to be created. ### `width` Width of the created thumbnail. ## Methods ### `Video.clearVideoCacheAsync()` Clears all video cache. > This function can be called only if there are no existing `VideoPlayer` instances. A promise that fulfills after the cache has been cleaned. ### `Video.createVideoPlayer(source)` Creates a direct instance of `VideoPlayer` that doesn't release automatically. > For most use cases you should use the [`useVideoPlayer`](#usevideoplayer) hook instead. See the [Using the VideoPlayer Directly](#using-the-videoplayer-directly) section for more details. ### `Video.getCurrentVideoCacheSize()` Returns the space currently occupied by the video cache in bytes. ### `Video.isPictureInPictureSupported()` Returns whether the current device supports Picture in Picture (PiP) mode. A `boolean` which is `true` if the device supports PiP mode, and `false` otherwise. ### `Video.setVideoCacheSizeAsync(sizeBytes)` Sets desired video cache size in bytes. The default video cache size is 1GB. Value set by this function is persistent. The cache size is not guaranteed to be exact and the actual cache size may be slightly larger. The cache is evicted on a least-recently-used basis. > This function can be called only if there are no existing `VideoPlayer` instances. A promise that fulfills after the cache size has been set. ## Types ### `AudioMixingMode` Literal Type: `string` Specifies the audio mode that the player should use. Audio mode is set on per-app basis, if there are multiple players playing and have different a `AudioMode` specified, the highest priority mode will be used. Priority order: 'doNotMix' > 'auto' > 'duckOthers' > 'mixWithOthers'. * `mixWithOthers`: The player will mix its audio output with other apps. * `duckOthers`: The player will lower the volume of other apps if any of the active players is outputting audio. * `auto`: The player will allow other apps to keep playing audio only when it is muted. On iOS it will always interrupt other apps when `showNowPlayingNotification` is `true` due to system requirements. * `doNotMix`: The player will pause playback in other apps, even when it's muted. > On iOS, the Now Playing notification is dependent on the audio mode. If the audio mode is different from `doNotMix` or `auto` this feature will not work. Acceptable values are: `'mixWithOthers'` | `'duckOthers'` | `'auto'` | `'doNotMix'` ### `AudioTrack` ### `BufferOptions` Specifies buffer options which will be used by the player when buffering the video. ### `ContentType` Literal Type: `string` Specifies the content type of the source. * `auto`: The player will automatically determine the content type of the video. * `progressive`: The player will use progressive download content type. This is the default `ContentType` when the uri does not contain an extension. * `hls`: The player will use HLS content type. * `dash`: The player will use DASH content type (Android-only). * `smoothStreaming`: The player will use SmoothStreaming content type (Android-only). Acceptable values are: `'auto'` | `'progressive'` | `'hls'` | `'dash'` | `'smoothStreaming'` ### `DRMOptions` Specifies DRM options which will be used by the player while loading the video. ### `DRMType` Literal Type: `string` Specifies which type of DRM to use: * Android supports ClearKey, PlayReady and Widevine. * iOS supports FairPlay. Acceptable values are: `'clearkey'` | `'fairplay'` | `'playready'` | `'widevine'` ### `IsExternalPlaybackActiveChangeEventPayload` ### `MutedChangeEventPayload` Data delivered with the [`mutedChange`](#videoplayerevents) event. ### `PlaybackRateChangeEventPayload` Data delivered with the [`playbackRateChange`](#videoplayerevents) event. ### `PlayerError` Contains information about any errors that the player encountered during the playback ### `PlayingChangeEventPayload` Data delivered with the [`playingChange`](#videoplayerevents) event. ### `SourceChangeEventPayload` Data delivered with the [`sourceChange`](#videoplayerevents) event. ### `SourceLoadEventPayload` Data delivered with the [`sourceLoad`](#videoplayerevents) event, contains information about the video source that has finished loading. ### `StatusChangeEventPayload` Data delivered with the [`statusChange`](#videoplayerevents) event. ### `SubtitleTrack` ### `SubtitleTrackChangeEventPayload` ### `SurfaceType` Literal Type: `string` Describes the type of the surface used to render the video. * `surfaceView`: Uses the `SurfaceView` to render the video. This value should be used in the majority of cases. Provides significantly lower power consumption, better performance, and more features. * `textureView`: Uses the `TextureView` to render the video. Should be used in cases where the SurfaceView is not supported or causes issues (for example, overlapping video views). You can learn more about surface types in the official [ExoPlayer documentation](https://developer.android.com/media/media3/ui/playerview#surfacetype). Acceptable values are: `'textureView'` | `'surfaceView'` ### `TimeUpdateEventPayload` Data delivered with the [`timeUpdate`](#videoplayerevents) event, contains information about the current playback progress. ### `VideoContentFit` Literal Type: `string` Describes how a video should be scaled to fit in a container. * `contain`: The video maintains its aspect ratio and fits inside the container, with possible letterboxing/pillarboxing. * `cover`: The video maintains its aspect ratio and covers the entire container, potentially cropping some portions. * `fill`: The video stretches/squeezes to completely fill the container, potentially causing distortion. Acceptable values are: `'contain'` | `'cover'` | `'fill'` ### `VideoMetadata` Contains information that will be displayed in the now playing notification when the video is playing. ### `VideoPlayerEvents` Handlers for events which can be emitted by the player. ### `VideoPlayerStatus` Literal Type: `string` Describes the current status of the player. * `idle`: The player is not playing or loading any videos. * `loading`: The player is loading video data from the provided source * `readyToPlay`: The player has loaded enough data to start playing or to continue playback. * `error`: The player has encountered an error while loading or playing the video. Acceptable values are: `'idle'` | `'loading'` | `'readyToPlay'` | `'error'` ### `VideoSize` Specifies the size of a video track. ### `VideoSource` Type: `string` or `number` or `null` or `object` shaped as below: ### `VideoThumbnailOptions` Additional options for video thumbnails generation. ### `VideoTrack` Specifies a VideoTrack loaded from a [`VideoSource`](#videosource). ### `VideoTrackChangeEventPayload` Data delivered with the [`videoTrackChange`](#videoplayerevents) event, contains information about the video track which is currently being played. ### `VolumeChangeEventPayload` Data delivered with the [`volumeChange`](#videoplayerevents) event. --- # video-av `import { useState, useRef } from 'react'; import { View, StyleSheet, Button } from 'react-native'; import { Video, ResizeMode } from 'expo-av'; export default function App() { const video = useRef(null); const [status, setStatus] = useState({}); return ( ); } %%placeholder-start%%const styles = StyleSheet.create({ ... }); %%placeholder-end%%const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor: '#ecf0f1', }, video: { alignSelf: 'center', width: 320, height: 200, }, buttons: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, });` --- # video-thumbnails `import { useState } from 'react'; import { StyleSheet, Button, View, Image, Text } from 'react-native'; import * as VideoThumbnails from 'expo-video-thumbnails'; export default function App() { const [image, setImage] = useState(null); const generateThumbnail = async () => { try { const { uri } = await VideoThumbnails.getThumbnailAsync( 'https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4', { time: 15000, } ); setImage(uri); } catch (e) { console.warn(e); } }; return ( {image && } {image} ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, image: { width: 200, height: 200, }, });` --- # view-pager `import { StyleSheet, View, Text } from 'react-native'; import PagerView from 'react-native-pager-view'; export default function MyPager() { return ( First page Swipe ➡️ Second page Third page ); } const styles = StyleSheet.create({ container: { flex: 1, }, page: { justifyContent: 'center', alignItems: 'center', }, });` --- # webbrowser ## Expo WebBrowser A library that provides access to the system's web browser and supports handling redirects. [](https://github.com/expo/expo/tree/sdk-54/packages/expo-web-browser)[](https://github.com/expo/expo/tree/sdk-54/packages/expo-web-browser/CHANGELOG.md)[](https://www.npmjs.com/package/expo-web-browser) `expo-web-browser` provides access to the system's web browser and supports handling redirects. On Android, it uses `ChromeCustomTabs` and on iOS, it uses `SFSafariViewController` or `ASWebAuthenticationSession`, depending on the method you call. As of iOS 11, `SFSafariViewController` no longer shares cookies with Safari, so if you are using `WebBrowser` for authentication you will want to use `WebBrowser.openAuthSessionAsync`, and if you just want to open a webpage (such as your app privacy policy), then use `WebBrowser.openBrowserAsync`. ## Installation `npx expo install expo-web-browser` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. ## Configuration in app config You can configure `expo-web-browser` using its built-in [config plugin](https://docs.expo.dev/config-plugins/introduction) if you use config plugins in your project ([Continuous Native Generation (CNG)](https://docs.expo.dev/workflow/continuous-native-generation)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library. ### Example app.json with config plugin `{ "expo": { "plugins": [ [ "expo-web-browser", { "experimentalLauncherActivity": true } ] ] } }` ### Configurable properties ## Usage `import { useState } from 'react'; import { Button, Text, View, StyleSheet } from 'react-native'; import * as WebBrowser from 'expo-web-browser'; %%placeholder-start%%%%placeholder-end%%import Constants from 'expo-constants'; export default function App() { const [result, setResult] = useState(null); const _handlePressButtonAsync = async () => { let result = await WebBrowser.openBrowserAsync('https://expo.dev'); setResult(result); }; return ( {result && JSON.stringify(result)} ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingTop: Constants.statusBarHeight, backgroundColor: '#ecf0f1', }, });` ### Handling deep links from the WebBrowser If your project uses Expo Router, deep links are handled automatically. If you use the `WebBrowser` window for authentication or another use case where you want to pass information back into your app through a deep link, add a handler with `Linking.addEventListener` before opening the browser. When the listener fires, you should call [`dismissBrowser`](https://docs.expo.dev/versions/latest/sdk/webbrowser#webbrowserdismissbrowser). It will not automatically be dismissed when a deep link is handled. Aside from that, redirects from `WebBrowser` work the same as other deep links. Read more about it in [Linking](https://docs.expo.dev/linking/into-your-app#handle-urls). ## API `import * as WebBrowser from 'expo-web-browser';` ## Methods ### `WebBrowser.coolDownAsync(browserPackage)` This methods removes all bindings to services created by [`warmUpAsync`](#webbrowserwarmupasyncbrowserpackage) or [`mayInitWithUrlAsync`](#webbrowsermayinitwithurlasyncurl-browserpackage). You should call this method once you don't need them to avoid potential memory leaks. However, those binding would be cleared once your application is destroyed, which might be sufficient in most cases. The promise which fulfils with `WebBrowserCoolDownResult` when cooling is performed, or an empty object when there was no connection to be dismissed. ### `WebBrowser.dismissAuthSession()` Dismisses the current authentication session. On web, it will close the popup window associated with auth process. The `void` on the successful attempt or throws an error if dismiss functionality is not available. ### `WebBrowser.dismissBrowser()` Dismisses the presented web browser. `[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<{ type: WebBrowserResultType.DISMISS }>` The promise that resolves with `{ type: 'dismiss' }` on the successful attempt or throws an error if dismiss functionality is not available. ### `WebBrowser.getCustomTabsSupportingBrowsersAsync()` Returns a list of applications package names supporting Custom Tabs, Custom Tabs service, user chosen and preferred one. This may not be fully reliable, since it uses `PackageManager.getResolvingActivities` under the hood. (For example, some browsers might not be present in browserPackages list once another browser is set to default.) The promise which fulfils with [`WebBrowserCustomTabsResults`](#webbrowsercustomtabsresults) object. ### `WebBrowser.maybeCompleteAuthSession(options)` Possibly completes an authentication session on web in a window popup. The method should be invoked on the page that the window redirects to. Returns an object with message about why the redirect failed or succeeded: If `type` is set to `failed`, the reason depends on the message: * `Not supported on this platform`: If the platform doesn't support this method (Android, iOS). * `Cannot use expo-web-browser in a non-browser environment`: If the code was executed in an SSR or node environment. * `No auth session is currently in progress`: (the cached state wasn't found in local storage). This can happen if the window redirects to an origin (website) that is different to the initial website origin. If this happens in development, it may be because the auth started on localhost and finished on your computer port (Ex: `128.0.0.*`). This is controlled by the `redirectUrl` and `returnUrl`. * `Current URL "" and original redirect URL "" do not match`: This can occur when the redirect URL doesn't match what was initial defined as the `returnUrl`. You can skip this test in development by passing `{ skipRedirectCheck: true }` to the function. If `type` is set to `success`, the parent window will attempt to close the child window immediately. If the error `ERR_WEB_BROWSER_REDIRECT` was thrown, it may mean that the parent window was reloaded before the auth was completed. In this case you'll need to close the child window manually. ### `WebBrowser.mayInitWithUrlAsync(url, browserPackage)` This method initiates (if needed) [CustomTabsSession](https://developer.android.com/reference/android/support/customtabs/CustomTabsSession.html#maylaunchurl) and calls its `mayLaunchUrl` method for browser specified by the package. A promise which fulfils with `WebBrowserMayInitWithUrlResult` object. ### `WebBrowser.openAuthSessionAsync(url, redirectUrl, options)` #### On Android: This will be done using a "custom Chrome tabs" browser, [AppState](https://reactnative.dev/docs/appstate), and [Linking](https://docs.expo.dev/versions/latest/sdk/linking) APIs. #### On iOS: Opens the url with Safari in a modal using `ASWebAuthenticationSession`. The user will be asked whether to allow the app to authenticate using the given url. To handle redirection back to the mobile application, the redirect URI set in the authentication server has to use the protocol provided as the scheme in app.json [`expo.scheme`](https://docs.expo.dev/versions/latest/config/app#scheme). For example, `demo://` not `https://` protocol. Using `Linking.addEventListener` is not needed and can have side effects. #### On web: > This API can only be used in a secure environment (localhost/https). to test this. Otherwise, an error with code [`ERR_WEB_BROWSER_CRYPTO`](#err_web_browser_crypto) will be thrown. This will use the browser's [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) API. * _Desktop_: This will create a new web popup window in the browser that can be closed later using `WebBrowser.maybeCompleteAuthSession()`. * _Mobile_: This will open a new tab in the browser which can be closed using `WebBrowser.maybeCompleteAuthSession()`. How this works on web: * A crypto state will be created for verifying the redirect. ``` * This means you need to run with `npx expo start --https` ``` * The state will be added to the window's `localstorage`. This ensures that auth cannot complete unless it's done from a page running with the same origin as it was started. Ex: if `openAuthSessionAsync` is invoked on `https://localhost:19006`, then `maybeCompleteAuthSession` must be invoked on a page hosted from the origin `https://localhost:19006`. Using a different website, or even a different host like `https://128.0.0.*:19006` for example will not work. * A timer will be started to check for every 1000 milliseconds (1 second) to detect if the window has been closed by the user. If this happens then a promise will resolve with `{ type: 'dismiss' }`. > On mobile web, Chrome and Safari will block any call to [`window.open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) which takes too long to fire after a user interaction. This method must be invoked immediately after a user interaction. If the event is blocked, an error with code [`ERR_WEB_BROWSER_BLOCKED`](#err_web_browser_blocked) will be thrown. * If the user does not permit the application to authenticate with the given url, the Promise fulfills with `{ type: 'cancel' }` object. * If the user closed the web browser, the Promise fulfills with `{ type: 'cancel' }` object. * If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser), the Promise fulfills with `{ type: 'dismiss' }` object. ### `WebBrowser.openBrowserAsync(url, browserParams)` Opens the url with Safari in a modal on iOS using [`SFSafariViewController`](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller), and Chrome in a new [custom tab](https://developer.chrome.com/multidevice/android/customtabs) on Android. On iOS, the modal Safari will not share cookies with the system Safari. If you need this, use [`openAuthSessionAsync`](#webbrowseropenauthsessionasyncurl-redirecturl-options). The promise behaves differently based on the platform. On Android promise resolves with `{ type: 'opened' }` if we were able to open browser. On iOS: * If the user closed the web browser, the Promise resolves with `{ type: 'cancel' }`. * If the browser is closed using [`dismissBrowser`](#webbrowserdismissbrowser), the Promise resolves with `{ type: 'dismiss' }`. ### `WebBrowser.warmUpAsync(browserPackage)` This method calls `warmUp` method on [CustomTabsClient](https://developer.android.com/reference/android/support/customtabs/CustomTabsClient.html#warmup\(long\)) for specified package. A promise which fulfils with `WebBrowserWarmUpResult` object. ## Types ### `AuthSessionOpenOptions` If there is no native AuthSession implementation available (which is the case on Android) the params inherited from [`WebBrowserOpenOptions`](#webbrowseropenoptions) will be used in the browser polyfill. Otherwise, the browser parameters will be ignored. Type: `[WebBrowserOpenOptions](https://docs.expo.dev/versions/latest/sdk/webbrowser#webbrowseropenoptions)` extended by: ### `WebBrowserAuthSessionResult` Literal Type: `union` Acceptable values are: `[WebBrowserRedirectResult](#webbrowserredirectresult)` | `[WebBrowserResult](#webbrowserresult)` ### `WebBrowserCompleteAuthSessionOptions` ### `WebBrowserCompleteAuthSessionResult` ### `WebBrowserCoolDownResult` Type: `ServiceActionResult` ### `WebBrowserCustomTabsResults` ### `WebBrowserMayInitWithUrlResult` Type: `ServiceActionResult` ### `WebBrowserOpenOptions` ### `WebBrowserRedirectResult` ### `WebBrowserResult` ### `WebBrowserWarmUpResult` Type: `ServiceActionResult` ### `WebBrowserWindowFeatures` Type: `Record` ## Enums ### `WebBrowserPresentationStyle` #### `AUTOMATIC` `WebBrowserPresentationStyle.AUTOMATIC = "automatic"` The default presentation style chosen by the system. On older iOS versions, falls back to `WebBrowserPresentationStyle.FullScreen`. #### `CURRENT_CONTEXT` `WebBrowserPresentationStyle.CURRENT_CONTEXT = "currentContext"` A presentation style where the browser is displayed over the app's content. #### `FORM_SHEET` `WebBrowserPresentationStyle.FORM_SHEET = "formSheet"` A presentation style that displays the browser centered in the screen. #### `FULL_SCREEN` `WebBrowserPresentationStyle.FULL_SCREEN = "fullScreen"` A presentation style in which the presented browser covers the screen. #### `OVER_CURRENT_CONTEXT` `WebBrowserPresentationStyle.OVER_CURRENT_CONTEXT = "overCurrentContext"` A presentation style where the browser is displayed over the app's content. #### `OVER_FULL_SCREEN` `WebBrowserPresentationStyle.OVER_FULL_SCREEN = "overFullScreen"` A presentation style in which the browser view covers the screen. #### `PAGE_SHEET` `WebBrowserPresentationStyle.PAGE_SHEET = "pageSheet"` A presentation style that partially covers the underlying content. #### `POPOVER` `WebBrowserPresentationStyle.POPOVER = "popover"` A presentation style where the browser is displayed in a popover view. ### `WebBrowserResultType` #### `CANCEL` `WebBrowserResultType.CANCEL = "cancel"` #### `DISMISS` `WebBrowserResultType.DISMISS = "dismiss"` #### `LOCKED` `WebBrowserResultType.LOCKED = "locked"` #### `OPENED` `WebBrowserResultType.OPENED = "opened"` ## Error codes ### `ERR_WEB_BROWSER_REDIRECT` Web only: The window cannot complete the redirect request because the invoking window doesn't have a reference to its parent. This can happen if the parent window was reloaded. ### `ERR_WEB_BROWSER_BLOCKED` Web only: The popup window was blocked by the browser or failed to open. This can happen in mobile browsers when the `window.open()` method was invoked too long after a user input was fired. Mobile browsers do this to prevent malicious websites from opening many unwanted popups on mobile. You're method can still run in an async function but there cannot be any long running tasks before it. You can use hooks to disable user-inputs until any other processes have finished loading. ### `ERR_WEB_BROWSER_CRYPTO` Web only: The current environment doesn't support crypto. Ensure you are running from a secure origin (localhost/https). --- # webview A library that provides a WebView component. [](https://github.com/react-native-webview/react-native-webview)[](https://www.npmjs.com/package/react-native-webview) `react-native-webview` provides a `WebView` component that renders web content in a native view. ## Installation `npx expo install react-native-webview` If you are installing this in an [existing React Native app](https://docs.expo.dev/bare/overview), make sure to [install `expo`](https://docs.expo.dev/bare/installing-expo-modules) in your project. Then, follow the [installation instructions](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Getting-Started.md#react-native-webview-getting-started-guide) provided in the library's README or documentation. ## Usage `import { WebView } from 'react-native-webview'; import Constants from 'expo-constants'; import { StyleSheet } from 'react-native'; export default function App() { return ( ); } const styles = StyleSheet.create({ container: { flex: 1, marginTop: Constants.statusBarHeight, }, });` ### With inline HTML `import { WebView } from 'react-native-webview'; import Constants from 'expo-constants'; import { StyleSheet } from 'react-native'; export default function App() { return (
Hello world
' }} /> ); } const styles = StyleSheet.create({ container: { flex: 1, marginTop: Constants.statusBarHeight, }, });` ## Learn more [ Visit official documentation Get full information on API and its usage. ](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Guide.md) ---