---
title: Add expo-updates to an existing project
description: Learn how to add expo-updates to an existing React Native project.
---
import { DiffBlock, Terminal } from '~/ui/components/Snippet';
import { Collapsible } from '~/ui/components/Collapsible';
The `expo-updates` library fetches and manages updates received from a remote server. It supports [EAS Update](/eas-update/introduction), a hosted service that serves updates for projects using the expo-updates library.
> If you are creating a new project, we recommend using `npx create-react-native-app` instead of `npx react-native init` because it will handle the following configuration for you automatically. It includes the `expo-updates` [config plugin](/guides/config-plugins), which will handle the following steps for you.
## Installation
The `expo-updates` library requires that your project already has [Expo modules configured](/bare/installing-expo-modules). Be sure to install it before continuing.
To get started, install `expo-updates`:
Then, install pods:
Once installation is complete, apply the changes from the following diffs to configure `expo-updates` in your project.
## Configuration in JavaScript and JSON
You'll need to modify **index.js** to import `expo-asset` early in your app, to be able to update assets with updates.
```diff index.js
+ import 'expo-asset';
import { registerRootComponent } from 'expo';
import App from './App';
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
```
## Configuration for iOS
Add the **Supporting** directory containing **Expo.plist** to your project in Xcode with the following content:
```xml Expo.plist
EXUpdatesCheckOnLaunch
ALWAYS
EXUpdatesEnabled
EXUpdatesLaunchWaitMs
0
EXUpdatesSDKVersion
46.0.0
EXUpdatesURL
https://exp.host/@my-expo-username/my-app
```
## Configuration for Android
Apply the following configurations to your **AndroidManifest.xml** file:
```diff AndroidManifest.xml
+
+
+
+
+
+
```
## Customizing Automatic Setup for iOS
By default, `expo-updates` requires no additional setup. If you want to customize the installation, for example, to enable updates only in some build variants, you can instead follow these manual setup steps and then apply any customizations.
### Update AppDelegate.h
```diff apps/bare-update/ios/bareupdate/AppDelegate.h
#import
+ #import
#import
#import
#import
- @interface AppDelegate : EXAppDelegateWrapper
+ @interface AppDelegate : EXAppDelegateWrapper
```
### Update AppDelegate.mm
There are multiple changes to apply to your project's **AppDelegate.mm**.
```diff apps/bare-update/ios/bareupdate/AppDelegate.mm
+ @interface AppDelegate ()
+
+ @property (nonatomic, strong) NSDictionary *launchOptions;
+
+ @end
+
@implementation AppDelegate
```
```diff apps/bare-update/ios/bareupdate/AppDelegate.mm
- RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
+ self.launchOptions = launchOptions;
+ self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+ #ifdef DEBUG
+ [self initializeReactNativeApp];
+ #else
+ EXUpdatesAppController *controller = [EXUpdatesAppController sharedInstance];
+ controller.delegate = self;
+ [controller startAndShowLaunchScreen:self.window];
+ #endif
+
+ [super application:application didFinishLaunchingWithOptions:launchOptions];
+
+ return YES;
+ }
+
+ - (RCTBridge *)initializeReactNativeApp
+ {
+ RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:self.launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"main" initialProperties:nil];
id rootViewBackgroundColor = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"RCTRootViewBackgroundColor"];
if (rootViewBackgroundColor != nil) {
```
```diff apps/bare-update/ios/bareupdate/AppDelegate.mm
rootView.backgroundColor = [UIColor whiteColor];
}
- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
- [super application:application didFinishLaunchingWithOptions:launchOptions];
-
- return YES;
+ return bridge;
}
- (NSArray> *)extraModulesForBridge:(RCTBridge *)bridge
```
```diff apps/bare-update/ios/bareupdate/AppDelegate.mm
#ifdef DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
- return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
+ return [[EXUpdatesAppController sharedInstance] launchAssetUrl];
#endif
}
+ - (void)appController:(EXUpdatesAppController *)appController didStartWithSuccess:(BOOL)success {
+ appController.bridge = [self initializeReactNativeApp];
+ }
// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options {
return [RCTLinkingManager application:application openURL:url options:options];
```
### Expo.plist
```diff apps/bare-update/ios/bareupdate/Supporting/Expo.plist
EXUpdatesURL
https://exp.host/@my-expo-username/my-app
+ EXUpdatesAutoSetup
+
```
## Customizing Automatic Setup for Android
By default, `expo-updates` requires no additional setup. If you want to customize the installation, for example, to enable updates only in some build variants, you can instead follow these manual setup steps and then apply any customizations.
### AndroidManifest.xml
```diff apps/bare-update/android/app/src/main/AndroidManifest.xml
+
```
### MainApplication.java
There are multiple changes to apply to your project's **MainApplication.java**
```diff apps/bare-update/android/app/src/main/java/com/bareupdate/MainApplication.java
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
+ import android.net.Uri;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
```
```diff apps/bare-update/android/app/src/main/java/com/bareupdate/MainApplication.java
import expo.modules.ApplicationLifecycleDispatcher;
import expo.modules.ReactNativeHostWrapper;
+ import expo.modules.updates.UpdatesController;
import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
```
```diff apps/bare-update/android/app/src/main/java/com/bareupdate/MainApplication.java
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
+ import javax.annotation.Nullable;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(
```
```diff apps/bare-update/android/app/src/main/java/com/bareupdate/MainApplication.java
protected JSIModulePackage getJSIModulePackage() {
return new ReanimatedJSIModulePackage();
}
+
+ @Override
+ protected @Nullable String getJSBundleFile() {
+ if (BuildConfig.DEBUG) {
+ return super.getJSBundleFile();
+ } else {
+ return UpdatesController.getInstance().getLaunchAssetFile();
+ }
+ }
+
+ @Override
+ protected @Nullable String getBundleAssetName() {
+ if (BuildConfig.DEBUG) {
+ return super.getBundleAssetName();
+ } else {
+ return UpdatesController.getInstance().getBundleAssetName();
+ }
+ }
});
```
```diff apps/bare-update/android/app/src/main/java/com/bareupdate/MainApplication.java
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
+ if (!BuildConfig.DEBUG) {
+ UpdatesController.initialize(this);
+ }
+
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
ApplicationLifecycleDispatcher.onApplicationCreate(this);
}
```
## Usage
See more information about usage in the [`expo-updates` README](https://github.com/expo/expo/tree/main/packages/expo-updates/README.md).
## FAQ
If you have assets (such as images or other media) that are imported in your application code, and you would like these to be downloaded atomically as part of an update, add the `assetBundlePatterns` field under the `expo` key in your project's **app.json**. This field should be an array of file glob strings that point to the assets you want to be bundled. For example: `"assetBundlePatterns": ["**/*"]`