Webアプリの更新・配布戦略: App Store・Play Store・Tauri・Electronをどう分けるか
Capacitor、Tauri、Electronでアプリを配布・更新するときに、ストア審査、署名鍵、リリースチャネル、緊急修正、ロールバックを設計する方法をまとめます。
更新は配布チームの最後の仕事ではない
WebアプリをiOS、Android、Windows、macOSのアプリへ広げると、更新は「ビルド後に公開する」作業ではなくなります。どの変更がサーバーだけで反映され、どの変更が署名済みバイナリを必要とし、誰が審査または更新サーバーを制御し、失敗時にユーザーのデータをどう守るかが製品体験になります。
更新に失敗したときユーザーは、フレームワーク名ではなく「アプリが開かない」「下書きが消えた」「ログインできない」を体験します。したがって企画、デザイン、開発、運用は同じリリースモデルを持つ必要があります。
まず更新対象を三種類に分ける
同じ「変更」でも配り方は異なります。混ぜないことが最初の安全策です。
| 種類 | 例 | 配布・確認の中心 |
|---|---|---|
| サーバー側 | API、コンテンツ、機能フラグ、検索設定 | 段階公開、互換性、監視、即時ロールバック |
| Web資産 | HTML、JS、CSS、画像、WebView内UI | バイナリへの同梱、ストアポリシー、キャッシュ |
| ネイティブ実行物 | iOS/Androidコード、Tauri/Electron本体、権限、署名 | ストア審査または署名済み更新、再起動、移行 |
WebViewのUIだけを変えたつもりでも、新しいネイティブプラグイン、permission、CSP、URL scheme、OS APIを必要とするならネイティブ更新です。反対に表示文言やサーバーで制御する設定は、アプリ更新を待たずに直せる設計にします。何でも遠隔から差し替える仕組みは便利ですが、各ストアのポリシー、セキュリティ、審査上の制約を確認し、実行コードの置換と解釈される運用を避けます。
App Storeはアプリの内容と更新経路を一緒に見る
iOSでは署名、provisioning、App Store Connect、審査、バージョンという流れが製品の更新経路です。CapacitorはWeb資産とネイティブiOSプロジェクトを接続しますが、ストアへ出るのは署名済みのiOSアプリです。npx cap sync後に作るアーカイブに、どのWebビルドが含まれたか追跡可能にします。
iOSリリースに必要な質問
- このリリースはカメラ、通知、写真、位置情報などの利用目的文を変更するか。
- 審査者が中核機能を確認できるテストアカウント、導線、説明を持つか。
- 最低対応iOSと、古いOSでの代替表示を決めたか。
- アプリのバージョン、ビルド番号、Web資産のコミットをリリースノートへ残すか。
- ログイン、決済、アップロードがネットワーク断・復帰でどう動くか確認したか。
審査を「通すための最後の書類」と扱わず、権限要求、初回体験、アカウントなしで確認可能な範囲を設計の早期から用意します。
Google Playはversion codeと署名が続くリリースだ
AndroidではversionCodeが更新系列を識別し、署名鍵が継続性を担保します。CapacitorプロジェクトでJSを更新しても、Androidのビルド・署名・AAB生成・テストトラックを通る手順が必要です。鍵を個人PCだけに置くと、緊急修正時にチームのリリース権限が失われます。
コミット → Webビルド → cap sync → Androidビルド → 署名済みAAB
→ internal test → closed/open track → production
まずinternal testingで、実機の起動、権限拒否、アップグレード、既存データ、通知、外部URLを確認します。productionのversionCodeを使い回さず、CIがリリース対象の版と署名元を記録するようにします。ストアでの段階公開は、問題をゼロにする機能ではなく、影響を観測して停止できる運用です。
CapacitorでWeb資産更新を扱うときの基準
CapacitorではWeb資産がネイティブアプリに同梱されます。リリースのたびに、どのnpm run build結果をどのcap syncが反映したかを自動化し、ローカルだけで同期された状態をなくします。
npm ci
npm run check
npm run build
npx cap sync ios
npx cap sync android
ビルド情報を画面または診断ログで確認できるようにします。障害報告に「iOS 1.8.0 (build 42), web 3f2a1c」のような情報があれば、サーバー互換性とバイナリの組合せを追えます。更新時にデータ構造を変える場合は、古いアプリと新しいAPI、新しいアプリと古いローカルデータの双方をテストします。
Tauriの更新は署名鍵が製品の連続性を作る
Tauriの更新機構では、更新アーティファクトとメタデータの署名・検証が連続性の中核です。鍵はソースコードや一般的なCIログに置かず、アクセス記録のある秘密管理へ保管します。鍵の紛失、漏えい、ローテーション、担当者不在の手順を、最初の公開前に文書化します。
# 開発者が個人鍵を作る例。実際の保管先・手順はチームの秘密管理に従う。
npm run tauri signer generate -- -w ~/.tauri/my-app.key
# CIではリポジトリの鍵ファイルでなく、保護されたsecretを環境変数として注入する。
TAURI_SIGNING_PRIVATE_KEY="$TAURI_SIGNING_PRIVATE_KEY" npm run tauri build
公開鍵はアプリ側の更新設定に固定し、更新URLはTLSで提供します。テスト用鍵と本番鍵を混ぜず、stable、beta、internalの各チャネルに対応する鍵・feed・配布先の責任を明確にします。鍵のコマンドや設定名はTauriの採用版の公式文書で再確認してください。
Electronは更新サーバーとセキュリティ境界を一緒に運用する
Electronの自動更新は、更新サーバー、署名、更新メタデータ、ダウンロード、再起動、失敗表示から成ります。checkForUpdatesを呼ぶだけでは十分ではありません。どの版がどのチャネルを見に行くか、更新ファイルを誰がアップロードできるか、署名が無効な場合に何をするかを設計します。
import { autoUpdater } from 'electron-updater';
autoUpdater.on('update-available', (info) => {
mainWindow.webContents.send('update:available', { version: info.version });
});
autoUpdater.on('download-progress', (progress) => {
mainWindow.webContents.send('update:progress', progress.percent);
});
autoUpdater.on('update-downloaded', () => {
// UIに「次回起動時」または「今すぐ再起動」を選ばせる。
});
autoUpdater.on('error', (error) => {
// 秘密情報を除いた診断情報をログへ残し、UIには回復可能な案内を出す。
});
rendererへ更新ライブラリそのものを渡さず、preloadの限定イベントとして進捗だけを渡します。更新中の下書き、長い処理、モーダル、オフラインで再起動を強制すると、信頼を失います。再起動の選択、保存確認、後で更新する導線を設計します。
チャネルを分けると緊急配布と無謀な配布を区別できる
単一のproductionへ全ユーザーを直接送ると、緊急修正と未検証の公開を区別できません。少なくともinternal、beta、stableを分け、誰が何の根拠で昇格できるかを決めます。
| チャネル | 目的 | 参加者 | 昇格の根拠 |
|---|---|---|---|
| internal | 署名、起動、データ移行、基本導線の確認 | 開発・QA | 自動テストと手動チェック |
| beta | 実利用での互換性、性能、文言の確認 | 同意したテスター | 重大障害なし、観測値・フィードバック |
| stable | 一般提供 | 全ユーザー | ロールバック手順とサポート準備 |
チャネルを増やすことは自動的な安全ではありません。版、feed、鍵、テストアカウント、問い合わせ先をチャネルごとに混同しない仕組みが必要です。
自動化は配布ボタンではなく、証拠を残す流れだ
CIは「成功」の表示だけでなく、後で再現できる証拠を残します。ソースコミット、依存ロック、Node/Rust/SDK版、Web資産ハッシュ、ネイティブ版、署名の有無、対象OS、テスト結果、成果物の場所を関連付けます。
# CIの擬似コード: 実際の提供者の構文に合わせて実装する。
steps:
- checkout: pinned_commit
- install: locked_dependencies
- run: npm run check
- run: npm run build
- run: native_package_and_sign
- run: smoke_test_packaged_app
- publish: internal_channel_only
- record: commit_versions_artifact_checksums
秘密鍵、ストア認証情報、トークンをログへ出さず、forkや未承認PRからリリース処理を実行できないようにします。成果物を再アップロードする権限と、productionへ昇格する権限も可能なら分離します。
ロールバックは以前のファイルを再公開することより広い
ネイティブアプリでは、前のバイナリを再び配っても、すでにデータ移行やAPI変更を受けたユーザーが安全に戻れるとは限りません。ロールバック計画には、サーバー互換性、データ形式、機能フラグ、更新を停止する条件、サポート案内を含めます。
| 失敗 | 最初の対応 | 事前に必要な設計 |
|---|---|---|
| 起動不能 | 配布停止、影響版の特定 | 小規模段階公開、クラッシュ報告 |
| API互換性なし | サーバー側で旧版を維持または機能停止 | 版付きAPI、最低対応版の記録 |
| データ移行失敗 | 自動移行を止め、復旧手順を出す | バックアップ、冪等移行、移行版の記録 |
| 権限要求への混乱 | 文言・代替導線を修正 | 拒否・設定復帰のUXテスト |
配布チェックリストは企画・デザイン・開発が一緒に閉じる
製品とデザイン
- 更新の理由、対象ユーザー、影響を説明できるか。
- 権限拒否、更新待機、ネットワーク断、再起動の状態が設計されているか。
- ストア審査者、ベータ参加者、サポート担当が中核行動を再現できるか。
開発とセキュリティ
- バージョン、ビルド番号、Web資産、ネイティブ成果物、署名が追跡できるか。
- 鍵とストア認証情報が秘密管理にあり、アクセスとローテーション手順があるか。
- 旧版とのAPI・ローカルデータ互換性を試したか。
運用とサポート
- internal、beta、stableの配布先と昇格条件があるか。
- 配布停止、機能フラグ、ロールバック、障害告知の責任者が明確か。
- ユーザーが現在版と診断情報を安全に共有できるか。