UNPKG

13.1 kBMarkdownView Raw
1# expo-updates
2
3`expo-updates` fetches and manages updates to your app stored on a remote server.
4
5## API documentation
6
7- [Documentation for the master branch](https://github.com/expo/expo/blob/master/docs/pages/versions/unversioned/sdk/updates.md)
8- [Documentation for the latest stable release](https://docs.expo.io/versions/latest/sdk/updates/)
9
10Additionally, for an introduction to this module and tooling around OTA updates, you can watch [this talk](https://www.youtube.com/watch?v=Si909la3rLk) by [@esamelson](https://github.com/esamelson) from ReactEurope 2020.
11
12## Compatibility
13
14This module requires `expo-cli@3.17.6` or later; make sure your global installation is at least this version before proceeding.
15
16Additionally, this module is only compatible with Expo SDK 37 or later. For bare workflow projects, if the `expo` package is installed, it must be version `37.0.2` or later.
17
18Finally, this module is not compatible with ExpoKit. Make sure you do not have `expokit` listed as a dependency in package.json before adding this module.
19
20## Upgrading
21
22If you're upgrading from `expo-updates@0.1.x`, you can opt into the **no-publish workflow**. In this workflow, release builds of both iOS and Android apps will create and embed a new update at build-time from the JS code currently on disk, rather than embedding a copy of the most recently published update. For instructions and more information, see the [CHANGELOG](https://github.com/expo/expo/blob/master/packages/expo-updates/CHANGELOG.md). (For new projects, the no-publish workflow is enabled by default.)
23
24# Installation in managed Expo projects
25
26For [managed](https://docs.expo.io/versions/latest/introduction/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](https://docs.expo.io/versions/latest/sdk/updates/).
27
28# Installation in bare React Native projects
29
30Learn how to install expo-updates in your project in the [Installing expo-updates documentation page](https://docs.expo.io/bare/installing-updates/).
31
32## Embedded Assets
33
34In certain situations, assets that are `require`d by your JavaScript are embedded into your application binary by Xcode/Android Studio. This allows these assets to load when the packager server running locally on your machine is not available.
35
36Debug builds of Android apps do not, by default, have any assets bundled into the APK; they are always loaded at runtime from the Metro packager.
37
38Debug builds of iOS apps built for the iOS simulator also do not have assets bundled into the app. They are loaded at runtime from Metro. Debug builds of iOS apps built for a real device **do** have assets bundled into the app binary, so they can be loaded from disk if they cannot be loaded from the packager at runtime.
39
40Release builds of both iOS and Android apps include a full embedded update, including manifest, JavaScript bundle, and all imported assets. This is critical to ensure that your app can load for all users immediately upon installation, without needing to talk to a server first.
41
42## Configuration
43
44Some build-time configuration options are available to allow your app to update automatically on launch. On iOS, these properties are set as keys in `Expo.plist` and on Android as `meta-data` tags in `AndroidManifest.xml`, adjacent to the tags added during installation.
45
46On Android, you may also define these properties at runtime by passing a `Map` as the second parameter of `UpdatesController.initialize()`. If provided, the values in this Map will override any values specified in `AndroidManifest.xml`. On iOS, you may set these properties at runtime by calling `[UpdatesController.sharedInstance setConfiguration:]` at any point _before_ calling `start` or `startAndShowLaunchScreen`, and the values in this dictionary will override Expo.plist.
47
48| iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
49| --- | --- | --- | --- | --- |
50| `EXUpdatesEnabled` | `enabled` | `expo.modules.updates.ENABLED` | `true` | ❌ |
51
52Whether updates are enabled. Setting this to `false` disables all update functionality, all module methods, and forces the app to load with the manifest and assets bundled into the app binary.
53
54| iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
55| --- | --- | --- | --- | --- |
56| `EXUpdatesURL` | `updateUrl` | `expo.modules.updates.EXPO_UPDATE_URL` | (none) | ✅ |
57
58The URL to the remote server where the app should check for updates. A request to this URL should return a valid manifest object for the latest available update and tells expo-updates how to fetch the JS bundle and other assets that comprise the update. (Example: for apps published with `expo publish`, this URL would be `https://exp.host/@username/slug`.)
59
60| iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
61| --- | --- | --- | --- | --- |
62| `EXUpdatesSDKVersion` | `sdkVersion` | `expo.modules.updates.EXPO_SDK_VERSION` | (none) | (exactly one of `sdkVersion` or `runtimeVersion` is required) |
63
64The SDK version string to send under the `Expo-SDK-Version` header in the manifest request. Required for apps hosted on Expo's server.
65
66| iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
67| --- | --- | --- | --- | --- |
68| `EXUpdatesRuntimeVersion` | `runtimeVersion` | `expo.modules.updates.EXPO_RUNTIME_VERSION` | (none) | (exactly one of `sdkVersion` or `runtimeVersion` is required) |
69
70The Runtime Version string to send under the `Expo-Runtime-Version` header in the manifest request.
71
72| iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
73| --- | --- | --- | --- | --- |
74| `EXUpdatesReleaseChannel` | `releaseChannel` | `expo.modules.updates.EXPO_RELEASE_CHANNEL` | `default` | ❌ |
75
76The release channel string to send under the `Expo-Release-Channel` header in the manifest request.
77
78| iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
79| --- | --- | --- | --- | --- |
80| `EXUpdatesCheckOnLaunch` | `checkOnLaunch` | `expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH` | `ALWAYS` | ❌ |
81
82The condition under which `expo-updates` should automatically check for (and download, if one exists) an update upon app launch. Possible values are `ALWAYS`, `NEVER` (if you want to exclusively control updates via this module's JS API), or `WIFI_ONLY` (if you want the app to automatically download updates only if the device is on an unmetered Wi-Fi connection when it launches).
83
84| iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
85| --- | --- | --- | --- | --- |
86| `EXUpdatesLaunchWaitMs` | `launchWaitMs` | `expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS` | `0` | ❌ |
87
88The number of milliseconds `expo-updates` should delay the app launch and stay on the splash screen while trying to download an update, before falling back to a previously downloaded version. Setting this to `0` will cause the app to always launch with a previously downloaded update and will result in the fastest app launch possible.
89
90# Removing pre-installed expo-updates
91
92Projects created by `expo init` and `expo eject` come with expo-updates pre-installed, because we anticipate most users will want this functionality. However, if you do not intend to use OTA updates, you can disable or uninstall the module.
93
94### Disabling expo-updates
95
96If you disable updates, the module will stay installed in case you ever want to use it in the future, but none of the OTA-updating code paths will ever be executed in your builds. To disable OTA updates, add the `EXUpdatesEnabled` key to Expo.plist with a boolean value of `NO`, and add the following line to AndroidManifest.xml:
97
98```xml
99<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
100```
101
102### Uninstalling expo-updates
103
104Uninstalling the module will entirely remove all expo-updates related code from your codebase. To do so, complete the following steps:
105
106- Remove `expo-updates` from your package.json and reinstall your node modules.
107- Remove the line `../node_modules/expo-updates/scripts/create-manifest-ios.sh` from the "Bundle React Native code and images" Build Phase in Xcode.
108- Delete Expo.plist from your Xcode project and file system.
109- Remove the line `apply from: "../../node_modules/expo-updates/scripts/create-manifest-android.gradle"` from `android/app/build.gradle`.
110- Remove all `meta-data` tags with `expo.modules.updates` in the `android:name` field from AndroidManifest.xml.
111- Apply the following three diffs:
112
113#### `AppDelegate.h`
114
115Remove`EXUpdatesAppControllerDelegate` as a protocol of your `AppDelegate`.
116
117```diff
118-#import <EXUpdates/EXUpdatesAppController.h>
119 #import <React/RCTBridgeDelegate.h>
120 #import <UMCore/UMAppDelegateWrapper.h>
121
122-@interface AppDelegate : UMAppDelegateWrapper <RCTBridgeDelegate, EXUpdatesAppControllerDelegate>
123+@interface AppDelegate : UMAppDelegateWrapper <RCTBridgeDelegate>
124
125 @property (nonatomic, strong) UMModuleRegistryAdapter *moduleRegistryAdapter;
126 @property (nonatomic, strong) UIWindow *window;
127 ```
128
129#### `AppDelegate.m`
130
131```diff
132 #import <UMReactNativeAdapter/UMNativeModulesProxy.h>
133 #import <UMReactNativeAdapter/UMModuleRegistryAdapter.h>
134
135-@interface AppDelegate ()
136-
137-@property (nonatomic, strong) NSDictionary *launchOptions;
138-
139-@end
140-
141 @implementation AppDelegate
142
143...
144
145 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
146 {
147 self.moduleRegistryAdapter = [[UMModuleRegistryAdapter alloc] initWithModuleRegistryProvider:[[UMModuleRegistryProvider alloc] init]];
148- self.launchOptions = launchOptions;
149-
150- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
151-#ifdef DEBUG
152- [self initializeReactNativeApp];
153-#else
154- EXUpdatesAppController *controller = [EXUpdatesAppController sharedInstance];
155- controller.delegate = self;
156- [controller startAndShowLaunchScreen:self.window];
157-#endif
158-
159- [super application:application didFinishLaunchingWithOptions:launchOptions];
160-
161- return YES;
162-}
163-
164-- (RCTBridge *)initializeReactNativeApp
165-{
166- RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:self.launchOptions];
167+ RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
168 RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"YOUR-APP-NAME" initialProperties:nil];
169 rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
170
171+ self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
172 UIViewController *rootViewController = [UIViewController new];
173 rootViewController.view = rootView;
174 self.window.rootViewController = rootViewController;
175 [self.window makeKeyAndVisible];
176
177- return bridge;
178+ [super application:application didFinishLaunchingWithOptions:launchOptions];
179+
180+ return YES;
181 }
182
183...
184
185 #ifdef DEBUG
186 return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
187 #else
188- return [[EXUpdatesAppController sharedInstance] launchAssetUrl];
189+ return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
190 #endif
191 }
192
193-- (void)appController:(EXUpdatesAppController *)appController didStartWithSuccess:(BOOL)success
194-{
195- appController.bridge = [self initializeReactNativeApp];
196-}
197-
198 @end
199```
200
201#### `MainApplication.java`
202
203```diff
204-import android.net.Uri;
205-import expo.modules.updates.UpdatesController;
206-import javax.annotation.Nullable;
207-
208 public class MainApplication extends Application implements ReactApplication {
209 private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(
210 new BasePackageList().getPackageList(),
211
212...
213
214 protected String getJSMainModuleName() {
215 return "index";
216 }
217-
218- @Override
219- protected @Nullable String getJSBundleFile() {
220- if (BuildConfig.DEBUG) {
221- return super.getJSBundleFile();
222- } else {
223- return UpdatesController.getInstance().getLaunchAssetFile();
224- }
225- }
226-
227- @Override
228- protected @Nullable String getBundleAssetName() {
229- if (BuildConfig.DEBUG) {
230- return super.getBundleAssetName();
231- } else {
232- return UpdatesController.getInstance().getBundleAssetName();
233- }
234- }
235 };
236
237...
238
239 public void onCreate() {
240 super.onCreate();
241 SoLoader.init(this, /* native exopackage */ false);
242-
243- if (!BuildConfig.DEBUG) {
244- UpdatesController.initialize(this);
245- }
246-
247 initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
248 }
249 }
250 ```
251
252#### Remove Pods Target EXUpdates (Optional)
253
254If, after following above steps, your `npm run ios` or `yarn ios` fails and you see `EXUpdates` in logs, follow the steps below:
255
256- Open the iOS directory in Xcode
257- Go to Pods module on right side
258- In the targets, find `EXUpdates`, right click and delete
259
\No newline at end of file