Conveyor supports three different approaches to software updates:
app.updates = background(the default)
app.updates = aggressive
app.updates = none
In aggressive mode an update check will be performed synchronously on each app start. If a new version is available then the update process will start and the update downloaded and applied, without any user interaction being required.
In background mode the behaviour differs by OS:
- The OS itself will check for updates every 8 hours and upgrade the app in the background, even if it's not being used. Your users will never see an update prompt.
- The app will check for updates on startup without blocking the user, and on a schedule whilst the app runs. Once the user agrees, updates will be downloaded and applied in the background ready for the next launch.
- No difference, forced updates are not supported.
app.updates = none support for auto updates is removed, except on Linux where apt repositories will continue to be installed (this is a known issue). Note that this doesn't simply turn off polling: on macOS Sparkle won't be shipped, and there isn't any way to trigger an update.
Which mode to use depends heavily on how often your users will start the app and how important it is for updates to be applied quickly. If your app is a client for a server that speaks a complex protocol and you don't want to preserve protocol backwards compatibility, aggressive mode is appropriate. If your app is self-contained or the protocols it speaks evolve in a compatible way, background mode gives a better user experience as the user won't be interrupted by the update process.
Silent upgrades on macOS
If you don't want your users to ever see an update prompt you can set
app.mac.sparkle-options.SUAutomaticallyUpdate = true. However, if your users don't run your app for long enough for updates to download and apply then they may fall behind and be unaware of it. Use this mode with caution.
When updates are aggressive you can force an update by restarting your app:
Updates are implemented by a program called
updatecheck.exe. The start menu entry points at this program, which will do a check and then invoke your real EXE. You can run this and then shut down, or open your app URL in the same way as the start menu does by opening the URL
shell:appsFolder\\$appUserModeID where the app user model ID can be obtained by running
conveyor make app-user-model-id (please note that it depends on the signing certificate used so if you sign with test certificates, pay attention to that).
open command with your
.app directory, or use the Launch Services API pointed at your own app.
On Linux aggressive updates aren't supported. You can of course run
apt-get update then
apt-get install <your package name> if you're installed via a deb, or invoke the GNOME UI for it yourself.
Here are some strategies for knowing when to restart the app:
- Poll the
metadata.propertiesfile Conveyor generates as part of the download site. See below for how to do this.
- If your app relies on a server, incorporate the required version of the app into the protocol so you can reject clients that are too old. For example you can put the min required version in an HTTP header.
- Simply set a maximum uptime for the app.
- Wait until the computer has been idle with the app on-screen for long enough before restarting automatically.
Be aware of the following:
Updates are only checked on startup. Users can leave their app running for long periods, so the server might change whilst instances are running. Your protocol should ideally check on each request if the client is out of date and return an error if so that tells the user to restart the app (or does it for them). Note that this is actually no different to a web app because users can leave tabs open for long periods, so if you roll out a new web server version that renames an endpoint you might break users who are using the app at that time, necessitating either a way to detect that (hard) or simply telling users to reload tabs if they break.
Your app will start a bit slower. This is of course also no different to a web app, which will also check with a web server on every startup. If the update check takes longer than two seconds then a progress UI will appear.
Aggressive updates aren't implemented on Linux. It's unconventional for apps to control their own update process on this platform. If distributing to Linux you should check the
metadata.properties file that's generated as part of your download/update site (
conveyor make site) by looking at the
app.version key, and then ask the user to update themselves if they've fallen behind in your UI.
Checking for new versions in JVM apps
When packaged the
app.repositoryUrl system property will contain the site base URL, and
app.version contains the content of the
app.version key. Note: this does not include the revision, as that's meant only for changes to the package itself not the contained
app.revision is also set if you want to compare against that too. So to implement an update check on Linux add
/metadata.properties to the value of that system property, download it over HTTPS, parse it with the
app.version key from the parsed file and then compare it with the
app.version system property. The
class from the Maven source code is an easy way to compare version numbers; it can be copy/pasted into your source tree. If the app
is behind then hide the main screen and show a message to the user asking them to upgrade their package by using apt-get.
Checking for new versions in Electron apps
After fetching the
metadata.properties file the dot-properties package can be used to
parse it, or you can just do some simple string manipulation: split to lines, drop any line starting with
#, split each
=, convert to a map and (optionally, if you're adding custom keys) un-backslash-escape the values. Supporting the full
specification isn't necessary for parsing this file. To learn what the current version use your
include your site URL in that file and then in.
Checking for new versions in other apps
Although there is a precise specification for the
there's no need to fully implement it. The format can be treated as a simple set of
key=value pairs in which lines starting with
are to be ignored, and the values should be un-backslash-escaped before use.