Android Expo Updates Issues

We’ve been building a bare workflow app for release and have faced some issues with expo-updates@0.2.2 and assets management on Android.

Runtime Version
The first weird thing was that in the docs it specified that runtimeVersion should be an “An object with keys ios and android whose corresponding values are the runtime version this update is compatible with.”

So, in our app.json we had something like this:

"runtimeVersion": {
   "ios": "1",
   "android": "1"
}

Having the json structured this way made expo-updates consistently fail to find the update on android (Updates.manifest = {}), and we had an error in cli saying that runtimeVersion should be a string.

When we set "runtimeVersion": "1" and Updates.manifest started to be populated again.

We had a look into the expo-updates Android code and found out that there are 3 types of manifest; bare, legacy and new (expo-cli@3.20.9).

The manifest we generate seems to match the legacyManifest, in fact in the function that parses the json it tries to handle both string and object for runtimeVersion. Code for this is here:

if (runtimeVersionObject != null) {
      if (runtimeVersionObject instanceof String) {
        runtimeVersion = (String)runtimeVersionObject;
      } else if (runtimeVersionObject instanceof JSONObject) {
        runtimeVersion = ((JSONObject)runtimeVersionObject).optString(“android”, runtimeVersion);
      }
    }

But it also seems that a legacyManifest should match this config:

expo.modules.updates.EXPO_LEGACY_MANIFEST

Questions

  1. However we do not set this parameter, so how does this work?
  2. Why don’t we have a bareManifest, when in a bare workflow?

assetUrlOverride Not Constructed Correctly

With the above fix and the manifest being parsed correctly, the update still fails due to wrong asset urls when using assetUrlOverride to set an absolute path for the assets. With this our hosted android-index.json would contain:

"assetUrlOverride": "https://xxx.cloudfront.net/yyy/3dd28fbbf/native/bare/assets",

This has always worked fine for iOS, however on android the update fails because it looks for assets and appends assetUrlOverride to the updates host url. We are setting the EXPO_UPDATE_URL with:

 <meta-data android:name=“expo.modules.updates.EXPO_UPDATE_URL” android:value=“https://xxx.com/pocket/jkTTiukljhe12kl2sF2d3/android-index.json” />

This results in something like:

https://xxx.com/pocket/jkTTiukljhe12kl2sF2d3/https%3A%2F%2Fxxx.cloudfront.net%yyy%2F055d780a0%2Fnative%2Fbare%2Fassets/0ec7d3a4f6643fca50b88f4e2efd5898

We also noticed the URL is only partially encoded.

To resolve this issue we have patched this code.

  1. In order to have the builder to get instantiated as empty: Uri.Builder assetsBaseUrlBuilder = new Uri.Builder();
  2. Properly handle the encoded path: assetsBaseUrlBuilder.encodedPath(assetsPath);

The resulting code looks like:

if (mAssetsUrlBase == null) {
          // use manifest url as the base
          String assetsPath = getRawManifestJson().optString("assetUrlOverride", "assets");
          Uri.Builder assetsBaseUrlBuilder = new Uri.Builder();
          List<String> segments = manifestUrl.getPathSegments();
          assetsBaseUrlBuilder.path("");
          for (int i = 0; i < segments.size() - 1; i++) {
            assetsBaseUrlBuilder.appendPath(segments.get(i));
          }
          assetsBaseUrlBuilder.encodedPath(assetsPath);
          mAssetsUrlBase = assetsBaseUrlBuilder.build();
        }

Questions
3. How is this intended to work?

With all of the above we now have expo-updates working on Android, hosted on our own server with an assetUrlOverride set. Has anyone else managed to get this working without the above?

5 Likes

Yes, it’s a bug for sure, please see the attached screenshot of the network traffic generated by Android App.

@notbrent do you recommend the above fix so we can use this fix till the proper fix get released?

@mdcuk34 I have applied your fix and it’s working fine :slight_smile: Also network requests goes to the right place.

2 Likes

@mdcuk34 Hi! I have the same problem with assetUrlOverride Not Constructing Correctly. Is it the only solution for this or maybe it is possible to make some expo-updates downgrade? Something changed since June? I tried new version but It is not working for same reason.

Hey @egorzotov, interestingly we’ve just hit the assetUrlOverride Not Constructing Correctly issue again (IOS & Android) due to the new Expo Client release; 2.16.1 works and 2.17.1 fails to download an update with a wrongly constructed URL.

We’re running an ejected app in the client and generating the JS with the following: expo export --target managed --public-url XXX --asset-url ZZZ and seeing the following request come through: https://ZZZhttps://Z%Z%Z/assets/6a05a3dbb727fc769e3a56794654dd86. I’m guessing the code mentioned in the original post or something similar has made it into the Expo Client and is causing the issue.

@notbrent Any ideas?

hi there! i’m going to pass this on to @esamelson - he works on the updates related code. we really appreciate all of the information provided in this report!

1 Like

a fix for this is available now: https://github.com/expo/expo/issues/10464#issuecomment-703178030

Hey @notbrent! Thanks for covering previous issue!

I think we got a new one in bare workflow now.
We have expo SDK 39 bare app that using expo-updates. I configured it like it said in docs, our manifest is self hosted and here is the link: https://gurucan-app-bundle.hb.bizmrg.com/v2-9-8-test/android-index.json

Here is configuration in AndroidManifest:

<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://gurucan-app-bundle.hb.bizmrg.com/v2-9-8-test/android-index.json"/>

It is configured properly and i can see that app trying to update and manifest fetched properly.
The problem is that assets links generated by expo-updates native code is corrupted and it is cause of failed OTA update.
Here is the error:

Failed to download asset from https://gurucan-app-bundle.hb.bizmrg.com/v2-9-8-test/%2Fassets/778ffc9fe8773a878e9c30a6304784de
java.lang.Exception: Network request failed: <?xml version="1.0" encoding="utf-8"?>
<Error><Code>AccessDenied</Code><RequestId>5HCZbcpD</RequestId><Message>Access Denied</Message></Error>
	at expo.modules.updates.loader.FileDownloader$1.onResponse(FileDownloader.java:64)
	at expo.modules.updates.loader.FileDownloader$4.onResponse(FileDownloader.java:202)
	at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206)
	at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
	at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
	at java.lang.Thread.run(Thread.java:929)

I think error caused by native code assets link generator because i assume that “%2F” is url encoded “/” symbol.

Maybe there is some problem with my “assetUrlOverride” option in manifest but I am sure that this is default value and it was working perfectly on expokit 36 SDK.

hi there! this seems like it might be an issue - are you using the latest version of expo-updates? if so, can you post to https://github.com/expo/expo/issues with information on how we can reproduce it?

@notbrent Hi again. I think that problem is actually resolved. I was so frustrated with previous update problem that i forgot about adding custom asset-url to expo export script. It became “./assets” instead of “/assets” and I assume that it is working now (no url error in adb).

expo export --output-dir $RELEASE_CHANNEL --public-url $HOSTING_ADDRESS/$RELEASE_CHANNEL --asset-url /assets"

I tried on absolutely clean project and updates working there.
My main app is crashing after fix and OTA update with this error: Unable to publish OTA updates in expo bare app
But i am sure that it is my bad and i need to clean some expo imports and maybe update cli tools.

Thanks for fast response!

1 Like