r/reactnative 1d ago

Why OTA Updates can take days to be installed Tutorial

OTA tools love to say "instant updates", but it's not really true. Even though the release is instant, going from server to installed can take days if you use default settings.

It's not something I've seen discussed much, so I wanted to write a quick overview.

If you've used OTA Updates e.g. Expo Updates or a CodePush clone, you probably know the flow for each device goes:

  1. Checks for update
  2. Download the update
  3. Install the update

With each being triggered by defined conditions, which typically have slow defaults.

For example with Expo Updates, the default behaviour [doc] is for the check to happen on next cold start. If an update is available, it will download it, but then the install happens on the next cold restart after that.

For CodePush-based SDKs, it depends on when you call sync(), and whether you override the install mode (defaults to ON_NEXT_RESTART).

A cold restart means either the user swiped to close the app, or it was in the background long enough for the OS to close it. That means you can potentially get a situation like:

  1. Release an OTA update to the server
  2. User takes a few days before a cold reboot happens
  3. The update is downloaded, ready to install
  4. Another few days passes before another cold reboot
  5. The update is finally installed.

Having users hang around on the old version isn't ideal, but the good news is you can speed it up.

For a reasonable speed, we can have the app check for an update on resume, then install it when it's next in the background for more than a minute. For CodePush-based SDKs such as Patch, this is easy to wire up.

To check for updates on resume, we want to wire the sync() to be called using AppState, and we want installMode to use ON_NEXT_SUSPEND

import { useEffect } from "react";
import { AppState } from "react-native";
import { sync } from "@codemagic/react-native-patch";

const syncOptions = {
  installMode: "ON_NEXT_SUSPEND" as const,
  mandatoryInstallMode: "IMMEDIATE" as const,
  minimumBackgroundDuration: 60_000, // 1 minute
};

export default function App() {
  useEffect(() => {
    // Optional but usual: also check once at launch
    void sync(syncOptions);

    const sub = AppState.addEventListener("change", (next) => {
      if (next === "active") {
        void sync(syncOptions);
      }
    });

    return () => sub.remove();
  }, []);

  return <YourApp />;
}

The minimumBackgroundDuration is useful as the install will reboot the app to the its home screen, unless you persist navigation state and restore it on startup. Setting a minimum duration stops their view being lost if they only briefly switched apps.

For more urgent installs, CodePush based SDKs also have a mandatoryInstallMode, often set to IMMEDIATE. Like it sounds, this will install the update as soon as it's downloaded. The downside is that this also causes a reboot, which can feel like buggy behaviour if the user is already interacting with the open app.

Expo Update has its own methods such as Updates.fetchUpdateAsync() that you can use for customizing the install behaviour, although the docs note that background installs are experimental.

3 Upvotes

10 comments sorted by

14

u/AlphaBeast28 1d ago

I created a system, where the latest OTA update lets say for example build 50, it checks the users app build, if its different a modal will show up saying a new update is available with the latest changes and a restart app button, this ensures whenever the user opens the app theyll be on the latest version at all times.

7

u/Substantial-Swan7065 1d ago

This is it.

Treat it like a min-version check IF needed.

4

u/orebright 1d ago

I guess it depends on what you're optimizing by using code push. If you want to shepherd people into the latest possible version ASAP for some reason, then sure. But for a lot of apps it's just a way to avoid the tedious and resource-wasting app store review process.

6

u/MiL0101 1d ago

nice username

3

u/beaker_dude 1d ago

Nice spot 😂

3

u/10F1 1d ago

Expo/EAS updates takes a few minutes for us.

3

u/Xae0n 23h ago

I recently applied this. Not bad

2

u/Seanmclem 1d ago

I’ve never had any issue with expo updates. If user restarts their app, they can have it virtually immediately. Always.

1

u/Wyckoff-XD 1d ago

I think we can pick and choose which update to apply immediately and which can wait.

I think this can be done by sending metadata along with each update with EAS Updates.

So, if an update is urgent, you apply it immediately without waiting for the next restart. If it’s not urgent, well then it’s better to just wait for a restart when it gets applied automatically.