乐闻世界logo
搜索文章和话题

Implementation of Electron Auto-Update Mechanism

2月18日 10:36

Auto-update is an important feature for desktop applications, allowing users to get the latest features and fixes. Electron provides multiple auto-update solutions. This article will detail how to implement auto-update.

electron-updater Basics

electron-updater is the most commonly used Electron auto-update solution.

Installation

bash
npm install electron-updater

Basic Configuration

javascript
// main.js const { app, BrowserWindow } = require('electron') const { autoUpdater } = require('electron-updater') let mainWindow app.whenReady().then(() => { createWindow() // Check for updates autoUpdater.checkForUpdatesAndNotify() }) function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600 }) mainWindow.loadFile('index.html') }

Configuring Update Server

1. GitHub Releases (Recommended)

json
// package.json { "build": { "publish": { "provider": "github", "owner": "your-username", "repo": "your-repo" } } }
javascript
// main.js autoUpdater.setFeedURL({ provider: 'github', owner: 'your-username', repo: 'your-repo' })

2. Custom Server

javascript
// main.js autoUpdater.setFeedURL({ url: 'https://your-server.com/updates', headers: { 'Authorization': 'Bearer your-token' } })

3. S3 Storage

json
// package.json { "build": { "publish": { "provider": "s3", "bucket": "your-bucket-name", "path": 'updates' } } }

Update Event Listeners

javascript
// main.js // Update available autoUpdater.on('update-available', (info) => { console.log('Update available:', info.version) sendStatusToWindow('Update available') }) // Update downloaded autoUpdater.on('update-downloaded', (info) => { console.log('Update downloaded:', info.version) sendStatusToWindow('Update downloaded') // Prompt user to restart app dialog.showMessageBox(mainWindow, { type: 'info', title: 'Update Available', message: 'A new version has been downloaded. Restart the application to apply the update.', buttons: ['Restart', 'Later'] }).then((result) => { if (result.response === 0) { autoUpdater.quitAndInstall() } }) }) // Update not available autoUpdater.on('update-not-available', (info) => { console.log('Update not available') sendStatusToWindow('Update not available') }) // Update error autoUpdater.on('error', (err) => { console.error('Update error:', err) sendStatusToWindow('Update error: ' + err.message) }) // Download progress autoUpdater.on('download-progress', (progressObj) => { let log_message = "Download speed: " + progressObj.bytesPerSecond log_message = log_message + ' - Downloaded ' + progressObj.percent + '%' log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')' sendStatusToWindow(log_message) }) function sendStatusToWindow(text) { mainWindow.webContents.send('update-status', text) }

Renderer Process Handling

javascript
// renderer.js const { ipcRenderer } = require('electron') // Listen for update status ipcRenderer.on('update-status', (event, message) => { console.log('Update status:', message) updateStatusElement.textContent = message }) // Manually check for updates document.getElementById('check-update').addEventListener('click', () => { ipcRenderer.send('check-for-updates') }) // Main process handling ipcMain.on('check-for-updates', () => { autoUpdater.checkForUpdates() })

Advanced Configuration

1. Scheduled Update Checks

javascript
// main.js const CHECK_UPDATE_INTERVAL = 24 * 60 * 60 * 1000 // 24 hours app.whenReady().then(() => { // Check on app startup autoUpdater.checkForUpdatesAndNotify() // Scheduled checks setInterval(() => { autoUpdater.checkForUpdates() }, CHECK_UPDATE_INTERVAL) })

2. Silent Updates

javascript
// main.js autoUpdater.autoDownload = true autoUpdater.autoInstallOnAppQuit = true app.on('before-quit', () => { if (autoUpdater.isUpdateDownloaded()) { autoUpdater.quitAndInstall() } })

3. Custom Update Check

javascript
// main.js async function checkForUpdates() { try { const updateCheckResult = await autoUpdater.checkForUpdates() if (updateCheckResult.updateInfo.version !== app.getVersion()) { // New version available return { hasUpdate: true, version: updateCheckResult.updateInfo.version, releaseNotes: updateCheckResult.updateInfo.releaseNotes } } else { // No new version return { hasUpdate: false } } } catch (error) { console.error('Update check failed:', error) return { hasUpdate: false, error: error.message } } }

Version Management

1. Version Number Format

json
// package.json { "version": "1.0.0" }

Follow Semantic Versioning (SemVer):

  • MAJOR.MINOR.PATCH
  • For example: 1.0.0, 1.2.3, 2.0.0

2. Releasing New Version

bash
# Update version number npm version patch # 1.0.0 -> 1.0.1 npm version minor # 1.0.0 -> 1.1.0 npm version major # 1.0.0 -> 2.0.0 # Build application npm run build # Publish to GitHub git push --follow-tags

3. Release Notes

Add release notes in GitHub Releases:

markdown
## Version 1.1.0 ### New Features - Added feature X - Added feature Y ### Bug Fixes - Fixed bug A - Fixed bug B ### Improvements - Improved performance - Enhanced user experience

Security Considerations

1. Verify Update Packages

javascript
// main.js autoUpdater.on('update-downloaded', (info) => { // Verify update package signature if (verifyUpdateSignature(info)) { autoUpdater.quitAndInstall() } else { console.error('Update signature verification failed') } }) function verifyUpdateSignature(info) { // Implement signature verification logic return true }

2. Use HTTPS

javascript
// main.js autoUpdater.setFeedURL({ url: 'https://your-server.com/updates', headers: { 'Authorization': 'Bearer your-token' } })

3. Limit Update Frequency

javascript
// main.js let lastUpdateCheck = 0 const UPDATE_CHECK_INTERVAL = 24 * 60 * 60 * 1000 // 24 hours async function checkForUpdatesWithRateLimit() { const now = Date.now() if (now - lastUpdateCheck < UPDATE_CHECK_INTERVAL) { console.log('Update check skipped - too soon') return } lastUpdateCheck = now return await autoUpdater.checkForUpdates() }

Error Handling

1. Network Errors

javascript
// main.js autoUpdater.on('error', (err) => { if (err.message.includes('ERR_INTERNET_DISCONNECTED')) { console.error('Network disconnected') sendStatusToWindow('Network disconnected. Please check your internet connection.') } else if (err.message.includes('ERR_CONNECTION_REFUSED')) { console.error('Connection refused') sendStatusToWindow('Cannot connect to update server.') } else { console.error('Update error:', err) sendStatusToWindow('Update failed: ' + err.message) } })

2. Insufficient Disk Space

javascript
// main.js autoUpdater.on('error', (err) => { if (err.message.includes('ENOSPC')) { console.error('No disk space') sendStatusToWindow('Not enough disk space to download update.') } })

Best Practices

1. User Experience

javascript
// main.js // Check for updates when app is idle app.on('ready', () => { setTimeout(() => { autoUpdater.checkForUpdatesAndNotify() }, 5000) // Delay 5 seconds to avoid affecting startup speed }) // Provide update progress feedback autoUpdater.on('download-progress', (progress) => { const percentage = Math.round(progress.percent) sendStatusToWindow(`Downloading update: ${percentage}%`) })

2. Rollback Mechanism

javascript
// main.js // Keep old version const { app } = require('electron') app.on('before-quit', () => { // Backup current version before update const currentVersion = app.getVersion() const backupPath = path.join(app.getPath('userData'), 'backup', currentVersion) // Implement backup logic })

3. Testing Updates

javascript
// Development environment testing if (process.env.NODE_ENV === 'development') { autoUpdater.setFeedURL({ url: 'http://localhost:3000/updates' }) }

Common Questions

Q: How to implement incremental updates?A: electron-updater supports incremental updates by default, just ensure server configuration is correct and use the same release process.

Q: How to retry after update failure?A: Listen to error event and implement retry logic:

javascript
let retryCount = 0 const MAX_RETRIES = 3 autoUpdater.on('error', (err) => { if (retryCount < MAX_RETRIES) { retryCount++ setTimeout(() => { autoUpdater.checkForUpdates() }, 5000 * retryCount) } })

Q: How to skip a specific version?A: Save skipped version in app settings, compare when checking for updates:

javascript
const skippedVersion = getSkippedVersion() if (newVersion !== skippedVersion) { // Show update prompt }

Q: How to migrate user data after update?A: Listen to before-quit event in main process, execute data migration logic before update.

标签:Electron