Skip to content

Self updating AppImages

probonopd edited this page Jul 4, 2018 · 7 revisions

Many AppImage users requested a feature other software distribution systems have had for many years: An app should be able to update itself. Using the new AppImageUpdate and libappimageupdate, this becomes even easier than ever before.

User stories

John: "I am running stock Ubuntu and downloaded Transmission.AppImage. Like on the Mac, I would like to be able to update the application from within itself - I know this feature from the Mac where Transmission uses the Sparkle Framework"

Jane: "I am running an AppImage-enabled distribution that comes with a software center that takes care of keeping all my AppImages updated for me. I should have the option to also check for updates from within the application, but this should not interfere with the software center.

Update Concepts

When talking about self-updating software, there's a few similar, but different in detail, concepts to consider:

  • fully automatic updates - either during application startup (ensures latest version, but the user might get distracted when forced to wait for more than a few minutes for the update to complete before the application finally starts up) - on termination (a little more user friendly, as the application starts up immediately) - or in the background, while the application is running
  • user-triggered self updates - application performs update check and asks user whether to upgrade
    • can be done both on application startup or termination, similar to fully automatic updates
    • fully manual updates with user triggered update check

Fully Automatic Self Updates

Some applications, e.g., ones with remote components (server-side APIs, game servers, etc.) often have to deal with outdated clients, which are unable to connect and/or use the online services. Therefore, such applications may consider updating themselves automatically.

However, this variant has a few disadvantages that should be considered before implementing it. First of all, by not asking for the users' consent, the user might be taken by surprise, which is a big downer especially when users are forced to use a slow connection to the Internet, they may have to plan updates to take place over night etc. Enforcing an update on application startup resp. performing it while the application is running ruins their user experience. To sum up, this method should only be considered if there is an absolute need for it.

We recommend to ask the user whether the application should search for updates whenever the application detects that a) a large timespan has passed since it was built, or b) if it encounters issues

NOTE: Ideally, please don't ask the user whether the application should search for updates directly when the application is launched for the first time. This gives a bad impression. Usually people want to look at the application when it is launched for the first time, and an update nag screen just gets in their way. Also, automatic screenshots for AppImageHub are not giving the best impression when all they show is an update nag screen. At least do this only on the second launch of the application, or when the user quits the application.

User Controlled Updates

A more user friendly approach is to inform a user about a new version and ask them whether to perform the update or not. Whenever a user decides to click OK, it is their decision, resulting in them being more willing to wait for the update to complete before getting distracted.

The most widely used implementations are to either check for updates on application startup, notify the user immediately (with a modal dialog), and ask them whether to perform an update or start the application. This is not very user friendly, and suffers from the same problems as the automatic self updates before application startup. More user friendly approaches allow the application to start up and draw the user interface, and then check for updates and ask the user whether to update (some implementations even perform updates in the background, and due to how AppImages work (being sold single files per application which are replaced by new files by AppImageUpdate), this becomes possible without any modification). After completing the update, next time the application is started, the new version will be displayed. Additional to that, the application can ask the user whether to restart immediately after the update completed.

Recommended user experience

One advantage of the AppImage format is that it gives full control to application authors over the end user experience. Hence, using AppImage and AppImageUpdate, application authors can implement almost any of the schemes outlined above. In order to maintain a consistent and positive user experience with AppImages and AppImageUpdate, we recommend application authors to follow the following Golden Rules:

  • Never download updates without the user's explicit consent, be it in the form of per-update consent, or, optionally, opt-in consent for automatic updates. Thanks for not killing users' mobile data plans by downloading stuff without asking
  • Respect global flags for "do not check for new versions" and __"do not attempt to update". The user may be running a central updating daemon that manages updates for the whole system, in which case any and all attempts to update the application from within itself should be skipped. We need to define those flags, 1) for per-system and 2) per-user configuration and 3) ENV (similar to how the old desktopintegration script was set up not to interfere with appimaged)
  • Do not bother the user with updates directly as the first thing when the application is launched. When opening an application for the first time, users should see something meaningful to give a positive impression and show immediately what the application is all about (after all, we are automatically taking a screenshot of what your application shows directly after it has been launched for AppImageHub)
  • Ask the user for permission before doing version checks. Many open source users value privacy highly and don't appreciate the "phone home" aspect of forced version checks, which effectively are a form of tracking

Real-world example

  • The update should ideally be nicely integrated into the GUI of your application, using whatever GUI toolkit you are using. We are interested in getting libraries for popular GUI toolkits like Qt, Gkt+ 2 and 3, WxWidgets, etc. - so if you implement this, please share with the world
  • During the update process, your application should remain fully usable (this works because the original file is not changed by the update process; instead a new file with the new version is placed next to the original one)
  • Releases should always update to releases, nightlies always to nightlies, etc. ("channels")
  • Whenever the application encounters issues (e.g., a crash reporter comes up) it could ask the user to check for updates, and accept bug reports only if no newer version is available in the channel

Using libappimageupdate to Provide a Native Update User Interface

Since the rewrite of AppImageUpdate in modern C++11, the software architecture has been changed: The core functionality was moved to a library with a clean API, for which several frontend user applications for standalone use have been developed. These are AppImageUpdate, a GUI app for updating AppImages, and appimageupdatetool, a more feature complete CLI tool exposing most of libappimageupdate's API to the command line, while setting sane defaults for the use case of managing external AppImages.

There is a guide on using libappimageupdate in an app center (e.g., OCS-Store app, NX Software Center) like scenario, where the task is to update AppImages downloaded and managed by through the app center.

If there are enough people showing interest in a guide dedicated to using it for self-updating applications, such a guide might follow with detailed instructions. However, most of the other guide applies to this scenario as well. Just beware to use the value of the APPIMAGE environment variable to initialize the appimage::update::Updater class, e.g., by appimage::update::Updater updater(getenv("APPIMAGE")) (but you should really add some error handling to that).

Using the existing AppImageUpdate User Interfaces to perform updates

As mentioned previously, there's a few frontends to libappimageupdate other AppImages. When parametrized correctly, those tools can be used for self updates as well.

To do so, you need to embed either appimageupdatetool*.AppImage (for CLI applications) or AppImageUpdate*.AppImage into your own AppImage. Instead of nesting these AppImages into your AppDir (which is possible), it may be preferred to extract them into your AppDir (see below). Similar to using libappimageupdate, the file path parameter needs to be set to the value of the environment variable APPIMAGE. Since in this scenario, the subprocess interface is used instead of having to use a C++ library, this method can be used for tools of all kinds, and is not bound to a single language (or, actually, ABI type).

Both AppImageUpdate and appimageupdatetool provide an easy to use update check. Just call those apps with the -j flag, and watch the exit code. If it exits with return value 0, the update check succeeded, and there is no newer version available. Status 1 means that the update check succeeded, and an update is available. Any other return code can be considered an error while trying to check for changes.

When there is an update available, your main application does not need to exit but can start AppImageUpdate or appimageupdatetool as previously described. The user can continue using your application while it is updated, which is an important aspect of the desired user experience. To do so, it is recommended to use the language's implementation of exec, e.g., by calling exec AppImageUpdate*.AppImage $APPIMAGE in a shell script.

Please note that putting AppImages into other AppImages is likely to break use of the extracted AppImage in situations where FUSE is not available (e.g., an unprivileged Docker container, where extracting an AppImage is a secure and unproblematic alternative to adding privileges to a container), as the AppImageUpdate AppImages still depend on FUSE. If your AppImage shall work in such situations after having been extracted, you should consider extracting AppImageUpdate*.AppImage resp. appimageupdatetool*.AppImage in a location inside the AppDir that you can locate relative to your main binary.