本文へスキップ

自動更新

自動更新を含めるには github.com/egoist/quickgui/extensions/updater をインポートします。インポートしないアプリにはアップデーターは同梱されません。

#設定

#1. 署名鍵を作成する

すべての更新は Ed25519 鍵で署名されます。鍵ペアは一度だけ作成し、アプリが存続する限り保管してください。インストール済みのアプリは、ビルド時の鍵で署名された更新しか受け付けません。

quickgui keygen --out-dir ~/.config/my-app/update-keys

このコマンドは quickgui-update.pub と quickgui-update.key を書き出します。.pub の内容を設定に記述します。.key ファイルは秘密情報です。パスワードマネージャーや CI のシークレットストアに保管し、リポジトリには決して入れないでください。紛失すると、インストール済みのアプリは二度と更新できなくなります。

#2. リリースの公開先を選ぶ

updates.target に "github" または "s3" を設定し、同じ名前のセクションを記入します。target によって --upload の送信先と、アプリが確認する URL が決まるため、フィードやダウンロードの URL を自分で書く必要はありません。両方のセクションを設定に残しておいても構いません。使われるのは target が指す方だけです。フィードのアドレスはアプリに組み込まれるため、後から target を変更しても、影響するのは変更後にビルドしたバージョンだけです。ユーザーが移行し終えるまでは、以前の target にも公開し続けてください。

GitHub Releases に必要なのはリポジトリ名だけです。インストール済みのアプリは認証なしで更新をダウンロードするため、リポジトリは公開されている必要があります。

[updates]
target = "github"                 # publish to and update from GitHub Releases
publicKey = "PASTE_THE_CONTENTS_OF_quickgui-update.pub"
automaticChecks = true            # default for new installs; users can change it
changelog = "CHANGELOG.md"        # optional; this file is used by default when it exists

[updates.github]
repository = "example/my-app"     # owner/name of a PUBLIC repository
# tagPrefix = "v"                 # release tag = tagPrefix + version, e.g. v1.2.0

Amazon S3 には、バケット、そのリージョン、そしてバケットを配信する公開 HTTPS アドレス(バケット自身の URL、またはその前段の CloudFront ドメイン)が必要です。

[updates]
target = "s3"                     # publish to and update from the bucket below
publicKey = "PASTE_THE_CONTENTS_OF_quickgui-update.pub"
automaticChecks = true            # default for new installs; users can change it
changelog = "CHANGELOG.md"        # optional; this file is used by default when it exists

[updates.s3]
bucket = "my-app-releases"
region = "us-east-1"
publicUrl = "https://my-app-releases.s3.us-east-1.amazonaws.com"
# prefix = "stable"               # optional folder inside the bucket

Cloudflare R2、MinIO などの S3 互換ストレージ では、S3 API のアドレスである endpoint を追加します。publicUrl は引き続きユーザーがダウンロードに使うアドレスで、R2 ではカスタムドメインまたはバケットの r2.dev URL です。

[updates]
target = "s3"                     # publish to and update from the bucket below
publicKey = "PASTE_THE_CONTENTS_OF_quickgui-update.pub"
automaticChecks = true            # default for new installs; users can change it
changelog = "CHANGELOG.md"        # optional; this file is used by default when it exists

[updates.s3]
bucket = "my-app-releases"
endpoint = "https://ACCOUNT_ID.r2.cloudflarestorage.com"   # S3 API endpoint
region = "auto"
publicUrl = "https://downloads.example.com"                # custom domain or https://pub-….r2.dev
# prefix = "stable"

バケットは、アップロードされたファイルの公開読み取りを許可している必要があります。QuickGUI はあなたの認証情報でアップロードしますが、バケットポリシーは変更しません。

#3. updates の全オプション

オプション必須意味
publicKeyはいquickgui-update.pub の内容。アプリに埋め込まれ、すべての更新の検証に使われます。
targetはい"github" または "s3"。どのセクションを使うかを選びます。
github.repositorytarget = "github" の場合は必須公開 GitHub リポジトリの owner/name。
github.tagPrefixいいえリリースタグはこの接頭辞にバージョンを付けたものです。既定は "v" で、バージョン 1.2.0 は v1.2.0 として公開されます。
s3.buckettarget = "s3" の場合は必須バケット名。
s3.publicUrltarget = "s3" の場合は必須バケットを配信する公開 HTTPS アドレス。クエリ文字列や認証情報は含められません。
s3.endpointいいえAWS 以外のプロバイダーの S3 API エンドポイント。AWS では省略します。
s3.regionいいえバケットのリージョン。R2 では "auto"。
s3.prefixいいえバケット内のフォルダー。publicUrl の後ろにも付加されます。
automaticChecksいいえ新規インストールが起動時に確認するかどうか。既定は true。ユーザー自身の選択は記憶され、優先されます。
changelogいいえすべてのバージョンをまとめた Markdown の変更履歴。version と一致する ## x.y.z セクションがリリースノートになります。CHANGELOG.md があれば既定でそれを使います。
ed25519SecretKeyいいえローカルビルド用の秘密鍵ファイルのパス。環境変数 QUICKGUI_UPDATER_PRIVATE_KEY が優先されます。
manifestいいえtrue にすると、--update-manifest と同様に、本番ビルドのたびに署名して更新フィードを書き出します。

#URL の決まり方

target によってすべてのアドレスが決まります。<file> は appcast-darwin-arm64.xml のようなファイル名、<tag> は tagPrefix にバージョンを付けたものです。

GitHubS3
更新フィード、install.sh、latest-linux-<arch>.txthttps://github.com/<repository>/releases/latest/download/<file><publicUrl>/<prefix>/<file>
インストーラーと更新アーカイブhttps://github.com/<repository>/releases/download/<tag>/<file><publicUrl>/<prefix>/<file>

GitHub では、フィードは常に Latest と表示されているリリースから取得されます。ドラフトとプレリリースは latest にならないため、通常のリリースとして公開するまでユーザーには届きません。--upload は常にドラフトを作成します。

CLI はバージョン、識別子、フィード URL、公開鍵をアプリに埋め込みます。秘密鍵が埋め込まれることはありません。App Store 向けやサンドボックス化したビルドでは、Go のビルドタグでアップデーターのインポートを除外してください。

#アプリでの使用

native.Run の準備ができたあと、コンポーネントの外で開始します。アプリ全体で 1 つのアップデーターを共有します。

import (
	"log"

	"github.com/egoist/quickgui/go/native"
	"github.com/egoist/quickgui/extensions/updater"
)

var updates *updater.Updater

func startUpdater() {
	updates = updater.Start(updater.Options{}, func(event updater.Event) {
		if event.Error != "" {
			log.Print(event.Error)
		}
		if event.QuitRequired {
			native.App.Quit(false, nil)
		}
	}, func(err error) {
		if err != nil {
			log.Print(err)
		}
	})
}

「更新を確認」の項目から updates.Check(done)、利用可能な更新のバナーから updates.Install(done)、設定から updates.SetAutomaticChecks(enabled, done) を呼び出します。コールバックは UI ゴルーチンで実行されます。State() は最新のイベントを返します。

Options で feed URL と公開鍵を上書きできます。開発ビルドは既定で無効です。AllowDevelopment: true はテスト用 feed と破棄可能なアプリバンドルでのみ使ってください。

#ライフサイクル

Event.Status は idle、checking、available、downloading、installing、または disabled です。イベントにはバージョン、説明、進捗、自動確認の設定、任意のエラーが含まれます。

macOS では Sparkle がダウンロード、検証、インストール、再起動を担当します。手動確認では Sparkle の標準 UI を表示でき、定期確認の結果はアプリ内バナーに渡せます。

Windows と Linux では、自動確認が有効なとき起動時に 1 回確認します。QuitRequired はヘルパーがアプリの終了を待っていることを意味します。作業を保存したあと native.App.Quit(false, nil) を呼び出してください。終了がキャンセルされると、ヘルパーはタイムアウトし、現在のアプリはそのまま残ります。

#対応プラットフォーム

プラットフォーム更新のペイロードインストール
macOS署名済み .app を含む ZIPSparkle。アップデーターと一緒のときだけ含まれます
WindowsNSIS .exe インストーラーヘルパーが終了を待ち、検証済みインストーラーをサイレント実行してから再起動します
LinuxType-2 .AppImage、または install.sh の tarballヘルパーが終了を待ち、ユーザー所有の AppImage またはインストールディレクトリを置換します。新しいビルドが起動に失敗した場合は元に戻します

Linux の .deb パッケージ、システムバイナリ、root 所有のインストールは disabled を報告します。そこではプラットフォームのパッケージマネージャーを使ってください。

quickgui build は <Name>-<version>-linux-<arch>.tar.gz、install.sh、latest-linux-<arch>.txt も出力します。--upload はこの 3 つをすべて公開し、GitHub ではスクリプトに固定の URL が付きます。curl -fsSL https://github.com/<owner>/<repo>/releases/latest/download/install.sh | sh は root なしで ~/.local/<package>.app にインストールし、アプリケーションメニューに登録します。このインストールは自動的に更新されます。不要な場合は linux.tarball = false を設定してください。

feed は Ed25519 署名付きの HTTPS Sparkle RSS appcast です。署名なしのフォールバックはありません。

#更新の公開

#1. 手元のマシンからリリースする

まず設定の version を上げます。アプリは自分より高いバージョンしかインストールしません。そのバージョンの ## <version> セクションを CHANGELOG.md に追加します。次に、ビルドに秘密鍵を渡し、--upload を付けて実行します:

export QUICKGUI_UPDATER_PRIVATE_KEY="$(cat ~/.config/my-app/update-keys/quickgui-update.key)"
quickgui build --upload

GitHub の場合は、一度 gh auth login でサインインしておきます(または GH_TOKEN を設定します)。S3 の場合は AWS_ACCESS_KEY_ID と AWS_SECRET_ACCESS_KEY を設定します。

--upload はアプリをビルドし、更新ファイルに署名し、フィードを書き出して、すべてを公開します。完了すると公開 URL を 1 つずつ表示します。GitHub の場合、これらの URL はドラフトリリースを公開した後に有効になります。アップロードせずに署名とフィードの書き出しだけを行いたい場合(先に dist/ を確認したい場合など)は、代わりに --update-manifest を使います。このコマンドはターゲットごとに 1 回実行します。ターゲットごとに専用のフィードがあるため、Mac が Linux ビルドをダウンロードすることはありません。

#2. アップロードされるファイル

ターゲットファイル
macOS新規ユーザー向けの <Name>.dmg、更新用の <Name>-<version>-<target>.zip、appcast-<target>.xml
Windows<Name>-<version>-<target>.exe(インストーラー兼更新)、appcast-<target>.xml
Linux.AppImage、<Name>-<version>-<target>.tar.gz、設定している場合は .deb、install.sh、latest-linux-<arch>.txt、appcast-<target>.xml

バージョン付きファイルが先に、フィードが最後にアップロードされるため、フィードがまだ存在しないファイルを指すことはありません。GitHub では、最初のターゲットがリリース <tag> をドラフトとして作成し(そのバージョンの変更履歴セクションが説明になります)、以降のターゲットは自分のファイルをそこに追加します。再実行すると同名のファイルは置き換えられます。

ドラフトはユーザーには見えず、更新フィードも変わらないため、アップロード途中のリリースが配信されることはありません。すべてのターゲットのアップロードが終わったら、ドラフトを確認して公開します。リリースページから、または次のコマンドで行えます:

gh release edit v1.2.0 --repo example/my-app --draft=false

公開すると最新リリースになり、インストール済みのアプリは次回の確認時に更新を見つけます。S3 にはドラフトの段階がなく、ファイルはアップロードされた時点で有効になります。

#3. GitHub Actions からリリースする

秘密鍵を QUICKGUI_UPDATER_PRIVATE_KEY という名前のリポジトリシークレットとして追加し(Settings → Secrets and variables → Actions)、設定のバージョンと一致するタグをプッシュします:

# .github/workflows/release.yml
name: Release
on:
  push:
    tags: ["v*"]

permissions:
  contents: write # lets GITHUB_TOKEN create the release and upload assets

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: macos-latest
            target: darwin-arm64
          - os: ubuntu-22.04
            target: linux-x64
          - os: windows-latest
            target: windows-x64
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - uses: actions/setup-go@v5
        with:
          go-version: stable
      - run: bun install
      - run: bunx @quickgui/cli build --target ${{ matrix.target }} --upload
        env:
          QUICKGUI_UPDATER_PRIVATE_KEY: ${{ secrets.QUICKGUI_UPDATER_PRIVATE_KEY }}
          GH_TOKEN: ${{ github.token }}
          # For updates.s3 instead of GH_TOKEN:
          # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

  # updates.github only: the uploads above go into a draft release. Publish it once every
  # target succeeded. Remove this job to review and publish drafts by hand.
  publish:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: gh release edit "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --draft=false
        env:
          GH_TOKEN: ${{ github.token }}

3 つのビルドジョブは同じドラフトリリースにアップロードし、すべてが成功した後にだけ publish がそれを公開するため、プラットフォームが欠けたリリースがユーザーに届くことはありません。gh CLI は GitHub のランナーにプリインストールされています。配布する macOS ビルドには --sign と --notarize も指定してください。Windows ではランナーに NSIS(makensis)が必要です。Linux は appimagetool がインストールされている場合にのみ AppImage を生成します(tarball には何も必要ありません)。

#リリースノート

リリースノートは、すべてのバージョンを 1 つにまとめた Markdown の変更履歴から取得されます。バージョン 1.2.0 を公開すると、ビルドは ## 1.2.0 という見出しの下のセクションを取り出し、更新と一緒に配布します。

updates.changelog にはプロジェクトからの相対パスでファイルを指定します。省略した場合、プロジェクトディレクトリに CHANGELOG.md があればそれが使われます。

# Changelog

## 1.2.0 - 2026-09-19

Faster startup and a fix for lost drafts.

- Search inside a project with **Ctrl+Shift+F**
- Windows remember their size and position
- Fix drafts being lost when the app quits during a save

## 1.1.0

- Add a tray icon
- Fix a crash when opening an empty project
  • リリースの見出しは ## x.y.z で、x.y.z は設定の version です。日付を続けることもできます:## x.y.z - 2026-09-19。
  • ノートは、その見出しの下から次の ## 見出しまでのすべてです。最初のリリース見出しより上にあるテキスト(タイトルや説明など)が公開されることはありません。
  • 必要であれば「追加」「修正」などのグループに ### を使えます。これらはセクションの中にとどまります。
  • 1 つのセクションは最大 16 KiB です。
  • 最新のリリースを一番上に書きます。コミット履歴ではなく、アプリを使う人にとって何が変わったのかを書いてください。

見出しがない場合やセクションが空の場合、公開は CHANGELOG.md has no notes for this release. Add a `## 1.2.0` section というエラーで失敗するため、誤ったノートでリリースされることはありません。変更履歴がまったくないプロジェクトはノートなしで公開され、更新はバージョン番号だけで引き続き提供されます。ビルドは、取り出したセクションを dist/<target>/release-notes.md にも書き出します。

表示される場所表示のされ方
Windows と Linuxアプリが Markdown を event.Notes としてそのまま受け取ります。Markdown コンポーネントでレンダリングするか、テキストとして表示してください。
macOSSparkle の更新ウィンドウが Markdown としてレンダリングします。
GitHub のリリースページ(target = "github")リリースの説明になります。

#S3 の認証情報

変数意味
AWS_ACCESS_KEY_ID または S3_ACCESS_KEY_IDバケットにオブジェクトを書き込む権限を持つアクセスキー
AWS_SECRET_ACCESS_KEY または S3_SECRET_ACCESS_KEYそのシークレット
AWS_SESSION_TOKEN または S3_SESSION_TOKEN一時的な認証情報の場合のみ

R2 では、バケットに対する Object Read & Write 権限を持つ API トークンを作成し、そのアクセスキー ID とシークレットを使います。CDN がバケットをキャッシュしている場合は、appcast-*.xml、latest-linux-<arch>.txt、install.sh のキャッシュ期間を短くしてください。これらはリリースのたびに変わります。

#Linux のインストールコマンド

Linux ビルドは install.sh も公開します。root なしで tarball を ~/.local/<package>.app にインストールし、アプリケーションメニューに登録します。このインストールは自動的に最新の状態に保たれます。ユーザーには次の 1 行を案内してください:

# updates.github
curl -fsSL https://github.com/example/my-app/releases/latest/download/install.sh | sh
# updates.s3
curl -fsSL https://downloads.example.com/install.sh | sh

同じ URL に | sh -s -- --uninstall を付けるとアンインストールできます。tarball とスクリプトが不要な場合は linux.tarball = false を設定します。

#トラブルシューティング

  • アプリが「最新です」と表示する。 公開した version はインストール済みのものより高い必要があります。GitHub ではリリースが公開済みで(--upload はドラフトのままにします)、プレリリースに指定されていない必要があり、そのターゲットのフィードが存在している必要があります。上の表のフィード URL をブラウザーで開いて確認してください。
  • Set updates.publicKey and QUICKGUI_UPDATER_PRIVATE_KEY。 ビルドに秘密鍵が渡されていません。変数をエクスポートするか、ed25519SecretKey を設定してください。
  • Update signing key does not match updates.publicKey。 秘密鍵が、設定した公開鍵と対になっていません。最初の鍵を使ってください。配布済みのアプリはその鍵しか信頼しません。
  • CHANGELOG.md has no notes for this release。 version と完全に一致する ## x.y.z 見出しを追加し、その下に少なくとも 1 行書いてください。
  • ステータスが disabled になる。 開発ビルドは更新されません。.deb、システム全体、root 所有の Linux インストールも同様です。本番ビルドでテストしてください。
  • GitHub upload failed。 gh auth status、トークンにリポジトリへの書き込み権限があるか(Actions では contents: write)、リポジトリ名が正しいかを確認してください。
  • S3 upload failed。 認証情報、region、endpoint を確認してください。ダウンロード時の 403 は、バケットが公開読み取りを許可していないことを意味します。

#ネイティブ成果物

このリポジトリでは、bun packages/native/build.ts --extension updater でアップデーターを一度ビルドします。パッケージ済みアプリは、Go のインポートがあるときアップデーターを自動的に含めます。

アップデーターの例を参照してください。Sparkle 自身のドキュメントが appcast の詳細を扱っています。Sparkle。