技術ログ

Electronアプリの自動アップデート機構を作る (実装記)

公開: 2026-05-19 · 著者: GRAMSHIFT

Electron配布で「ユーザーに古いバージョンを使わせ続けない」ための仕組みを実装する

Electronアプリの自動アップデート機構を作る (実装記)

あなたがElectronで配布しているデスクトップアプリに、自動アップデート機構を入れていますか?もし入っていないなら、ユーザーから「動かない」「バグがある」と言われたときに、実は数バージョン前を使っていただけだった、というケースが頻発しているはずです。GramShift Desktopはこれまで25回リリース (v1.0.0〜v1.5.15、2025-12〜2026-05)していますが、自動アップデート機構を最初から入れたことで、サポート対応時間を明確に削減できました。この記事では実装の核と、私が踏み抜いた具体的な落とし穴を共有します。

構成全体像: electron-updater + GitHub Releases

GramShift Desktop の自動アップデート機構は、electron-updaterパッケージと GitHub Releases を組み合わせた標準的な構成です。新しいバージョンをリリースする手順はこうなります。第一に、ローカルで npm version patch/minor/major でバージョンを上げる。第二に、npm run build で各プラットフォーム向けインストーラーを生成。第三に、GitHub Releases に .exe / .dmglatest.yml をアップロード。第四に、起動済みクライアントが定期的に latest.yml をチェックして、新バージョンを検出すると自動でダウンロード・インストールします。

この構成のいいところは、サーバーを別途運用する必要がないことです。GitHub Releases が CDN として機能し、無料で配信できます。GramShift では月間ダウンロード総量が約3GBほどありますが、GitHub の帯域制限に引っかかったことはありません。

main プロセスでの実装最小コード

Electron の main プロセスでの最小限の実装はこのようになります。アプリ起動直後にチェックして、新バージョン検出時にユーザーに通知、ダウンロード後にインストール確認ダイアログを表示する流れです。

const { app, dialog, autoUpdater } = require('electron');
const { autoUpdater: electronUpdater } = require('electron-updater');

function setupAutoUpdate(mainWindow) {
 electronUpdater.autoDownload = false;
 electronUpdater.autoInstallOnAppQuit = true;

 electronUpdater.on('update-available', (info) => {
 dialog.showMessageBox(mainWindow, {
 type: 'info',
 title: '新しいバージョンがあります',
 message: `v${info.version} に更新できます`,
 buttons: ['今すぐ更新', '後で']
 }).then((result) => {
 if (result.response === 0) electronUpdater.downloadUpdate();
 });
 });

 electronUpdater.on('update-downloaded', () => {
 dialog.showMessageBox(mainWindow, {
 title: '更新の準備ができました',
 message: 'アプリを再起動して更新を適用します',
 buttons: ['再起動', '次回起動時']
 }).then((result) => {
 if (result.response === 0) electronUpdater.quitAndInstall();
 });
 });

 electronUpdater.checkForUpdates();
}

app.on('ready', () => {
 const mainWindow = createWindow();
 setupAutoUpdate(mainWindow);
});

autoDownload = false にしているのは、ユーザーの帯域とディスク容量を勝手に消費したくないからです。「更新可能」を伝えてから、ユーザーの同意を得てダウンロードに進むほうが、リアクションも良くなります。

v1.5.7 リリースで踏み抜いた落とし穴 — 難読化の罠

これまで25リリースを重ねた中で最も印象に残っているのが、v1.5.7 リリース時の難読化トラップです。当時、私は配布ファイルの逆コンパイル対策として一部の JavaScript を難読化していたのですが、API 通信を担当する api.js も誤って難読化対象に含めてしまいました。その結果、reportActivity 関数の HTTP 通信だけが本番環境で動かない、という症状が発生しました。

奇妙なことに heartbeatreportStats は同じ api.js から動いていて、ダッシュボードには「今日のいいね 0」と表示されるのに、実際の DB には件数が記録されている、というねじれ状態でした。原因が「特定の関数だけ難読化で名前変換が壊れている」と気づくまで約3時間、ログ追加と検証を繰り返しました。最終的に api.js を難読化対象から外して再ビルドすると、すべての通信が復活しました。

この失敗から得た教訓は「ネットワーク通信を担うファイルは難読化対象から除外する」「リリース直後の数時間は本番ダッシュボードに張り付いて表示の整合性を確認する」の2つです。難読化は逆コンパイル対策として一定の効果がありますが、デバッグ時の難易度を明確に上げるので、対象を絞り込むのが必須です。

コード署名と Windows SmartScreen 警告

Windows でElectronアプリを配布すると、最初の数百ダウンロードの間は SmartScreen の「発行元が確認できません」警告が出ます。コード署名証明書を購入すれば回避できますが、年間 3-5 万円のコストがかかります。個人開発の初期段階では「警告を一旦許容して、後から署名を入れる」という選択でも問題ないと判断しました。GramShift も現状は無署名で、ダウンロード時の警告画面を回避する手順をユーザーマニュアルに記載しています。

ダウンロード総数が1,000を超えると SmartScreen のレピュテーションが上がって警告が出なくなる仕様もあるため、初期 1,000 ダウンロードは「警告を許容しつつ実績を積む」期間として戦略的に運用するのもありです。

自動アップデートは「ユーザー対応コストを削減する投資」

自動アップデート機構の実装には、初期構築で約1日かかります。しかし運用開始後は、ユーザーが古いバージョンを使い続けることがほぼなくなり、サポート対応の前提が揃います。「バグ報告 → どのバージョンですか? → 最新版にしてください → 解決」というルーチンを完全に省略でき、私の場合、月のサポート対応時間が明確に削減されました (具体的な削減率は事業性質上開示せず)。Electronで個人開発しているなら、リリース第1版から自動アップデートを組み込むことを強くおすすめします。

GramShift Desktop 25リリースの軌跡 (一部抜粋)

自動更新を入れたおかげで、リリースペースが落ちませんでした。代表的なリリースを並べると、改修の方向性が見えます。

  • v1.0.0 (2025年12月): 初版リリース、自動いいね基本機能
  • v1.1.x (2026年1月-2月): 自動フォロー追加、UI改善、JSTタイムスタンプ統一
  • v1.2.0 (2026年4月19日): Intelligent Engagement Update、フォロワー属性に応じた優先度ロジック
  • v1.2.2 (2026年5月4日): エラー耐性 + 監視機能強化、Discord webhook 集約
  • v1.3.0 (2026年5月9日): 検索UI経由フロー大改修、難読化導入
  • v1.5.0 (2026年5月16日): Meta検知対策、Human-Pacing基盤の大幅強化 (詳細閾値は非公開)
  • v1.5.3 (2026年5月16日): キーワード検索フローの全面書き直し、人間風タイピング導入
  • v1.5.4 (2026年5月16日): 競合フォロワーターゲティング機能を完全廃止 (誇大表記リスク・規約グレーゾーン回避)
  • v1.5.5 (2026年5月16日): キーワード枯渇の自動検知 + Discord 通知
  • v1.5.7 (2026年5月17日): 配布周りの設定改善

1日に6リリース連続でぶん回した日 (5/16のMeta検知対応) は、自動更新がなければ配信できませんでした。クライアント側に「今日6回更新してください」と言うわけにはいきません。リリース → 自動更新 → 即反映、のサイクルが回せたから、当日に Human-Pacing を実装〜配信まで完了できました。

個人SaaSの本番運用記録は技術ログ失敗談カテゴリに随時追記しています。

実例: ユーザー向けインストール / アップデート手順 LP

Electron 自動アップデート機構を実装したあとに必要なのが、ユーザー向けの「初回インストール」と「アップデート手順」の説明 UI です。GramShift では gramshift.com/download にタブ切替形式で両方の手順を画像付きで配置しています。実際の LP プレビューを以下に残します。

GramShift LP のインストール手順タブ ファーストビュー
新規インストール手順タブ (初回ユーザー向け): 警告画面の説明を緑色ボックスで先出し、不安を先回り解消
GramShift LP のアップデート手順タブ ファーストビュー
アップデート手順タブ (既存ユーザー向け): 自動アップデートが効かないケースの手動更新フロー

自動アップデート機構を実装するだけでなく、「アップデートが効かないとき」のフォールバック手順を LP に画像付きで載せると、サポート問い合わせが大幅に減ります。GramShift では LP 公開後、アップデート関連の問い合わせが体感で半分以下になりました。

LP の構造を細部まで (フルスクロール画面)

ファーストビューだけでなく、スクロールしたあとの全体構造も残しておきます。インストール手順タブはステップ番号付きで 5 段階、アップデート手順タブは「自動更新の確認 → 効かない場合の手動更新」の流れで構成しています。実際の LP は gramshift.com/download で動作確認できます。

GramShift LP インストール手順タブの全体構造 (ステップ番号付き 5 段階の手順表示)
Figure: インストール手順タブ全体 — Edge SmartScreen 警告対応を含む 5 ステップ構成
GramShift LP アップデート手順タブの全体構造 (自動更新確認 + 手動更新フォールバック)
Figure: アップデート手順タブ全体 — 自動更新が効かないケースのフォールバック手順を画像付きで明示

LP に手順を画像付きで載せるかどうかは、サポート問い合わせ削減効果と引き換えに「LP のページサイズが重くなる」というトレードオフがあります。GramShift の場合、LP 公開後にアップデート関連の問い合わせが体感で半分以下になったため、ページ重量化のコストより問い合わせ削減の恩恵の方が大きいと判定しました。

関連記事

以下の記事も同じ文脈で書いています。

よくある質問

electron-updater と自前更新どちらを選ぶか?

electron-updater 一択。GitHub Releases / S3 / 汎用 HTTP 等の publish backend をサポート、署名検証も自動。自前実装は工数とテストコストの観点で個人開発スケールでは過剰。

自動更新で UI を止めない設計は可能か?

可能。autoDownload: true で背景 DL → ユーザー承認で適用する設計。再起動タイミングはユーザーが選べるため、操作中の中断を最小化できる。

更新失敗時のフォールバック手順は?

LP に手動更新手順 (再 DL → インストーラ実行) を画像付きで載せておく。問い合わせの大半は LP リンク 1 つで自己解決できる。