How do I force an expo app to update

Joel Jackson picture Joel Jackson · Jul 3, 2018 · Viewed 11.2k times · Source

I have an app written in expo, and can't figure out how to push a new build. On the expo site if I run the app from the QR code the app is correct, but the native app from the app store doesn't update.

The steps I've been using are 1) exp build:android 2) exp publish

How do I make the app actually update?

Answer

Bruno Eduardo picture Bruno Eduardo · Jan 27, 2019

TL;DR: OTA updates are enforced by default. App Store updates can be enforced by adding code to check your app version on startup and, if there's a new version, open the App Store on your app's page.

There's two ways of updating a standalone Expo app:

  1. OTA update using expo-cli publish
  2. Using Google Play/App Store

Both of these methods have advantages and shortcomings.

OTA Updates

This is the usual way an update is delivered to Expo apps. OTAs are done via the expo CLI tool and deliver new Javascript code based on your package.json settings. This option also offers the option to publish code using release channels, meaning you could push updates first to you staging environment, validate the update and then push it to production via CLI like so:

expo-cli publish -release-channel staging # pushes and update to the staging channel
expo-cli publish -release-channel production # pushes an update to the production channel

If you are publishing but your standalone app is not updating you might be pushing code to the wrong release channel. You can read more about release channels here.

OTAs are enforced by default:

By default, Expo will check for updates automatically when your app is launched and will try to fetch the latest published version. If a new bundle is available, Expo will attempt to download it before launching the experience.

However it's possible to disable this behavior by setting updates.enabled to false in app.json and then implement your own logic (or none at all), as per the example in their docs:

try {
  const update = await Expo.Updates.checkForUpdateAsync();
  if (update.isAvailable) {
    await Expo.Updates.fetchUpdateAsync();
    // ... notify user of update ...
    Expo.Updates.reloadFromCache();
  }
} catch (e) {
  // handle or log error
}

This system is really great for pushing new JS code to your users, it really helps with live testing since you can test your app with your user, find a flaw, fix it and publish new code which will be almost instantly available for download.

Yet this method has its limitations, for example: you can't update the Expo SDK version this way, you must build a new standalone app and distribute it through the app store (or whatever other method of your choosing).

App Stores

This is the most common way to distribute your .apk and .ipa files. These files can be created by using the expo-cli build:android and expo-cli build:ios for Android and iOS respectively.

It seems like there's an Android API being tested to enforce apps to be updated via this method (SO thread, article), but I don't think it's available yet.

One possible solution to enforce updates via this method is to check your app version on startup and, if there's a new version available in the store, open the app's store page via deep linking so the user is able download it. The example below should help you visualize what I mean.

componentDidMount {
   const hasNewVersion = isStoreUpdateAvailable(); // Checks the store for a new app update
   if (hasNewVersion) {
     Linking.openURL("market://details?id=<>"); // Opens the app's store page so the user can download the update
   }
}

Here's the docs about linking to Google Play.

Hope this answer all your questions, if not leave a comment and I'll edit the answer.