🍣

[Cloudflare R2] electron-updaterでprivate repoのElectronアプリを配信する

2025/02/23に公開

はじめに

Electronで作ったMacアプリを配布したい!アプリ更新も手間をかけずに配信したい!
そんなときに便利なのがelectron-updaterの提供するAutoUpdateです(Electon本体が提供しているAutoUpdateとは別)。

このAutoUpdateの前提としてビルドしたアプリをどこかしらでホスト(リリース)する必要があり、Cloudflare R2でホストする手順と、検討した他の手段について記載します。

動作環境

macOS Sonoma 14.3.1
electron@34.0.2
electron-builder@25.1.8
electron-updater@6.3.9
GitHub Actions

課題

GitHubでコード管理しているなら、一番簡単な方法はGitHub Releasesでリリースをホストすることです。ただ、私はprivateリポジトリでコードを管理しており、アクセスするにはPAT(Personal Access Token)が必要です。

デスクトップアプリでPATを使うには、アプリに埋め込む(やり方はどうあれハードコードと同義)か、別途サーバーを用意する(PATを渡してしまったらあまり意味がない気がするし、認証も考えないといけない)くらいしか選択肢がないように思います(もしいい方法があれば教えて下さい)。

GitHubのPATは、fine-grainedを使ってもContents Read権限を付与するしかなく、内容は"Repository contents, commits, branches, downloads, releases, and merges."なのでこれを渡すのであればリポジトリをprivateにしている意味があまりないです。

ということでGitHub Releasesが使えないと分かり、代替手段を探すことになりました。現状の結論として、Cloudflare R2でリリースを配信し、アプリにはread-onlyのアクセスを渡す予定です ビルドしたモジュールだけを格納するR2はPublicにすればいいと気づきました。

ローカルからCloudflare R2に公開する

基本的な流れは以下の記事の通りです。electron-updaterはAWS S3をリリースのホストとしてサポートしており、Cloudflare R2はS3互換なので、S3として設定すればOKです。(S3ではなくR2を使う理由は、AWSよりCloudflareのほうが開発体験が良く好みだからです)
https://www.electron.build/publish#s3

  1. CloudflareでR2のバケットを作成する
  2. R2にアクセスするためのAPIキーを作成する
  3. APIキーを配置する
  4. electron-builderの設定をする
  5. run npm run dist:mac
electron-builder.json
...
  "publish": {
    "provider": "s3",
    "bucket": "<bucket name>",
    "endpoint": "https://<cloudflare account id>.r2.cloudflarestorage.com"
  },
...
package.json
...
  "scripts": {
    "dist:mac": "npm run build:electron && npm run build && electron-builder --mac --arm64 -p always",
  },
...

スクリプトの最後の -p alwaysオプションを指定することで、publish設定に沿ってビルドしたモジュールをリリースしてくれます。

作業自体はとても簡単で、設定も数行書くだけですが、1点だけ、step3のAPIキーを環境変数(.env)に設定すると以下のエラーで動きませんでした。

⨯ NoCredentialProviders: no valid providers in chain. Deprecated.
        For verbose messaging see aws.Config.CredentialsChainVerboseErrors

AWS公式Issueを見ながら.aws/credentialsを作成してAPIキーを記述したところ、無事に通るようになりました。

GitHub ActionsからCloudflare R2に公開する

Actionsから実行するときの差分だけ記載します。
APIキーの配置は、こちらは環境変数(Secrets)で問題なかったです。あとはelectron-builderの実行を npx electron-builderとしていることくらいです。

build-mac.yml
...
      - name: Build and Sign macOS app
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: |
          npm run build:electron && npm run build
          npx electron-builder --mac --arm64 -p always
...

これでローカル、CI両方でR2にリリースを載せられるようになったので、あとはアプリ側のAutoUpdateでこれを取得し、アップデートを適用できるようになるはずです。この手順は実装できたら別の記事にまとめるつもりです。

その他、試したこと

もともとGitHub ReleasesでリリースするつもりがうまくいかずにR2に流れ着いたので、試したことを書いておきます。

Nuts

こちらのIssueで見つけたのですが、Nutsというprivate repoのリリースをホストするプロキシがあるようです。まさにドンピシャの解決策だと思って喜び勇んで試してみたのですが、公式ガイドに載っているHerokuのデプロイが動きませんでした。

A valid GitHub directory could not be found.
The given URL (https://nuts.gitbook.com/) is not a valid GitHub repository.

こちらのIssueをみてHeroku Buttonsも見に行ったところ、そもそも該当のボタンが削除されているようでした。また、Nuts自体も最終コミットが10年近く前だったので諦めました。

PAT

stackoverflowをみてPATも試しました。確かに動くんですが、冒頭で書いたとおりの課題があり、私のユースケース的に許容できなかったので見送りました。

ちなみに、PATを利用する場合はその渡し方も困るポイントかと思います。setFeedURL というメソッドで設定を渡すことができますが、非推奨です。

electron-builder.jsonでtokenとして渡すのが正攻法らしいですが、ハードコードするわけにはいかないので、動的にjsonを生成するようなワークアラウンドが必要そうです。めんどくさいですね。

Discussion