這裏文章都是從我的的github博客直接複製過來的,排版可能有點亂. 原始地址
http://benq.im/2015/05/12/hexomd-06/
上一篇咱們實現了粘貼上傳圖片
功能.javascript
今天將實現自動更新
的功能,有了這個功能之後我再發博客就不須要每次都把最新的程序從新打包上傳了.html
對於不想看如何實現的朋友,直接下載打包好的程序就行,之後更新能夠點擊軟件右上角的第一個按鈕便可(手動).
java
自動更新方案
在作上一個軟件Gungnir的時候,爲了能夠顯示更新進度,自動更新的方案是列出全部須要更新的文件,而後自動下載每一個文件並覆蓋,可是在須要更新一些node模塊(文件通常都不少)時就至關麻煩了,有一個文件傳輸失敗就會致使更新出錯.實現起來至關麻煩,並且也並不能帶來什麼優點.node
因此作這個軟件的自動更新的時候,我用了更爲簡單粗暴的方案:將須要更新的文件打包成zip文件,直接下載並解壓覆蓋便可.git
實現
自動更新做爲較單獨的功能模塊,我把所有代碼放在modules/updater.js,這裏就不把所有代碼貼出來了,須要的本身點連接看,裏面有註釋. 我只講一些實現細節.github
安裝依賴模塊
首先是安裝兩個新增了的node模塊依賴when
和bufferhelper
,第一個是promise
模塊,第二個看名字就知道,無須解釋.npm
1 |
npm install bufferhelper |
將7z.exe
放到軟件根目錄備用
json
增長了updater配置節點,配置最新的版本號version
和對應的補丁文件地址package
,因爲我這個軟件功能不多,代碼並很少,所以我如今每次更新都是包含以前全部補丁的文件打包,加起來也才1m多,這樣實現比較簡單,只要下載最新的包便可.promise
1 2 3 4 5 |
... "updater":{ "version":"0.6.0.1", "package":"http://7xit5q.com1.z0.glb.clouddn.com/update.zip" } |
updater.js
updater.js
裏實現了hmd.updater
模塊,包含4個方法hexo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
var packageFile = 'https://raw.githubusercontent.com/benqy/hexomd/master/package.json',
execPath = require('path').dirname(process.execPath),
updatePath = execPath + '\\update', fs = require('fs'), util = require('./helpers/util'), when = require('./node_modules/when'); var checkUpdateTimer; hmd.updater = { get: function (url) { ... }, checkUpdate: function () { ... }, update:function(packageUrl){ ... }, install: function () { ... } }; |
更新的流程爲 : checkUpdate
檢查是否有更新 > update
下載補丁包 > install
安裝補丁包
get
方法裏要注意的是下載下來的內容要判斷是否通過GZIP
壓縮,若是是,則要用node自帶的zlib
解壓.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
... req = protocolModule.get(urlOpt, function (res) { var isGzip = !!res.headers['content-encoding'] && !!~res.headers['content-encoding'].indexOf('gzip'); ... if (isGzip) { require('zlib').unzip(buffer, function (err, buffer) { gzipDeferred.resolve(buffer); }); } else { gzipDeferred.resolve(buffer); } ... return deferred.promise; |
checkUpdate
方法裏先下載線上的package.json
文件與本地進行比較,若是版本號不一致,則提示用戶更新.若是用戶選擇更新,則下載package.json到本地,而後調用update
方法下載補丁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
checkUpdate: function () { hmd.msg('===正在檢查更新==='); checkUpdateTimer =setTimeout(function(){ hmd.msg('===更新失敗,可能github被牆了===', hmd.MSG_LEVEL.error); }, 10000); var locPackage = require('nw.gui').App.manifest; hmd.updater.get(packageFile) .then(function (packageData) { clearTimeout(checkUpdateTimer); packageData.text = packageData.buffer.toString(); if (!packageData.text) return; var remotePackage = JSON.parse(packageData.text); if (remotePackage.updater.version != locPackage.updater.version){ if (confirm('是否更新到最新版本:' + remotePackage.updater.version)) { if (!fs.existsSync(updatePath)) { util.mkdir(updatePath, true); } fs.writeFileSync(updatePath + '\\package.json', packageData.buffer); hmd.updater.update(remotePackage.updater.package); } } else { hmd.msg('當前版本:' + remotePackage.updater.version + ',已是最新版'); } }); } |
update
方法下載補丁包到update
目錄,而後調用install
安裝補丁
1 2 3 4 5 6 7 8 |
update:function(packageUrl){ hmd.msg('===正在下載更新文件===', hmd.MSG_LEVEL.warnings); hmd.updater.get(packageUrl + '?' + new Date() * 1) .then(function (data) { fs.writeFileSync(updatePath + '\\update.zip',data.buffer); hmd.updater.install(); }); }, |
install
將補丁包經過7z.exe
解壓覆蓋到程序目錄,而後提示用戶重啓軟件.
1 2 3 4 5 6 7 8 9 |
install: function () { require("child_process").exec('xcopy "' + updatePath + '\\package.json" "' + execPath + '\\package.json" /s /e /y'); var unzip = execPath + '\\7z.exe x '+ updatePath +'\\update.zip -y'; require("child_process").exec(unzip,function(){ hmd.msg('===更新完成,重啓後生效==='); }); } |
這裏我直接用7z.exe,反正也不大,也可使用一些開源的node壓縮模塊.
綁定更新按鈕
更新模塊完成了,如今將功能綁定到按鈕上.
先在modules/directives增長新的directivehmdUpdate
1 2 3 4 5 6 7 8 |
angular.module('hmd.directives', []) .directive('hmdUpdate', [function () { return function (scope, elem) { $(elem[0]).on('click', function () { hmd.updater.checkUpdate(); }); }; }]) |
而後將index.html上的更新按鈕與directive綁定
1 |
<a class="btn rectbtn" href="javascript://" title="點擊檢查更新" hmd-update>...</a> |
別忘了引用updater.js
1 2 3 |
<script src="modules/app.js"></script> <script src="modules/updater.js"></script> <script src="modules/directives.js"></script> |
總結
基本的自動更新的功能比圖片上傳更爲簡單,可是今天作的這個功能還有不少細節問題,好比:
- 沒法自動刪除新版本不須要的文件
- 之後若是程序大了,更新補丁每次都全量打包會致使更新很慢
- 更新後不會自動重啓軟件.
- 更好的方案是自動根據git的提交信息生成更新列表,而且根據版本號管理.
![](http://static.javashuo.com/static/loading.gif)
接下來的計劃:
- 雲同步.
- 插件機制
- 表情插件.
附件
本篇程序打包.
項目地址