Electron autoUpdater實(shí)現(xiàn)Windows安裝包自動(dòng)更新的方法
前言
Electron幫助我們突破瀏覽器的界限,通過Electron構(gòu)建的桌面應(yīng)用擁有各種瀏覽器應(yīng)用夢(mèng)寐以求的能力。
Electron提供的autoUpdater還可以幫助我們實(shí)現(xiàn)桌面應(yīng)用的自動(dòng)更新。
文件結(jié)構(gòu)
首先,我們已經(jīng)有了一個(gè)基于Electron做的應(yīng)用,項(xiàng)目中有兩個(gè)package.json。這樣做的一個(gè)原因是將devDependencies和dependencies分開了,另外就是不需要在打包的時(shí)候再去指定哪些依賴不需要一起打到安裝包里面去了(通過ignore參數(shù))。
目錄結(jié)構(gòu)類似于這樣:
myapp -node_modules -package.json -app -js -css -index.html -main.js -package.json
外面的package.json內(nèi)容類似于:
{ "name": "myapp", "main": "app/main.js", "scripts": { "start": "electron ." }, "devDependencies": { "electron-prebuilt": "^1.2.7" } }
里面的package.json的內(nèi)容類似于:
{ "name": "myapp", "version": "1.0", "main": "main.js", "description": "my app", "scripts": { "start": "electron ." }, "dependencies": {} }
注意里面的package.json中的name,version,description是必填的,接下來打包會(huì)用到。
electron-squirrel-startup
為了使最后的安裝包能夠?qū)崿F(xiàn)自動(dòng)更新,我們需要對(duì)現(xiàn)有的應(yīng)用做一些改動(dòng),使它可以處理一些啟動(dòng)或者安裝時(shí)的事件。
我們可以在main.js里面加入一些處理的代碼或者方便起見,我們可以直接使用electron-squirrel-startup。
先安裝:
npm install electron-squirrel-startup --save
因?yàn)樾枰趍ain.js里面用到,我們需要將其安裝在app里面。
在main.js里面使用它,第一行加入如下代碼即可:
if (require('electron-squirrel-startup')) return;
有興趣的童鞋可以一起跟我去看看electron-squirrel-startup做了什么事情,急著打包的童鞋可以直接忽略這一段:
在myapp/app/node_modules/electron-squirrel-startup下面有一個(gè)index.js:
var path = require('path'); var spawn = require('child_process').spawn; var debug = require('debug')('electron-squirrel-startup'); var app = require('electron').app; var run = function(args, done) { var updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe'); debug('Spawning `%s` with args `%s`', updateExe, args); spawn(updateExe, args, { detached: true }).on('close', done); }; var check = function() { if (process.platform === 'win32') { var cmd = process.argv[1]; debug('processing squirrel command `%s`', cmd); var target = path.basename(process.execPath); if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') { run(['--createShortcut=' + target + ''], app.quit); return true; } if (cmd === '--squirrel-uninstall') { run(['--removeShortcut=' + target + ''], app.quit); return true; } if (cmd === '--squirrel-obsolete') { app.quit(); return true; } } return false; }; module.exports = check();
它的代碼只有短短幾十行,做的事情也很簡(jiǎn)單,注意返回值為true的那幾行,基本上來說就是安裝時(shí),更新完成時(shí),卸載時(shí) main.js都會(huì)被調(diào)用,我們需要根據(jù)不同的情況做不同的事情,完成這些事情后不要啟動(dòng)應(yīng)用(會(huì)出錯(cuò)),直接退出就好。
正常啟動(dòng)前我們需要去檢測(cè)是否有新的安裝包,之后下載新包,重新安裝,重啟應(yīng)用,為了做到這一點(diǎn),我們需要在main.js里面加入如下代碼:
app.on('ready', () => { //安裝后第一次啟動(dòng)不去檢測(cè)更新,go做的事情就是啟動(dòng)我們的應(yīng)用 if (process.argv[1] == '--squirrel-firstrun') { go(); return; } /* 設(shè)置自動(dòng)更新的feedURL,本地測(cè)試可以設(shè)置為類似于http://127.0.0.1:8080/latest * 在latest文件夾下放著三個(gè)我們的安裝文件(Setup.exe,RELEASES,myapp-1.0-full.nupkg),下面會(huì)講到 * / autoUpdater.setFeedURL(feedURL); autoUpdater.on('update-downloaded', function() { // 下載完成,更新前端顯示 autoUpdater.quitAndInstall(); }); try { // 不是安裝應(yīng)用的情況下啟動(dòng)下回出錯(cuò),此時(shí)直接正常啟動(dòng)應(yīng)用 autoUpdater.checkForUpdates(); } catch (ex) { go(); return; } // createWindow是我們自己定義的方法,用來創(chuàng)建窗口,此處用來創(chuàng)建檢測(cè)更新的窗口 createWindow({ name: 'updateWindow', url: 'check-for-updates.html', title: "checkForUpdates", icon: icon, frame: false, width: 1306, height: 750 }); });
自動(dòng)更新后臺(tái)搭建
var express = require('express'); var app = express(); app.use(express.static('releases')); var server = app.listen(8080, function() { var host = server.address().address var port = server.address().port console.log("應(yīng)用實(shí)例,訪問地址為 http://%s:%s", host, port); });
文件結(jié)構(gòu)如下:
autoupdate-backend -package.json -index.js -node_modules -releases -latest
此時(shí)latest文件夾里面還是空的,之后我們開始打包,將打包出來的三個(gè)文件放在此處即可。
electron-packager
在myapp下安裝:
npm install electron-packager --save-dev npm install electron-packager -g
兩種安裝方式對(duì)應(yīng)兩種使用方式,第一種在腳本中使用,第二種的命令行使用。
腳本中使用,小姐姐在這里借助了gulp,所以需要安裝gulp:
npm install gulp --save-dev npm install gulp -g
新建GulpFile.js,定義一個(gè)task:
var gulp = require('gulp'); var platform = 'win32'; var arch = 'ia32'; var appPath = 'app'; var packageOutPath = 'production/package'; var iconPath = 'app/favicon.ico'; gulp.task('generate-package', () => { generatePackage(); }); function generatePackage(callback) { var packager = require('electron-packager') packager({ dir: appPath, platform: platform, arch: arch, out: packageOutPath, icon: iconPath, /*桌面快捷方式名稱以及開始菜單文件夾名稱*/ 'version-string': { CompanyName: 'MyCompany Inc.', ProductName: 'myapp' } }, function (err) { if (err) { console.log(err); } else { callback && callback(); } }); }
需要打包的時(shí)候,打開命令行:
gulp generate-package
這樣做的好處是調(diào)用方便,當(dāng)然我們也可以直接通過命令行調(diào)用electron-packager,前提是我們?nèi)职惭b了它或者將其安裝目錄添加到了環(huán)境變量中:
更多參數(shù)一一加上即可。
貼上官方文檔鏈接:
github鏈接:https://github.com/electron-userland/electron-packager
下面兩個(gè)鏈接在上面的文檔里面都能找到,但是個(gè)人感覺比較常用,還是貼出來:
參數(shù)使用:https://github.com/electron-userland/electron-packager/blob/master/usage.txt
腳本使用:https://github.com/electron-userland/electron-packager/blob/master/docs/api.md
打包
myapp下安裝electron-winstaller:
npm install electron-winstaller --save-dev
還是在gulp里面添加一個(gè)task,連同package的代碼一起貼上:
var gulp = require('gulp'); var platform = 'win32'; var arch = 'ia32'; var appPath = 'app'; var outName = 'myapp-win32-' + arch; var packageOutPath = 'production/package'; var installerOutPath = 'production/installer'; var packagePath = `${packageOutPath}/${outName}`; var installerPath = `${installerOutPath}/${outName}`; var iconPath = 'app/favicon.ico'; var gifPath = 'loading.gif'; gulp.task('generate-package', () => { generatePackage(); }); gulp.task('generate-installer', () => { isDirExist(packagePath, (exist) => { if (exist) { generateInstaller(); } else { generatePackage(() => { generateInstaller(); }); } }); }); function isDirExist(path, callback) { fs.readdir(path, (err) => { callback && callback(!err); }); } function generatePackage(callback) { var packager = require('electron-packager') packager({ dir: appPath, platform: platform, arch: arch, out: packageOutPath, icon: iconPath, /*桌面快捷方式名稱以及開始菜單文件夾名稱*/ 'version-string': { CompanyName: 'MyCompany Inc.', ProductName: 'myapp' } }, function (err) { if (err) { console.log(err); } else { callback && callback(); } }); } function generateInstaller() { var electronInstaller = require('electron-winstaller'); electronInstaller.createWindowsInstaller({ appDirectory: packagePath, outputDirectory: installerPath, loadingGif: gifPath, authors: 'ganyouyin', exe: 'myapp.exe', title: 'My APP', iconUrl: `${__dirname}/${iconPath}`, setupIcon: iconPath, setupExe: 'Setup.exe', noMsi: true }).then(() => console.log("It worked!"), (e) => console.log(`No dice: ${e.message}`)); }
之后執(zhí)行任務(wù):
gulp generate-installer
第一次會(huì)非常慢,但是執(zhí)行完成后我們的安裝包就出來了。
此時(shí)我們的文件結(jié)構(gòu)是:
myapp -GulpFile.js -package.json -node_modules -app -production -package -myapp-win32-ia32 - 各種文件,包含一個(gè)myapp.exe,雙擊可以直接運(yùn)行 -installer -myapp-win32-ia32 -Setup.exe -RELEASES -myapp-1.0-full.nupkg
有了三個(gè)文件,將他們粘到之前的autoupdate-backend/releases/latest文件夾下面。
測(cè)試
- 啟動(dòng)我們的自動(dòng)更新后臺(tái);
- 將myapp/app下的package.json里面的version改為1.1,再次打包;
- 將之前的autoupdate-backend中的latest文件夾重命名為1.0;
- 新建文件夾latest,將新打包產(chǎn)生的三個(gè)文件粘進(jìn)去;
- 雙擊1.0里面的Setup.exe安裝應(yīng)用;
- 關(guān)閉應(yīng)用,雙擊桌面上的快捷方式myapp.exe再次打開應(yīng)用;
不出意外此時(shí)就會(huì)去進(jìn)行自動(dòng)更新的操作,結(jié)束后自動(dòng)重啟,再次打開時(shí)已經(jīng)是1.1的應(yīng)用。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C#開發(fā)windows服務(wù)實(shí)現(xiàn)自動(dòng)從FTP服務(wù)器下載文件
- Windows下支持自動(dòng)更新的Electron應(yīng)用腳手架的方法
- windows長(zhǎng)時(shí)間保持遠(yuǎn)程桌面不被自動(dòng)斷開
- 在Windows環(huán)境下使用MySQL:實(shí)現(xiàn)自動(dòng)定時(shí)備份
- windows mysql 自動(dòng)備份的幾種方法匯總
- 在Windows下自動(dòng)備份PostgreSQL的教程
- Windows系統(tǒng)自動(dòng)連接網(wǎng)絡(luò)共享打印機(jī)BAT腳本分享
- windows10徹底關(guān)閉自動(dòng)更新【絕對(duì)可行】
相關(guān)文章
給easyui datebox擴(kuò)展一個(gè)清空的實(shí)例
下面小編就為大家?guī)硪黄oeasyui datebox擴(kuò)展一個(gè)清空按鈕的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11js實(shí)現(xiàn)類似jquery里animate動(dòng)畫效果的方法
這篇文章主要介紹了js實(shí)現(xiàn)類似jquery里animate動(dòng)畫效果的方法,實(shí)例分析了javascript模擬實(shí)現(xiàn)jQuery中animate動(dòng)畫效果的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04全面了解javascript中的錯(cuò)誤處理機(jī)制
下面小編就為大家?guī)硪黄媪私鈐avascript中的錯(cuò)誤處理機(jī)制。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-07-07JS實(shí)現(xiàn)簡(jiǎn)單獲取最近7天和最近3天日期的方法
這篇文章主要介紹了JS實(shí)現(xiàn)簡(jiǎn)單獲取最近7天和最近3天日期的方法,涉及javascript針對(duì)日期與時(shí)間的相關(guān)數(shù)值運(yùn)算與轉(zhuǎn)換操作技巧,需要的朋友可以參考下2018-04-04IE11下CKEditor在Bootstrap Modal中下拉問題的解決
這篇文章主要介紹了IE11下CKEditor在Bootstrap Modal中下拉問題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09JavaScript 繼承 封裝 多態(tài)實(shí)現(xiàn)及原理詳解
這篇文章主要介紹了JavaScript 繼承 封裝 多態(tài)實(shí)現(xiàn)及原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07