コンテンツにスキップ

自動アップデート

この節の要旨 GitHub Releases をソースにした無停止アップデート機構。チェック → ダウンロード → 展開 → ユーザー同意 → 終了時適用 → 再起動という段階制御で、ユーザーが明示的に承認するまで実ファイルは書き換えられません。

構成

構成要素 役割
UpdateService チェック・ダウンロード・展開と、適用するファイルの準備を担当
更新の通知 更新の準備ができると、ステータスバー直上・中央寄せのバナーを出す。再起動ボタンと閉じるボタン付き
設定(settings.json) AutoUpdateEnabled, LastUpdateCheck, SkippedVersions — チェック間隔・最終チェック時刻・スキップ済みバージョン一覧

チェックと取得フロー

  1. 自動チェック: UpdateService.Initialize() が AutoUpdateEnabled==true のとき Timer を生成し、起動 30 秒後に初回、以後 4 時間間隔でバックグラウンドチェックを実行。rate limit 対策として前回チェックから 30 分以内はスキップ(_lastCheckUtc でガード)。
  2. 手動チェック: Control Deck → このアプリについて → 「アップデートを確認」で CheckForUpdatesAsync() を即時呼び出し。結果はトーストと UpdateStatus プロパティで表示。
  3. バージョン照会の二段構え:
  4. 第一優先は Cloudflare Worker(VersionCheckUrl)。GitHub API rate limit を回避するためのキャッシュ層。
  5. Worker が error プロパティを返した/HTTP 失敗した場合、GitHub API (releases/latest) へ自動フォールバック(CheckGitHubDirectAsync)。
  6. ダウンロードタイプの優先順位(Auto 指定時):
  7. 差分版 (delta) — DeltaFromVersion == AppVersion が一致するときのみ使用
  8. 完全版 (full) — 上記が使えない場合のフォールバック バージョンを飛ばして更新した場合は delta が一致しないため、自動的に完全版になります。また、プログラム本体の置き場所が変わる前のバージョンから更新する場合も、必要なファイルが揃わないため常に完全版が選ばれます(ResolveDownloadType)。
  9. ダウンロード進捗: _downloadClient(API ヘッダーなし、タイムアウト 5 分)でストリーム受信し、GlowBar(10〜74%)で可視化。受信後は ZipFile.ExtractToDirectory で一時ディレクトリ(TempUpdateDir)に展開。展開完了時に IsReadyToRestart = true と RaiseStateChanged()。

ユーザー同意ゲート(v0.45.1 以降)

再起動ポップアップがユーザー操作で閉じられる前にアプリが終了しても、黙って更新が適用されることはありません。

  • UpdateService.UserConsentedToApply フラグは ApplyAndRestart()(=ポップアップ「再起動」ボタン押下時)でのみ true になる。
  • アプリ終了時の App_Exit → UpdateService.ApplyOnExit() は if (!IsReadyToRestart || !UserConsentedToApply) return; のガードで動作。
  • ユーザーが同意せずに閉じた場合、次回起動時の 30 秒タイマーで再度チェックが走り、同じポップアップが再出現する(ダウンロード済みの展開物は TempUpdateDir に残置)。

適用バッチと再起動通知

  • LaunchUpdateBatch() が生成した .bat が xcopy /s /y /q で extracted/ 内を appDir に上書きコピーし、新バイナリで再起動。
  • 再起動後のプロセスは --updated コマンドライン引数付きで起動し、アプリがこれを検出して「アップデートが完了しました(vX.Y.Z)」トーストを表示。同時に CleanupTempFiles() で旧キャッシュを削除。

スキップ機能

バージョン通知ダイアログで「このバージョンをスキップ」を選択すると、対象バージョンが WindowSettings.SkippedVersions に追加され、以後の自動チェックでは通知されません(手動チェックには表示される)。

トラブルシュート

症状 原因と対処
ポップアップが出ない ログ(data/logs/*.log)で [Update] StateChanged raised と [Update] ShowRestartPopup called が出ているか確認。出ていない場合は _updateServiceSubscribed 未初期化の疑い
「rate limit」ログが出る Worker 経由ではなく GitHub API 直接呼出でレート上限超過。次回チェックが 6 時間後に自動延長される。rate limit 中のダウンロードはブラウザで Releases ページを開くフォールバックに切り替わる
再起動しても更新が反映されない 適用バッチがアンチウイルスにブロックされた可能性。data/logs/ の [Update] ApplyAndRestart と [Update] ApplyOnExit ログで IsReadyToRestart / UserConsentedToApply の値を確認
自動アップデートを完全に止めたい Control Deck → このアプリについて → 「自動アップデートを有効にする」を OFF。WindowSettings.AutoUpdateEnabled = false が保存され、タイマーは SetEnabled(false) で停止

ログ仕様

アップデート関連の主要ログプレフィックスは [Update]。v0.45.1 以降で以下のポイントに明示ログが追加されました。

  • [Update] 定期チェック開始 / 結果: hasUpdate=...
  • [Update] {typeLabel} (v... → v...) — ダウンロード開始
  • [Update] ダウンロード&展開完了 IsReadyToRestart=true
  • [Update] StateChanged raised: IsDownloading=..., IsReadyToRestart=..., AvailableVersion=...
  • [Update] ShowRestartPopup called from {source}, version=...
  • [Update] ApplyAndRestart: ユーザー承認済み、バッチ起動
  • [Update] ApplyOnExit: IsReadyToRestart=..., UserConsentedToApply=...