Cordova app (Android) not reloading after hot code push with deployed app

The issue is that hot code push can only update JavaScript code, so to protect against situations where updated code depends on (versions of) plugins that are not in the native app bundle, we block hot code push when either the platform version or the set of plugins have changed.

You may have installed or updated plugins yourself, but Meteor 1.3.1 also updates some plugins included by default. So if your server is running Meteor 1.3.1 and your app was build using Meteor 1.3, hot code push will be blocked until you update the app on the app store.

Is this the case, that hot code will be blocked for every minor update to Meteor, if the app and server are not running the same version?

This will be a huge problem for us. I can see the need to do this between 1.2 and 1.3 as it was a major update to mobile with lots of breaking changes. However, this is will be untenable for us if we have to re-submit to app store for every minor bug fix release of Meteor. I can potentially see the need to block hot code push if cordova plugin versions change, but not for Meteor IOS/Android versions.

Please clarify, thanks.

It is not about the version of Meteor per se, so this shouldn’t happen for every minor update. But we did update some of the versions of default plugins in Meteor 1.3.1, so that is what triggered this.

I updated my project to 1.3.1 today and I can see in __meteor_runtime_config__ that this is what’s running in production…

Unless absolutely required because of a major blocking bug in any of the default plugins bundled with Meteor I’d like to suggest that we NOT update these plugins between minor (x.x.x) releases and save these changes for major releases (x.x.0) going forward.

In addition, this should be documented in the release notes and history as this type of change is really a “breaking change” for any deployed mobile app.

Thanks again for all your hard work and great improvements with Meteor mobile.

3 Likes

@martijnwalraven i have a very similar issue while developing locally. The manifest file seems to not be served when i start the server with a simple

meteor run --settings “config/settings-local.json” --mobile-server “localIp:3000”

as soon as i run with ‘meteor run android-device’ the manifest file is served. But sometimes i want to just start the app via android studio to test some stuff. This was different some time ago and it think it makes sense to include server the manifest whenever there is a mobile-server flag and/or there are ios and android as platforms included.

http://MY.LOCAL.IP:3000/__cordova/manifest.json

Is there a special flag we could use to fix this while developing right now?

@nerdmed: This was actually a deliberate change made as a result of this issue, because people wanted the ability to run the app in the browser without building the Cordova bundle. A few people have noted they preferred the previous behavior, so maybe we need to somehow make this configurable.

@martijnwalraven ok i see, i dont know how much time you have right now for this. I could work on a PR to make it customizable. I think the options are:

  • Enviroment variable
  • Detect --mobile-server Flag (why should i use the mobile server flag when running on browsers only)

I think detecting the mobile server flag makes most sense. What do you think?

I was just scouting around the forums to find out why my app wasn’t hot code pushing, them came across this post. A big +1 to not make any cordova updates or anything that would disable hot code push in minor versions, this caused us some headaches today wondering why our app wasn’t updating.

@markoshust same here, all my developers were going crazy because of this - maybe i will find the time for a quick fix on the weekend

@martijnwalraven I have been running into similar problems ( Error: Skipping downloading new version ... ) in development. While we’re not in production yet I can see this causing issues for us regardless of how Meteor’s own cordova dependencies are handled going forward.

I can understand the point made by @skirunman in regards to not updating plugin dependencies unless necessary but at the same time why should we limit updates to cordova components based on this? In our case we also have our fair share of plugin (some in-house) dependencies that will likely change frequently but will generally remain compatible.

Do you think it would make more sense to provide a means to override this compatibility check in some way (perhaps thru mobile-config.js) to define some type of compatibility level (i.e. a-plugin 1.0.0 & 1.0.1 are compatible) which would be generated in the manifest and taken into account during this check? Meteor itself could even inject its own pre-defined compatibility maps for said major version if it makes sense but beyond that it would be up to us to decide and define what is considered compatible and what isn’t in regards to cordova upgrades.

Thanks for all your awesome work!

1 Like

Really I don’t get any of this…

This is from production manifest after building on final server

manifest: [], version: "fcff1a30ae87438d1f849d8c31522ba775768e4a", cordovaCompatibilityVersions: { android: "3c917ef06da10ba0bd5ca565c630423e423d14e5", ios: "bb2f370767fa894b9135fa8213e1a46e4bc17aa2" }

and this what my local manifest shows when I run meteor --production (–android-device so the manifest is served…)

manifest: [], version: "0c7e8aae38dba77f94a7333cdb4f2aeac5c8db67", cordovaCompatibilityVersions: { android: "61029d6a87fc59dfe343a3c0486f392ebe295113", ios: "4ba03a4d551df0557396260438c3d791f05f7a44" }

On my local server, the meteor version is updated, cordovaCompatibility stands, that makes sense, and updates get pushed all right.
When I build my app for Cordova locally, it gets assigned a cordovaCompatibilityVersions.android that should reflect what that version will be on production server.

My question is simple:

if I build my app locally, say for Android, and then push my code to be handled by the build stack on the server, which then produce a NEW build, with a new cordovaCompatibilityVersions.android, how the hell can those versions match in the first place?

Sorry if I sound desperate. That’s because I am :tired_face:.

Are your server and your development machine running the same version of Meteor? There have been some updates to plugins in 1.3.1, and these affect the cordovaCompatibilityVersions.

Other than that, the results should be the same. The hash is based on the exact versions of the Cordova platform and plugins used in your app.

What do you mean by build stack on the server? I assume you run meteor build?

Yup, 1.3.1 on both sides.

Meteor app is published using Scalingo node buildpack with the --server-only option set to true to build the cordova.web target, just like we talked about…

I uninstalled my own local Cordova via npm, just to be sure.
meteor build logs say Android project created with cordova-android@5.1.1.
I can’t say for sure if there’s a difference in Cordova version once deployed, but the meteor version is definitely the same.

And meteor_runtime_config gives me

on server:
appId:"1yb4n7j1dgujxeg48ddu" autoupdateVersion:"17296cfd7afc77a031d0460b67db848d2b77982c" autoupdateVersionCordova:"42854b4dd77a1e2d02d1521e685d561c6e727a21" autoupdateVersionRefreshable:"18ed05fde50e6f92d9f8ca65f1119c3dc66d5671"

Inspecting the webview of the mobile app:
appId: "1yb4n7j1dgujxeg48ddu" autoupdateVersionCordova: "598ce839cf96aa4e2b890c6a598db1fd2ce6ad6c"

@martijnwalraven any updates on this issues? Its really a pain while developing for native. I think the tradeoff between speed and breaking the developer experience for a lot of mobile developers should be clearly towards making things work. I would really appreciate reverting the change that is causing this issues. I assume that this did not happen with one of the 2 patches that were released the last days.

@nerdmed: While there have been plugin changes between 1.3.0 and 1.3.1, there have been none in further patch releases. So as far as I know hot code push should work, and if it doesn’t we should find out why.

Another question is whether the current compatibility policy is too strict or whether we need to implement some kind of manual override. Basically, any change in native code (platforms and plugins) could trigger an incompatibility with user JavaScript code, so I implemented a conservative strategy of always blocking hot code push when the versions don’t match.

1 Like

@martijnwalraven is it possible for you to not block hot code push releases for custom cordova plugins that we install?

there are many situations where we want to release a new code update with a hot code push. it does involve a new cordova plugin, however there is also functionality we are releasing that doesn’t require this new plugin, and/or the plugin is optional (for example, let’s say ‘dark keyboard’). we don’t want our entire hot code push blocked because the new version of our code says that we have this plugin, which really isn’t needed.

as far as being worried about cordova-specific code causing an app to crash, i think that should be left up to the implementer to decide. for example, every single place there is cordova code in my app, i wrap it in code like this:

import {Meteor} from 'meteor/meteor';
import {_} from 'meteor/underscore';

const hideKeyboard = () => {
  if (Meteor.isCordova
    && _.isObject(cordova.plugins)
    && _.isObject(cordova.plugins.Keyboard)
  ) { 
    cordova.plugins.Keyboard.close();
  }
};

export default hideKeyboard;

so let’s say i release new code now containing the Keyboard cordova plugin, i really don’t want this hot code push blocked, because it will not crash my app because of this code.

if you want to continue blocking, it would be really nice to expose the ability to not block hot code pushes in this event from the mobile-config file or something similar.

another situation where this applies is let’s say i have a major release coming up, and i submitted it to the app store and it’s awaiting approval. if i push the related code out to production, anyone who downloads the current version of the app that is live in the app store never gets any hot code push updates, because the most recent push fails because of the cordova block. however, when apple reviews it, it can get denied because the server code isn’t up to date, as it’s possible some new function calls don’t exist yet on the server because we can’t push out this update (because we still want users to get most recent hot code push for their app version).

1 Like

@markoshust: I think the solution is to allow developers to override cordovaCompatibilityVersions (the same way we allow AUTOUPDATE_VERSION to be defined manually). This way, you could set it to the current value when adding new plugins so hot code push won’t be blocked. Could you open a GitHub issue for this?

1 Like

+1 this would be awesome! Spent nearly two days tracking the same issue (on iOS) down to a tiny cordova version bump.

doesn’t look like an issue was already opened for this, opened one as: https://github.com/meteor/meteor/issues/7030

1 Like