Skip to content

Instantly share code, notes, and snippets.

@iffy
Last active August 15, 2024 09:27
Show Gist options
  • Save iffy/0ff845e8e3f59dbe7eaf2bf24443f104 to your computer and use it in GitHub Desktop.
Save iffy/0ff845e8e3f59dbe7eaf2bf24443f104 to your computer and use it in GitHub Desktop.
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>
@oliexe
Copy link

oliexe commented Jan 7, 2021

@brennomarques

Appreciate the sample app, everything works perfectly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment