自己動手開發更好用的markdown編輯器-06(自動更新)


這里文章都是從個人的github博客直接復制過來的,排版可能有點亂. 原始地址  http://benq.im/2015/05/12/hexomd-06/
 
文章目錄
  1. 1. 自動更新方案
  2. 2. 實現
    1. 2.1. 安裝依賴模塊
    2. 2.2. 自定義package.json
    3. 2.3. updater.js
    4. 2.4. 綁定更新按鈕
  3. 3. 總結
  4. 4. 附件

上一篇我們實現了粘貼上傳圖片功能.

今天將實現自動更新的功能,有了這個功能以后我再發博客就不需要每次都把最新的程序重新打包上傳了.

對於不想看如何實現的朋友,直接下載打包好的程序就行,以后更新可以點擊軟件右上角的第一個按鈕即可(手動).

自動更新方案

在做上一個軟件Gungnir的時候,為了可以顯示更新進度,自動更新的方案是列出所有需要更新的文件,然后自動下載每個文件並覆蓋,但是在需要更新一些node模塊(文件一般都很多)時就相當麻煩了,有一個文件傳輸失敗就會導致更新出錯.實現起來相當麻煩,而且也並不能帶來什么優勢.

所以做這個軟件的自動更新的時候,我用了更為簡單粗暴的方案:將需要更新的文件打包成zip文件,直接下載並解壓覆蓋即可.

實現

自動更新作為較單獨的功能模塊,我把全部代碼放在modules/updater.js,這里就不把全部代碼貼出來了,需要的自己點鏈接看,里面有注釋. 我只講一些實現細節.

安裝依賴模塊

首先是安裝兩個新增了的node模塊依賴whenbufferhelper,第一個是promise模塊,第二個看名字就知道,無須解釋.

1
npm install when --save

 

1
npm install bufferhelper --save

7z.exe放到軟件根目錄備用

自定義package.json

增加了updater配置節點,配置最新的版本號version和對應的補丁文件地址package,由於我這個軟件功能很少,代碼並不多,因此我現在每次更新都是包含之前所有補丁的文件打包,加起來也才1m多,這樣實現比較簡單,只要下載最新的包即可.

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個方法

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 = {
//下載指定url的內容並返回promise對象
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) {
//是否經過gzip壓縮
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)) {
//如果update目錄不存在則創建
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>

總結

基本的自動更新的功能比圖片上傳更為簡單,但是今天做的這個功能還有很多細節問題,比如:

  1. 無法自動刪除新版本不需要的文件
  2. 以后如果程序大了,更新補丁每次都全量打包會導致更新很慢
  3. 更新后不會自動重啟軟件.
  4. 更好的方案是自動根據git的提交信息生成更新列表,並且根據版本號管理.

接下來的計划:

  1. 雲同步.
  2. 插件機制
  3. 表情插件.

附件

本篇程序打包.
項目地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM