Need to transform design to code? Don't hardcode it, Avocode it!
See how
GET A FREE MONTH
Code
·
LAST UPDATED
October 24, 2016

Get that damn Windows Auto Update working on Electron

Fullstack developer @Avocode.

This article is based on Window Auto Update example repository. Feel free to clone and try it here.

If you're building a cross-platform app with JavaScript, HTML and CSS, you might have some experience with the Electron autoUpdater. Though it provides an uniform API, autoupdating on Windows tends to be quite tricky. Since Avocode is also running on Windows, I had to create a couple of tweaks here and there. So everything you need to make Windows Auto Update work is:

  • Electron
  • Electron packager (builder), I use electron-builder which can build all the platforms just on Mac
  • Some index.html file that Electron can load and boot electron.autoUpdater there

Behind the scenes

It's not that important to know how this works behind the scenes, so let's just quickly go through some terms:

electron-builder uses Squirrel, a packager capable of building setup files for .exe binaries automatically.

You need an installer because just a bold .exe file itself cannot be auto updated with Electron. That's why you need a packager capable of calling Squirrel.

Since Squirrel is a Windows application, you still need some runtime. On Linux or Mac you can simply use Wine.

I would recommend this perfect tutorial how to install Wine on the Mac via brew: https://www.davidbaumgold.com/tutorials/wine-mac/.

The update process itself is based on .nupkg packages (=binary format similar to .zip) which holds source code of your application.

Squirrel generates your-app-1.0.0-full.nupkg which is a complete application binary and if it's possible it also generates a file called your-app-1.0.0-delta.nupkg.

This *-delta.nupkg file is important for auto updates. This file holds a patch that needs to be applied to previous version of your app to update to the next version.

So how can you force electron-builder to create such file for you?

The key is the RELEASES file. This file is always generated by Squirrel. It is simply a list of available app versions with checksums and names of *.nupkg files for every version.

Let's do this

Alright, first make sure you are on a Windows machine. If not, just download and install Wine - Mac guide here.

Once you are done with that, you can install this repo:

bash
npm install
//or
yarn install

Alright, verify that everything works by starting a prebuild of our app:

bash
npm start

What an app, right? Note that version number is dynamic and will change when we update our app.

Let's try to create the Windows build I have prepared for you:

bash
npm run build

Well, this fails. The reason it fails is that I have added a line that tells Squirrel where it should find all my app releases in RELEASES file.

Now let's just delete one line from package.json, so we can build the windows app. Note that electron-builder uses package.json to configure the build, and so far I got everything I needed without any programming required.

bash
// delete this line:
"remoteReleases": "http://localhost:9000/dist/win1/"
//lets do the build again
npm run build

Now everything should go OK. If you have troubles with Wine make sure you did all of the steps described above.

NOTE that in package.json this part:

plain
"win": {
   "certificateFile": "./certs/my_signing_key.pfx",
   "certificatePassword": ""
}

I generated dummy certificates to sign this app. If you won't provide these files, autoUpdate will not work, so you better replace these lines with your own certificate info.

FYI: Guide to generate such certificates is here: https://www.npmjs.com/package/electron-installer-windows

So what do we have now? Well, in dist/win there is something like electron-windows-autoupdate-1.0.0-full.nupkg which is packed binary. Along with electron-windows-autoupdate Setup 1.0.0 which is Windows installer of our App. Great.

If you don't like the file name, just change name key in package.json.

The most important part to make Windows AutoUpdate work is however this simple text file RELEASES (dist/win/RELEASES).

This file is the key to create *-delta.nupkg files needed for auto update. Squirrel must be able to find this file, however electron-builder only supports web links to the release file in config. But is that an obstacle for a programmer like you? Of course not.

It's time to make folder dist/win accessible over the internet. In production, you would probably upload all these artifacts from dist/win to S3 bucket or whatever, and just pasted the links. Well, in dev mode, we would be OK just with SimpleHTTPServer which is shipped on Mac as well as on Linux and Windows if you download python. You can of course use any other server, that can server static files, express, webpack, apache, nginx whatever. The only requirement is that we have a web url that points to dist/win.

Firstly rename dist/win to some other name (I use dist/win1). The reason for renaming is that the electron-builder would overwrite folder dist/win with all it's content, In order to keep it unchanged for the auto update, just rename it.

Then just:

bash
// start server here
python -m SimpleHTTPServer 9000
// or just
npm run start:server

Now if you do:

bash
open http://localhost:9000/dist/win1/RELEASES

it should open RELEASES in the browser, maybe it downloads it - everything but the 404 error is OK.

Next we have to tell Squirrel that we already have some versions of our app built and we want another version to be and update of older ones.

To do that, just bump version in package.json to eg. 2.0.0. If you won't bump version, new build will not be an update of previous version.

Now let's put back that line we deleted from electron-builder config in package.json.

So your key build in package.json should look like this.

"build": {
   "squirrelWindows": {
      "remoteReleases": "http://localhost:9000/dist/win1/"
   },
   "win": {
      "certificateFile": "./certs/my_signing_key.pfx",
      "certificatePassword": ""
   }
},

NOTE that in remoteReleases you only need to specify the path to the folder where RELEASES and *-*.nupkg files are, not the path to individial files!

So run again the build script:

bash
// make sure serve runs in root of this repo
// npm run start:server
npm run build

dist/win and dist/win1 should be in the dist folder.

To verify that Squirrel has seen previous RELEASES, take a look into dist/win/RELEASES. And here you should see something like this:

CF1472BFD1F777AAE09501313AA55A7C080CD620 electron-windows-autoupdate-1.0.0-full.nupkg 54575243
7CD4A1765DF084BFE36FC615A63D05DA3CB89ABD electron-windows-autoupdate-2.0.0-delta.nupkg 34921
A94689C1884E9ED50963BFF58ED974AA4D17EEA1 electron-windows-autoupdate-2.0.0-full.nupkg 54576239

If there is just one line, it means that you did not bump version in package.json.

If you have 3 lines, well done. Squirrel noticed a previous version and created *-delta.nupkg which holds the difference between the older version and current one. There is also a note about *-full.nupkg which is a package binary of the next version of your app that you just built.

Now that all the update files are prepared we may implement app code that will implement auto update in the app.

Handle auto update in the app

All the magic you can see in index.html.

Things to notice are:

  • auto update event listener registered by autoUpdate.on()
  • most important event is update-downloaded, after this event you can install the update
  • autoUpdater.setFeedURL() which I may get to
  • finally autoUpdater.checkForUpdates() that is all you need to do to check for update and download it
  • and of course autoUpdater.quitAndInstall() called after update-downloaded is fired

Setting auto update feed URL

Note this line autoUpdater.setFeedURL('http://localhost:9000/dist/win/'). AutoUpdater uses Squirrel in the background, so it requires a URL to a folder where all the required files are located. These files are familiar *-full/delta.nupkg and RELEASES.

But this time, this url must point to a folder where update files are located.

In our case, we have old update files in dist/win1 but files for a newer version (along with RELEASES with all the versions) is in dist/win.

Next we will try install and auto update our app, we have to start a server that would point to dist/win and set autoUpdater.setFeedURL() accordingly, so we have to run this on the Windows machine.

We can copy update files to windows machine, or upload them to the web, and set the url, so that it points to the folder with *.nupkg and RELEASES.

You can use SimpleHTTPServer again even on Windows, just make sure you have python installed and in your PATH.

You can clone this repo and run:

bash
npm run start:server

Again and it should all work.

Now, this is the time to run windows installer, but make sure you install the first version from dist/win1/*Setup<version>.exe!!

Once done, you should see Current version is: 1.0.0 in our awesome app. Also you should see some logs in console saying that an update is available, then that the update is available, being downloaded and finally an alert pop ups, confirm it and App will automatically update.

Now you see Current version is: <BUMPED VERSION>

FAQ

No update is available

Make sure that dist/win is accessible via browser on your Windows machine. Make sure you have correct url set on updater by calling autoUpdater.setFeedURL().

/RELEASES/ not found

Make sure server is running and "remoteReleases" in package.json is set correctly.

Cannot get signature of running application

Code sign was not applied, take a look here how to generate one: https://www.npmjs.com/package/electron-installer-windows

Let me know how it works for you, either in the comments below or on Github where you can also find a run example.

get guacamole
Free 3-in-1 UI kit
Are you a modern designer with taste? Get Guacamole
- a free UI kit  for Adobe Xd, Photoshop and Sketch.
Get a free UI kit
Available for: