update.electronjs.orgを使って、アプリの自動更新機能をお気楽に組み込む
- ElectronのautoUpdater
- update.electronjs.org
- 対応している環境
- 更新用のアプリをReleasesに置く
- Electronアプリへの組み込み(自動的に更新処理)
- Electronアプリへの組み込み(任意のタイミングで更新)
- autoUpdaterが間違ったファイルをダウンロードする(1敗)
- 終わり
ElectronのautoUpdater
Electronには、アプリの新しいバージョンをダウンロードして
更新する機能が用意されています。
https://www.electronjs.org/docs/api/auto-updater
Electronアプリからこの機能を使うには本来、
最新版アプリの情報を返すアップデートサーバーが必要になるのですが、
GitHubのReleasesに最新アプリバイナリを置いているアプリ
については、
Electron公式がアップデートサーバーを用意してくれているので、
アプリ側の修正だけで、簡単に自動アップデート機能を組み込めるようになっています。
update.electronjs.org
こちらが公式が用意しているサーバーで、
update.electronjs.org (GitHubにリダイレクト)
このサーバーは、次のパターンのURLを叩くと、GitHubの最新リリースの情報を取得して返します。
https://update.electronjs.org/update/${process.platform}/${app.getVersion()}
例えば、GitHubのレポジトリが"taku-o/myukkurivoice"で、
現在実行中のアプリのバージョンが"0.13.6"だとすれば、次のURLになりますね。
このURLをブラウザで開くと、JSON形式で最新リリースのデータが返ってくるのが分かります。
https://update.electronjs.org/taku-o/myukkurivoice/darwin-x64/0.13.6
{"name":"0.13.7","notes":"- \"MYukkuriVoice について\"ダイアログの表示を修正。\r\n - ビルド時の...
対応している環境
update.electronjs.orgで対応している環境はLinux環境以外です。
Linuxは駄目かー。そっかー、残念ですね。
macOSのアプリについては、アプリにDeveloper ID Applicationの署名が必要。
実行中のアプリ、そして、ダウンロードする更新アプリ、両方に署名が必要です。
(アプリに署名がされていないと、自動アップデートがエラーになる。)
Error: Code signature at URL file:///Users/user/Library/Caches/jp.nanasi.myukkurivoice.ShipIt/update.TdmmDN0/ MYukkuriVoice-darwin-x64/MYukkuriVoice.app/ did not pass validation: コードオブジェクトがまったく署名されていません
Error: Could not get code signature for running application
Catalinaでは、アップル公証(Notarization)も必要かも?
調べていません。
わざわざ公証の実装を外してまで検証しないよ。
面倒だからね。仕方ないね(^_^)/
更新用のアプリをReleasesに置く
更新用のアプリは、zipで固めてGitHubのReleasesに置いておきます。 https://github.com/taku-o/myukkurivoice/releases/tag/0.13.8
1. バージョン番号のReleasesタグを作る(0.13.8 とか) 2. 更新用のアプリをzip形式にしてアップロードする 3. zipファイルのファイル名は、例えば、AppName-darwin-x64.zip のような形式にする
update.electronjs.orgは、Windows環境とMac環境に対応していますが、
いくつかアップロードされているzipファイルのうち、
どのzipファイルが、どの環境用のものかは、ファイル名から判断されています。
なので、zipファイル名には、mac, darwin, win32-x64など対応環境を示す文字を入れておきましょう。
mac darwin osx win32-ia32 win32-x64
Electronアプリへの組み込み(自動的に更新処理)
Electronアプリのコードにアプリ自動更新の機能を組み込みます。
npmでupdate-electron-appを入れておいて、
npm install update-electron-app
アプリ側で、このコードを呼び出す。
require('update-electron-app')()
簡単!
Electronアプリへの組み込み(任意のタイミングで更新)
上の実装は簡単なのですが、しかし、ドキュメントによると、
10分毎に更新をチェックしにいくようです。
https://www.electronjs.org/docs/tutorial/updates
なんてこった(>_<)!
そんなにアプリを頻繁に更新するわけないぞ(>_<)!
1ヶ月に1回更新できたらマシな方だ(>_<)!
そういう場合は、checkForUpdates()を手動で叩いて、
好きな頻度で更新するか、メニューから更新できるようにしたら良いでしょうな。
autoUpdater.checkForUpdates();
import {app, dialog, autoUpdater} from 'electron'; // register events autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => { const dialogOptions = { type: 'info', buttons: ['Restart', 'Later'], title: 'Application Update', message: process.platform === 'win32' ? releaseNotes : releaseName, detail: '新しいアプリのダウンロードが完了しました。アプリを再起動して更新を適用します。', }; dialog.showMessageBox(dialogOptions) .then((result) => { const btnId: number = result.response; if (btnId === 0) { autoUpdater.quitAndInstall(); } }); }); autoUpdater.on('error', (err: Error) => { const dialogOptions = { type: 'error', title: 'Application Version Check Error.', message: 'アプリのアップデート中にエラーが発生しました。', buttons: ['OK'], defaultId: 0, cancelId: 0, }; dialog.showMessageBox(dialogOptions); }); // setup feed url const server = 'https://update.electronjs.org'; const feed = `${server}/taku-o/myukkurivoice/${process.platform}-${process.arch}/${app.getVersion()}`; autoUpdater.setFeedURL({ url: feed, serverType: 'json', }); // update autoUpdater.checkForUpdates();
いったんcheckForUpdates()を実行すると、
アプリの更新処理をストップ出来ないらしく、
実行前にユーザーに確認ダイアログを出しておいた方が良さそうです。
あるいは、今動作しているアプリのバージョンが最新かどうか確認しておいてから、
アプリを更新しても良いか聞いておきましょう。
autoUpdaterが間違ったファイルをダウンロードする(1敗)
ElectronのautoUpdaterは、おおよそ次の順番で処理しています。
(Mac環境)
1. 実行中のアプリの署名の確認 2. 実行中のアプリが最新版かどうかチェック 3. 最新アプリのダウンロード 4. zipファイルの解凍 5. 最新アプリの署名の確認 6. アプリの入れ替え
update.electronjs.orgはこんな実装(↓)になっているので、
データファイルなどの名前に"mac"の文字が入っていると、
更新アプリでなく、間違ったファイルをダウンロードすることがありますね。
(1敗)
# https://github.com/electron/update.electronjs.org/blob/ed32d4fedca459fb734a5d898d8573f57b605bd4/index.js#L236 const assetPlatform = fileName => { if (/.*(mac|darwin|osx).*\.zip/i.test(fileName)) return 'darwin-x64' if (/win32-ia32/.test(fileName)) return 'win32-ia32' if (/win32-x64|(\.exe$)/.test(fileName)) return 'win32-x64' return false }
ダウンロードされたzipファイルは、
次のような場所に保存された後、解凍され、
その後、アプリの署名の検証が行われます。
/Users/user/Library/Caches/xx.xx.bundleid.ShipIt/update.QCBggxR
なので、誤ったファイルをダウンロードしていて、
署名エラーが発生している時は、
このディレクトリを監視していれば、問題を追えます。
(エラーになった時、すぐ消されちゃうみたいですけど。)
if (/win32-x64|(\.exe$)/.test(fileName)) return 'win32-x64'
試していませんけれど、このコードを見る限り、
Windows環境はexe形式もいけるみたいですね。
自己解凍形式がサポートされているのかな?
終わり
MacのElectronアプリだったらさ、
自動更新機能を組み込まなくても、Mac App Storeに出せば良いじゃない?
どうも駄目なレビュアーに当たった気がします。
審査が通らない。
話が通じない。
そろそろ審査アプリのバンドルIDを変更して、
レビューする人を切り替えようかと考え始めています。
(あくまでも自分は悪くないと決めつけるスタイル)