Is your Meteor Cordova app not getting the updates you’re deploying?
After reading this article, you’ll know:
This article builds on the Cordova article. We recommend reading that first, though we’ve tried to link back to its relevant sections.
Make sure that you have:
hot-code-push listed in your .meteor/versions file--server flag of your meteor build command points to the same place as your ROOT_URL environment variable (or, on Galaxy, the site in meteor deploy site). See details Did the app suddenly stop getting new code after you updated meteor, or you changed plugins?
The client probably logs: Skipping downloading new version because the Cordova platform version or plugin versions have changed and are potentially incompatible
Meteor, Cordova and plugins cannot be updated through Hot Code Push. So Meteor by default disables Hot Code Push to app versions that have different versions than the server. This avoids crashing a user’s app, for example, when new JS calls a plugin that his app version doesn’t yet have.
You can override this behavior. Just make sure you deal with potentially incompatible versions in your JS instead.
AUTOUPDATE_VERSION is an environment variable you can add to your run and deploy commands:
$ AUTOUPDATE_VERSION=abc meteor deploy example.com
If your app has an AUTOUPDATE_VERSION set, make sure you change its value when you want a deploy to update your clients.
Are you seeing your web app incorporate changes without reload, yet your cordova app reloads each time?
For CSS-only changes, this is the expected behaviour. Browsers update the layout without reload, but in cordova, any change reloads the whole app.
In case you want to implement soft CSS update for Cordova, see below how to edit the source.
There are several reload packages, and maybe your app includes some custom reload code. Of course, these may have bugs or be outdated.
In particular, when you push an update, does the app reload but use the old code anyways? Probably, the code hasn’t been updated to work with Meteor 1.8.1 or later. As mentioned in the changelog, we recommend you call WebAppLocalServer.switchToPendingVersion before forcing a browser reload.
Alternatively, use the built-in behavior to reload. Instead of, say, window.location.reload(), call the retry function passed to the Reload._onMigrate() callback. For example:
Reload._onMigrate((retry) => {
if (/* not ready */) {
window.setTimeout(retry, 5 * 1000); // Check again in 5 seconds
return [false];
}
// ready
return [true];
});
If you use a package that is no longer compatible, consider forking it or opening a PR with the above changes. Alternatively, you can switch to a compatible one such as quave:reloader
Cordova doesn’t show the URL bar, but the user is still on some URL or other, which may have a hash (#). HCP works better if it doesn’t.
If you can, remove the hash fragment before the reload.
In the client side logs, you may see HCP fail with errors like:
Error: Error downloading asset: /
at http://localhost:12472/plugins/cordova-plugin-meteor-webapp/www/webapp-local-server.js:51:21
at Object.callbackFromNative (http://localhost:12472/cordova.js:287:58)
at <anonymous>:1:9
This error from cordova-plugin-meteor-webapp may be caused by big files, often in the public folder. Downloading these can fail depending on connection speed, and available space on the device.
You could run $ du -a public | sort -n -r | head -n 20 to find the 20 biggest files and their sizes. Consider serving them from an external storage service or CDN instead. Then they are only downloaded when really needed, and can fail downloading without blocking HCP.
If you notice HCP works in production but not when you test locally, you may need to enable clear text or set a correct --mobile-server. Both are explained in the docs.
If none of that solved your issues and you’d like to dive deeper, here’s some tips to get you started.
If you end up finding a bug in one of Meteor’s packages or plugins, don’t hesitate to open an issue and/or a pull request.
Hot code push is included in meteor-base through a web of official meteor packages, most importantly reload and autoupdate.
In the case of cordova, a lot of the heavy lifting is done by cordova-plugin-meteor-webapp.
To oversimplify, autoupdate decides when to refresh the client, the plugin then downloads the new client code and assets, and reload then refreshes the page to start using them.
We can break it down a bit more:
To figure out where the issue is, we can log the various steps HCP takes.
First, make sure you can see client-side logs (or print them on some screen of your app).
A few more useful values to print, and events to listen to, might be:
The version hashes: __meteor_runtime_config__.autoupdate.versions['web.cordova']
The reactive Autoupdate.newClientAvailable(): if this turns into true and then doesn’t refresh, you know the client does receive the new version but something goes wrong trying to download or apply it.
Tracker.autorun(() => {
console.log(‘new client available:’, Autoupdate.newClientAvailable());
});
Meteor.default_connection._subscriptions. For example, to log whether the subscription is ready and inactive (using lodash):const { ready, inactive } = _.chain(Meteor)
.get('default_connection._subscriptions', {})
.toPairs()
.map(1)
.find({ name: 'meteor_autoupdate_clientVersions' })
.pick(['inactive', 'ready']) // comment this to see all options
.value();
console.log(‘ready:’, ready);
console.log(‘inactive:’, inactive);
Or, to log the value of ready each time the subscription changes:
const hcpSub = _.chain(Meteor)
.get('default_connection._subscriptions', {})
.toPairs()
.map(1)
.find({ name: 'meteor_autoupdate_clientVersions' })
.value(); // no .pick() this time; return whole subscription object
Tracker.autorun(() => {
hcpSub.readyDeps.depend(); // Rerun when something changes in the subscription
console.log('hcpSub.ready', hcpSub.ready);
});
Should print false and then true less than a second later.
WebAppLocalServer.onNewVersionReady;WebAppLocalServer.onNewVersionReady(() => {
console.log('new version is ready!');
// Copied from original in autoupdate/autoupdate_cordova.js because we overwrite it
if (Package.reload) {
Package.reload.Reload._reload();
}
});
Reload._onMigrate(). Be sure to return [true] or the reload may not happen. (I believe that if this is run in your app code, it means all packages allowed the reload. But I didn’t find my source on this.)Reload._onMigrate(() => {
console.log('going to reload now');
return [true];
});
Meteor.startup was the result of a HCP reload or not, we can take advantage of the fact that Sessions (like ReactiveDicts) are preserved.Meteor.startup(() => {
console.log('Was HCP:', Session.get('wasHCP'));
Session.set('wasHCP', false);
Reload._onMigrate(() => {
Session.set('wasHCP', true);
return [true];
});
});
Finally, if you want to change some of the package and plugin code locally, you can.
Say we want to edit the autoupdate package.
In the root of your project, create a folder named packages, then add a folder autoupdate. Here we put the code from the original package (found in ~/.meteor/packages), then we edit it.
Meteor will now use the local version instead of the official one.
To install a modified version of a plugin,
git clone https://github.com/meteor/cordova-plugin-meteor-webapp.gitmeteor add cordova:cordova-plugin-meteor-webapp@file://path/to/cordova-plugin-meteor-webapp Meteor will start using the local version instead of the official one. But note you will have to rerun meteor build or meteor run every time you change the plugin.
If you found a bug in one of the packages or plugins, don’t hesitate to open an issue and/or pull request.