我們把自己開發的Electron應用發布之前,需要把app打包成簡單的安裝包,這樣app更容易被獲取,以此來發布我們的應用。我們可以參考Wix或其他的安裝程序,但是對於Electron應用更好的打包程序是Squirrel。畢竟某些著名的Visual Studio Code 和Slack 的客戶端應用就是用這個框架來打包和更新的。現在我來告訴你怎么創建一個基於Electron的windows應用。
Electron 和 squirrel 的更新非常快,我們可以到
http://electron.atom.io/docs/v0.36.8/api/auto-updater/ 和 https://github.com/atom/grunt-electron-installer
獲取更多完成以下任務的信息。
設置階段
如果你是一個Electron新玩家,看看我之前的文章《Electron入門》
在項目根目錄
創建一個Staging文件夾,用來存放創建發布應用的工具和文件。接着,在這里下載squirrel.windows二進制文件https://github.com/Squirrel/Squirrel.Windows/releases,在這篇文章中,Squirrel.Windows 1.0 Preview 2 是當前版本,如果版本有更新,可能需要調整一些步驟。復制文件然后放到剛才創建的Staging文件夾里面,最后文件夾結構如下。
充分准備完我們就可以開始了!
在Eletron 中處理 squirrel 事件
如果你看一下 eletron.exe里面的版本信息,你可以在版本信息里面看到一個設置版本標志,標明可執行的 squirrel 版本。
這個可執行文件,在 electron 安裝,更新,卸載,刪除的時候通知 squirrel 怎么處理這些squirrel 事件 。事實上squirrel 並沒有很好的參考文檔,我花了一段時間才理解Windows的參考文檔,但是有了這個版本標志,就可以傳遞任務信息比如給app創建快捷方式,通過這個來更改squirrel的默認行為。
當squirrel 運行的時候,就會執行 “Squirrel Aware”可執行文件,去監聽 傳遞過來的作為事件標志的參數。這些事件參數必須在程序的入口就被處理,然后立即結束程序。就是說,在electron應用中,我們需要更改main.js這個文件來處理這些事件。在main.js的開頭,其他代碼調用之前,添加這段代碼:
var app = require('app');
var path = require('path');
var cp = require('child_process');
var handleSquirrelEvent = function() {
if (process.platform != 'win32') {
return false;
}
function executeSquirrelCommand(args, done) {
var updateDotExe = path.resolve(path.dirname(process.execPath),
'..', 'update.exe');
var child = cp.spawn(updateDotExe, args, { detached: true });
child.on('close', function(code) {
done();
});
};
function install(done) {
var target = path.basename(process.execPath);
executeSquirrelCommand(["--createShortcut", target], done);
};
function uninstall(done) {
var target = path.basename(process.execPath);
executeSquirrelCommand(["--removeShortcut", target], done);
};
var squirrelEvent = process.argv[1];
switch (squirrelEvent) {
case '--squirrel-install':
install(app.quit);
return true;
case '--squirrel-updated':
install(app.quit);
return true;
case '--squirrel-obsolete':
app.quit();
return true;
case '--squirrel-uninstall':
uninstall(app.quit);
return true;
}
return false;
};
if (handleSquirrelEvent()) {
return;
}
以上這段代碼,用來在安裝和更新時給執行文件添加快捷方式,並且在刪除和卸載應用的時候自動刪除快捷方式。Squirrel 的更新執行程序Update.exe會執行這些操作,也可以在這里給其他的事件添加快捷方式,比如,Visual Studio Code添加了注冊表值,當你右鍵單擊一個文件時,可以選擇用Visual Studio Code打開。
Electron 介紹
更新:請仔細閱讀這個部分,雖然這里很多內容都可以用electron-packager 包來完成。看我的簡短文章 《使用Electron-Packager來打包Electron App》 然后再回到這篇文章中。需要注意之后在這個文章中,你需要調整 .nuspec 這個文件里面<file>標簽,把路徑正確地指到 你的electron包。
如果你用默認的electron.exe安裝自己的app,app的快捷方式和來源信息就跟之前下載的Electron開發包一樣。其實需要更改app名字和來源說明,以此來聲明這是我們自己的app。同時Squirrel也使用這些資源去創建快捷方式。查看這里的文檔獲取更多關於Squirrel命名規則的相關信息。
如果你想修改執行文件的話,到這個目錄
<project_folder>/node_modules/electron-prebuilt/dist/electron.exe 把文件復制黏貼到相同目錄並且重命名 yourapp.exe就ok。
在打包過程中,credit.exe和squirrel可以同時使用,credit.exe用來更改可執行文件的icon和版本信息。我發現跟着我這篇文章的方向走,使用Resource Hacker,會比較容易一些:《如果更改.exe文件的icon》。如果你需要一個.ico 的icon文件來測試的話可以用以下這個免費的資源。
http://www.wangjiewen.com/setup.ico
當你編輯icon和版本信息的時候,對squirrel安裝程序來說這個非常重要,在Resource Hacker保存更改后,它會創建一個 <your_app_ame>_original.exe。如果你想在相同的目錄中使用electron.exe,就刪除<your_app_ame>_original.exe這個文件。注意:如果進行這些更改,windows資源管理器可能不會把當前這個icon關聯到你新的exe,這沒關系,別慌。
創建Nuget 包
正如上述, Squirrel.Windows就是用nuget構建的。我們需要把文件打包成一個Nuget 包,然后使用squirrel 來創建一個安裝文件。先在項目根目錄里面放一個nuget.exe,通過命令行進入該目錄,執行以下命令:
nuget spec
之后會創建一個默認配置的Package.nuspec文件,在編輯器中打開這個文件進行編輯,像這樣:
<?xml version="1.0"?>
<package >
<metadata>
<id>Package</id>
<version>1.0.0</version>
<authors>Administrator</authors>
<owners>Administrator</owners>
<licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
<projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
<iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Package description</description>
<releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>Tag1 Tag2</tags>
<dependencies>
<dependency id="SampleDependency" version="1.0" />
</dependencies>
</metadata>
</package>
點擊 nuspec reference 查看更多關於創建Package.nuspec的信息。
注意
1. 根據Squirrel文檔說明,target folder 屬性需要設置為lib/net45,否則並沒有用。
2. 再三確認<dependencies> 標簽里面沒有依賴。
3. 更多注意事項查看文檔:
https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/getting-started.md
4. <description> 標簽和<iconUrl>標簽用來在windows上注冊應用,當安裝,刪除,或者卸載應用的時候,會出現在windows的對話框上。
5. 我們能成功執行electron.exe ,是因為這個可執行文件就在dist 目錄下面。如果放在其他地方,記得把文件路徑加到file標簽上。
6. 如果node_modules目錄不在app目錄里面,也要添加進去。
接着,用下面的命令創建一個nuget包。
nuget pack Package.nuspec
之后在根目錄會出現這個nuget包<my_app_name>.<version>.nupkg。
創建安裝程序
把應用程序打包成nuget包之后,就可以用squirrel創建一個安裝程序了。在根目錄打開命令行,執行以下命令:
squirrel --releasify <my_app_name>.<version>.nupkg
編譯一段時間后程序會創建一個Release文件夾,里面有三個文件,nuget包,RELEASES 文件和安裝文件Setup.exe。把這三個文件發送給想要安裝這個應用的用戶就可以了。注意上面這條命令,也可以用來設置setup.exe在安裝過程中用傳統icon還是用自定義的圖片文件。
在本地機器執行setup.exe,Squirrel 在啟動app之后會快速執行,並在桌上和開始菜單欄中創建好快捷方式。應用會被安裝在C:\Users\Administrator\AppData\Local\文件夾中,注意Squirrel 的日志文件也存在目錄中,調試安裝問題的時候非常有用。
如果要卸載這個應用,可以利用Windows “程序和功能”的對話窗口來卸載,這樣確保添加在開始菜單和桌面的快捷方式得以移除。
更新
現在用戶可以使用你的安裝程序來安裝文件了,有了Squirrel 會讓更新應用這件事情變得很簡單。跟隨下面的步驟來創建一個更新程序:
1.把之前用來創建安裝包的文件夾復制一份,打開。
2.更改Package.nuspec這個文件,在<version>標簽中把版本數字提高到當前匹配的版本。同時也應該考慮同時更新可執行文件的版本信息。
3.回到命令行創建 .nupkg 包
4.在用 nupkg 包 創建一個新的安裝文件
5.將發布文件夾里面的內容分發給用戶
最終沒用的舊版本的包會被刪除,同時不需要發布舊的nuget包,發布setup.exe,RELEASES文件和最新的nuget包就好了。當執行新的exe時,舊的應用文件會被替換,我猜想使用這種更新方法來發布新版本應用,會比直接安裝一個新版本更快。
自動更新
上面的方法是通過發布setup文件來更新應用的。但是,我們可以設置的app,讓squirrel在后台執行更新程序,打開main.js,將下列代碼寫入,用來監聽squirrel事件。
var updateDotExe = path.resolve(path.dirname(process.execPath),
'..', 'update.exe');
var child = cp.spawn(updateDotExe,
["--update", "http://mywebsite.com/releases"], { detached: true });
child.on('close', function(code) {
// anything you need to do when update is done.
});
使用上面的代碼,如果Squirrel 在更新url中發現更新,就會自動在后台下載更新,安裝。下一次啟動應用的時候,就是最新的版本。這肯定比加一個“檢查更新”按鈕要好,或者彈出一個提示框讓用戶來決定是否更新。以下是一個如何在主線程運行自動更新程序的例子。
var dialog = require('dialog');
var updateDotExe = path.resolve(path.dirname(process.execPath),
'..', 'update.exe');
var child = cp.spawn(updateDotExe, ["--download", "http://mywebsite.com/releases"], { detached: true });
var stdout = '';
child.stdout.setEncoding('utf8');
var jsonStarted = false;
child.stdout.on('data', function (d) {
if (!jsonStarted && d.startsWith("{")) {
jsonStarted = true;
return stdout += d;
}
if (!jsonStarted) {
return;
}
return stdout += d;
});
child.on('close', function(code) {
if (stdout.length > 0) {
var data = JSON.parse(stdout);
dialog.showMessageBox({ message: "Update to version " + data.futureVersion + "?",
buttons: ["Update", "Not Now"] }, function (choice) {
if (choice === 0) {
var child = cp.spawn(updateDotExe, ["--update", "http://mywebsite.com/releases"], { detached: true });
dialog.showMessageBox({ message: "The update should be available next time you start the application.",
buttons: ["Awesome"] });
}
});
}
});
當然可能你想要運行安裝程序然后自動重啟應用,不得不說這是一個簡單的例子。
附加資源
我一直存在一些疑問,關於怎么使用squirrel是怎么去更新一個app的。最難的部分在這篇文章中已經為你解答,但是看一下windows 參考文檔,會更完整。
這里: https://github.com/Squirrel/Squirrel.Windows/tree/master/docs
這里有一個更好的關於squirrel創建.net應用的視頻,
http://channel9.msdn.com/Events/dotnetConf/2015/Squirrel-for-Windows-installing-NET-apps-the-way-it-should-be
有一些關於electron app的概念 探討,比如有人提出使用 Squirrel.Windows 來創建基於Electron的Slack 應用。
如果你正在用grunt 這里有一個工具
https://github.com/atom/grunt-electron-installer 用來給 electron app創建squirrel安裝包。這個我沒有試過,但是我猜比本文中一步一步來做的方法要好。