Instantly share code, notes, and snippets.

@iffy /.gitignore
Last active Dec 6, 2018

Embed
What would you like to do?
Example using electron-updater with `generic` provider.
node_modules
dist/
yarn.lock
wwwroot

This repo contains the bare minimum code to have an auto-updating Electron app using electron-updater with releases stored on a plain HTTP server.

This example uses localhost as the release server.

  1. For macOS, you will need a code-signing certificate.

    Install Xcode (from the App Store), then follow these instructions to make sure you have a "Mac Developer" certificate. If you'd like to export the certificate (for automated building, for instance) you can. You would then follow these instructions.

  2. Install necessary dependencies with:

     yarn
    

    or

     npm install
    
  3. Build your app with:

     node_modules/.bin/build --win --mac --x64 --ia32
    
  4. Copy the files in the dist/ directory to your webserver. Here's how to do it on a Linux system:

     mkdir -p wwwroot
     cp dist/*.json wwwroot/
     cp dist/*.yml wwwroot/
     cp dist/mac/*.zip wwwroot/
     cp dist/mac/*.dmg wwwroot/
     cp dist/*.exe wwwroot/
    
  5. Serve wwwroot over HTTP:

     node_modules/.bin/http-server wwwroot/ -p 8080
    
  6. Download and install the app from http://127.0.0.1:8080

  7. Update the version in package.json.

  8. Do steps 3 and 4 again.

  9. Open the installed version of the app and see that it updates itself.

const {app, BrowserWindow, Menu, protocol, ipcMain} = require('electron');
const log = require('electron-log');
const {autoUpdater} = require("electron-updater");
//-------------------------------------------------------------------
// Logging
//
// THIS SECTION IS NOT REQUIRED
//
// This logging setup is not required for auto-updates to work,
// but it sure makes debugging easier :)
//-------------------------------------------------------------------
autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
log.info('App starting...');
//-------------------------------------------------------------------
// Define the menu
//
// THIS SECTION IS NOT REQUIRED
//-------------------------------------------------------------------
let template = []
if (process.platform === 'darwin') {
// OS X
const name = app.getName();
template.unshift({
label: name,
submenu: [
{
label: 'About ' + name,
role: 'about'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click() { app.quit(); }
},
]
})
}
//-------------------------------------------------------------------
// Open a window that displays the version
//
// THIS SECTION IS NOT REQUIRED
//
// This isn't required for auto-updates to work, but it's easier
// for the app to show a window than to have to click "About" to see
// that updates are working.
//-------------------------------------------------------------------
let win;
function sendStatusToWindow(text) {
log.info(text);
win.webContents.send('message', text);
}
function createDefaultWindow() {
win = new BrowserWindow();
win.webContents.openDevTools();
win.on('closed', () => {
win = null;
});
win.loadURL(`file://${__dirname}/version.html#v${app.getVersion()}`);
return win;
}
autoUpdater.on('checking-for-update', () => {
sendStatusToWindow('Checking for update...');
})
autoUpdater.on('update-available', (ev, info) => {
sendStatusToWindow('Update available.');
})
autoUpdater.on('update-not-available', (ev, info) => {
sendStatusToWindow('Update not available.');
})
autoUpdater.on('error', (ev, err) => {
sendStatusToWindow('Error in auto-updater.');
})
autoUpdater.on('download-progress', (ev, progressObj) => {
sendStatusToWindow('Download progress...');
})
autoUpdater.on('update-downloaded', (ev, info) => {
sendStatusToWindow('Update downloaded; will install in 5 seconds');
});
app.on('ready', function() {
// Create the Menu
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
createDefaultWindow();
});
app.on('window-all-closed', () => {
app.quit();
});
//-------------------------------------------------------------------
// Auto updates
//
// For details about these events, see the Wiki:
// https://github.com/electron-userland/electron-builder/wiki/Auto-Update#events
//
// The app doesn't need to listen to any events except `update-downloaded`
//
// Uncomment any of the below events to listen for them. Also,
// look in the previous section to see them being used.
//-------------------------------------------------------------------
// autoUpdater.on('checking-for-update', () => {
// })
// autoUpdater.on('update-available', (ev, info) => {
// })
// autoUpdater.on('update-not-available', (ev, info) => {
// })
// autoUpdater.on('error', (ev, err) => {
// })
// autoUpdater.on('download-progress', (ev, progressObj) => {
// })
autoUpdater.on('update-downloaded', (ev, info) => {
// Wait 5 seconds, then quit and install
// In your application, you don't need to wait 5 seconds.
// You could call autoUpdater.quitAndInstall(); immediately
setTimeout(function() {
autoUpdater.quitAndInstall();
}, 5000)
})
app.on('ready', function() {
autoUpdater.checkForUpdates();
});
{
"name": "electron-updater-generic-example",
"version": "0.2.0",
"main": "main.js",
"description": "electron-updater generic example project",
"author": "Matt Haggard",
"devDependencies": {
"electron": "^1.4.15",
"electron-builder": "^12.3.1",
"http-server": "^0.9.0"
},
"dependencies": {
"electron-log": "^1.3.0",
"electron-updater": "^1.4.2"
},
"build": {
"publish": [
{
"provider": "generic",
"url": "http://127.0.0.1:8080/"
}
],
"appId": "com.github.iffy.electronupdatergenericexample",
"mac": {
"category": "your.app.category.type",
"target": [
"zip",
"dmg"
]
},
"nsis": {
"perMachine": true
}
}
}
<!DOCTYPE html>
<html>
<head>
<title>Electron Updater Example</title>
</head>
<body>
Current version: <span id="version">vX.Y.Z</span>
<div id="messages"></div>
<script>
// Display the current version
let version = window.location.hash.substring(1);
document.getElementById('version').innerText = version;
// Listen for messages
const {ipcRenderer} = require('electron');
ipcRenderer.on('message', function(event, text) {
var container = document.getElementById('messages');
var message = document.createElement('div');
message.innerHTML = text;
container.appendChild(message);
})
</script>
</body>
</html>
@hz0324

This comment has been minimized.

hz0324 commented Oct 20, 2017

Hi, I am following your code exactly as it is.
The app starts the downloading process, but it doesn't start the installation after closing itself.
No error information at all. Please help.
What should I do?

Thanks.

I am running this code on Windows 10.

@Nirupg63

This comment has been minimized.

Nirupg63 commented Nov 6, 2017

@hz0324
I had the same problem as well. Running the app as admin allowed the previously installed app to update but doesn't re-open it after updating.

@geek4teck

This comment has been minimized.

geek4teck commented Nov 25, 2017

I too had the same problem, but it got fixed, the major reason is lack of permission for the new version to install. If you check the logs (in Windows

C:\Users<Username>\AppData\Roaming<App Name>\log.log

file), you can find where the exact problem is.

Another reason could be code signing, when you were installing 1.0.0 (First Version) if you see Windows not allowing you to install and considering it insecure, then during silent update the new version won't install as windows will not allow permission to the app.

Hope this helps

@SimplyAhmazing

This comment has been minimized.

SimplyAhmazing commented May 15, 2018

How can I pass custom request params to the generic server? Whether via request headers or URL parameters?

@Stogoh

This comment has been minimized.

Stogoh commented May 29, 2018

It says, that the provider is not supported. But I have it defined in the package.json file, what could be the problem?

@Tony607

This comment has been minimized.

Tony607 commented Aug 29, 2018

In Windows, run installed older version app as admin before attempting an auto update.

@stupidArnob

This comment has been minimized.

stupidArnob commented Sep 14, 2018

just change the Electron and builder version it will worked

@flashpointsrl

This comment has been minimized.

flashpointsrl commented Sep 21, 2018

I've some doubts.
If I put the releases in the folder http://127.0.0.1:8080/releases which are the requirements for the server?
In the folder "releases" do I have to put all the releases or only the last one?
How does the electron app know which one to download?

@TinyChou

This comment has been minimized.

TinyChou commented Sep 25, 2018

I've some doubts.
If I put the releases in the folder http://127.0.0.1:8080/releases which are the requirements for the server?
In the folder "releases" do I have to put all the releases or only the last one?
How does the electron app know which one to download?

Hi guys, you can see the lastest app is configured in the json files after build cmd exec.

like this:

{
  "version": "1.0.0",
  "releaseDate": "2018-09-25T06:39:42.341Z",
  "url": "http://127.0.0.1:8080/ElectornUpdaterDemo-1.0.0-mac.zip"
}
@mh90gh

This comment has been minimized.

mh90gh commented Oct 11, 2018

I have the autoupdate functionality working, but can't seem to get differential updates working. I am using nsis not nsis-web, but I saw some notes saying that should work now. Has anyone else successfully got this working?

@jneb92jneb92

This comment has been minimized.

jneb92jneb92 commented Oct 18, 2018

Hi !
I don't really get how the autoUpdater object will know which file to open. For instance, if you build for windows, linux and mac and copy paste into your webserver a .zip for mac, .AppImage for linux and an .exe for windows => how will the autoUpdater know which file he is suppose to take ?
Shouldn't we specify the file name instead of just specifying the folder in package.json ?

"linux": {
      "category": "Graphics",
      "publish": [{
        "provider": "generic",
        "url": "https://static.site-example.io/appli//linux/appli.AppImage"
      }]
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment