もう一つの配布チャネル — Mac App Store

前のシリーズでは、macOS アプリを Developer ID で直接配布する事前設定を扱いました。証明書、公証、Sparkle 自動アップデート、アップデートフィードのホスティングまで整えることで、App Store を経由せずに .dmg ファイルを直接ダウンロードさせることができるようになりました。

今回のシリーズでは、同じアプリを Mac App Store (MAS) にも出すための事前設定を扱います。2 つの配布方法はどちらか一方を選ぶものではありません。一つのアプリを直接配布チャネルと App Store チャネルの両方で同時に運用することができます。App Store は決済・返金・検索露出を Apple が代わりに処理してくれ、ユーザーの信頼度も高いという利点があり、直接配布と並行して運用するケースが多くあります。

このシリーズは、アプリがすでに Developer ID で直接配布されており、Sparkle 自動アップデートが組み込まれているという前提から始まります。その設定は Developer ID 直接配布シリーズの 1 編から扱っています。まだ読んでいない場合は先に読むことをお勧めします。

なぜ MAS には「もう一つのターゲット」が必要なのか

直接配布のアプリには Sparkle 自動アップデートが含まれています。アプリが自らアップデートフィードを確認し、新しいバージョンをダウンロードして自分自身を置き換える機能です。

しかし、Mac App Store の審査規則はこの動作を禁止しています。App Store に出品されたアプリは、外部からコードをダウンロードして自分自身を更新してはならず、アップデートは App Store を通じてのみ行われなければなりません。つまり、MAS に出すビルドには Sparkle が含まれていてはいけません。

しかし、直接配布用のビルドには Sparkle が必ず必要です。1 つのビルド成果物で両方の要件を同時に満たすことはできません。そのため、解決策はこうなります。

同じコードベース、2 つのビルドターゲット。

チャネルビルドターゲットSparkle配布先
Developer IDFocusTimer含む直接配布 (.dmg)
Mac App StoreFocusTimer MAS除くApp Store

ソースコードは一つで共有しながら、ビルドターゲットを 2 つに分けて、片方にだけ Sparkle をリンクするわけです。このシリーズでは、その 2 つ目のターゲット (FocusTimer MAS) を作成する事前設定を扱います。

このシリーズで作るもの

3 編にわたって、以下を整えます。

  • (1 編、この記事) MAS 専用の Bundle ID 登録 + Xcode ビルドターゲットの複製
  • (2 編) 2 つのチャネルを分ける設定ファイル (entitlements・Info.plist) とコード分岐
  • (3 編) アップロード用 ExportOptions-MAS.plist + App Store Connect への登録 + ビルド検証

シリーズを終えた時点で、次のものが揃っているはずです。

  • Apple Developer Portal に登録された MAS 専用の Bundle ID
  • Sparkle の依存関係を外した FocusTimer MAS ビルドターゲット
  • MAS 専用の entitlements ファイルと Info.plist ファイル
  • #if canImport(Sparkle) で分岐されたコード
  • App Store アップロード用の ExportOptions-MAS.plist

サンプルアプリ — FocusTimer

前のシリーズと同様、架空の macOS アプリ FocusTimer (集中時間を管理するシンプルなタイマーアプリ) を例として使います。FocusTimer、バンドル識別子 com.example.FocusTimer、Team ID ABCDE12345 などはすべてサンプル値です。実際には、ご自身のアプリとアカウント情報に置き換えて使用してください。

この記事は Xcode 26 を基準に書いています。

ステップ 1 — MAS 専用の Bundle ID の登録

なぜ別の Bundle ID が必要か

直接配布チャネルの Bundle ID が com.example.FocusTimer の場合、MAS チャネルには異なる Bundle ID を使います。

チャネルBundle ID
Developer IDcom.example.FocusTimer
Mac App Storecom.example.FocusTimer.mas

既存の Bundle ID の末尾に .mas を付ける形です。なぜわざわざ分けるのでしょうか?

  • 1 台の Mac 上で 2 つのチャネルが共存できる — Bundle ID が同じだと macOS が 2 つのアプリを同じアプリとして認識して競合します。異なれば、直接配布版と App Store 版を同じマシンに同時にインストールできます (開発・テストに便利です)。
  • UserDefaults ドメインの分離 — 設定の保存領域が Bundle ID 単位で分かれるため、2 つのチャネルの設定が混在しません。
  • Launch Services の競合回避 — macOS が「このアプリを開いて」などのリクエストをどのアプリに送るか決定する際の混乱を防ぎます。

直接配布チャネルの Bundle ID はそのまま維持してください。既存ユーザーを識別する基準となるため、変更してはいけません。MAS 用に新しい ID をもう一つ登録するのです。

登録手順

  1. developer.apple.com/account にサインイン (Apple Developer Program アカウント)
  2. Certificates, Identifiers & Profiles → 左メニューの Identifiers+ ボタン
  3. App IDs を選択 → Continue → タイプは AppContinue
  4. Description: わかりやすい名前を入力 (例: FocusTimer MAS)
  5. Bundle ID:
    • Explicit (明示的) を選択
    • 入力値: com.example.FocusTimer.mas
  6. Capabilities: アプリが使わない機能はすべてオフにします。iCloud、プッシュ通知、アプリ内課金、Sign in with Apple などを使わない場合は何も有効にしなくて構いません。(App Sandbox は Xcode 側の entitlements が処理するため、ここで有効にする必要はありません。)
  7. ContinueRegister

検証

Identifiers リストに FocusTimer MAS — com.example.FocusTimer.mas の項目が表示されれば登録完了です。

ステップ 2 — Xcode ビルドターゲットの複製

次に、Xcode プロジェクトに FocusTimer MAS ビルドターゲットを作成します。最も速い方法は既存のターゲットを複製することです。

2-1. ターゲットの複製 (Duplicate)

  1. Xcode で FocusTimer.xcodeproj を開く
  2. Project navigator (左パネル) の一番上にあるプロジェクトアイコン (青色) をクリック
  3. 中央の編集エリアの TARGETS リストで FocusTimer を右クリック → Duplicate
  4. ダイアログが表示されたら Duplicate Only を選択
  5. 新しいターゲット名が FocusTimer copy として作成されます。名前をダブルクリックして FocusTimer MAS に変更
  6. 「新しい Scheme を追加しますか?」というプロンプトが表示されたら Activate を選択 (または後で Manage Schemes から追加)

2-2. Bundle ID の即時変更

複製直後に最初にすべきことは Bundle ID の交換です。そのままにしておくと、2 つのターゲットが同じ ID を持つことになります。

TARGETS → FocusTimer MAS → General → Identity → Bundle Identifier をステップ 1 で登録した値に変更します。

com.example.FocusTimer.mas

2-3. 重要な落とし穴 — Duplicate が残す「整理作業」

ここがこの編で最も注意が必要な部分です。Xcode の Duplicate Target は**「安全なデフォルト」**で動作しますが、その安全さがかえって手作業の後片付けを残します。複製直後に次の 4 つを確認する必要があります。

① 新しいターゲットがソースファイルを含むようにする

Duplicate は安全のために新しいターゲットからすべてのソースファイルを自動的に除外します。そのままにしておくと、FocusTimer MAS ターゲットは空のシェルとなり、ビルドしてもコードが何も含まれません。新しいターゲットが既存のソースファイルを再び含むよう、メンバーシップを整理する必要があります。

② MAS ターゲットから Sparkle の依存関係を削除する

Duplicate は元のターゲットの Swift Package の依存関係をそのままコピーします。そのため、FocusTimer MAS ターゲットにも Sparkle が引き継がれます。このシリーズの出発点が「MAS ビルドには Sparkle があってはならない」だったため、MAS ターゲットのパッケージ依存関係リストと Frameworks ビルドフェーズから Sparkle を削除します。

③ 一時的な Info.plist ファイルの整理

Duplicate は FocusTimer copy-Info.plist のような一時的な Info.plist ファイルを作成します。2 編で MAS 専用の Info.plist を別途作成するため、これらの一時ファイルはプロジェクト参照と実際のファイルの両方を削除します。

④ MAS ターゲットのビルド設定の更新

バンドル識別子、Info.plist のパス、entitlements のパスなどのビルド設定を MAS 用に合わせる必要があります。この作業は2 編で専用の設定ファイルを作成した後にまとめて行います。

①・②は Xcode UI のターゲットメンバーシップ・パッケージ依存関係の画面でほとんど処理できますが、複製過程で残った重複参照がきれいに削除されない場合、プロジェクトファイル (.pbxproj) を直接確認する必要があることもあります。整理が完了したと判断したら、2 つのターゲットをそれぞれビルドしてみて、MAS ターゲットのビルドで import Sparkle が壊れるかどうか確認するのが最も確実な検証です (2 編でこのコード分岐を扱います)。

1 編まとめ

ここまで進んだ方は、以下が揃っているはずです。

  • ✅ Apple Developer Portal に登録された MAS 専用 Bundle ID (com.example.FocusTimer.mas)
  • ✅ 複製によって作成された FocusTimer MAS ビルドターゲット
  • ✅ 複製が残した整理作業 (ソースのメンバーシップ・Sparkle の依存関係・一時ファイル) への理解

ターゲットという「器」は作られました。しかし、このターゲットはまだ事実上 FocusTimer のコピーであり、本当の意味での「MAS 用」にはなっていません。MAS ビルドは直接配布ビルドとは異なる権限 (entitlements)異なる Info.plist を使わなければならず、コードも Sparkle がなくても壊れないよう分岐させる必要があります。

次の編では、2 つのチャネルを分ける設定ファイルとコード分岐を扱います。