將建置傳送到 App Store 的路徑

第 1 篇建立了 MAS 建置目標,第 2 篇建立了區分兩個渠道的設定檔和程式碼分支。FocusTimer MAS 目標現在已成為可以上架 App Store 的形態。

本篇(最終篇)將搭建將該建置上傳到 App Store Connect 的路徑,並介紹如何驗證兩個渠道在未來不會被破壞,從而收尾本系列。

與第 1、2 篇相同,FocusTimercom.example.FocusTimer.mas、Team ID ABCDE12345 等均為範例值。

第 1 步 — 用於上傳的 ExportOptions-MAS.plist

在直接分發系列中,我們提到將封存匯出為分發用時,xcodebuild -exportArchive 指令會讀取 ExportOptions.plist。MAS 渠道需要獨立的匯出設定檔。

在專案的發布目錄中建立 ExportOptions-MAS.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>app-store</string>
    <key>destination</key>
    <string>upload</string>
    <key>signingStyle</key>
    <string>automatic</string>
    <key>teamID</key>
    <string>ABCDE12345</string>
</dict>
</plist>

各金鑰的含義如下:

  • method = app-store — 表示將此建置匯出為 Mac App Store 渠道用途,與直接分發渠道的 developer-id 形成對比。
  • destination = uploadxcodebuild -exportArchive 會將匯出的產物直接上傳到 App Store Connect,無需像以前那樣經過 Transporter 或其他上傳工具。
  • signingStyle = automatic — Xcode 會自動匹配 Mac App Store 佈建設定檔和 Apple Distribution 憑證。
  • teamID — 你的 Apple Developer Team ID。

建立此檔案一次後,即可在所有 MAS 發布中重複使用。保留直接分發用的 ExportOptions.plist 不變,將此檔案與其並排放置。

第 2 步 — 在 App Store Connect 註冊應用程式記錄

要實際提交應用程式審核,App Store Connect 中必須有應用程式記錄 (record)。記錄是容納應用程式在 App Store 中展示的所有資訊的容器,包括應用程式名稱、描述、截圖、價格等。

應用程式記錄可以在實際首次提交前再建立。在一次性準備階段,只需提前了解「需要確定哪些項目、如何確定」即可。特別是下面的 Primary Language,一旦設定便難以更改,請提前慎重決定。

在 App Store Connect → My Apps+New App 中填寫以下內容:

  • Platform — 選擇 macOS
  • Primary Language(主要語言) — ⚠️ 最需要慎重決定的項目。 一旦設定,透過自助服務更改非常困難。若計劃在多個國家發布,通常將**英語(英語,美國)**設為主要語言,因為主要語言是「特定國家沒有對應翻譯時顯示的基準語言」。
  • App Name(應用程式名稱) — 以主要語言為基準的名稱(如 FocusTimer)。其他語言的名稱稍後透過各語言在地化 (localization) 單獨新增。例如,可以讓韓語使用者看到韓語名稱,日語使用者看到日語名稱。
  • Bundle ID — 從下拉選單中選擇 com.example.FocusTimer.mas。這正是第 1 篇中註冊的那個 ID。請不要與直接分發用 Bundle ID(com.example.FocusTimer)混淆——必須選擇帶有 .mas 後綴的那個。
  • SKU — 僅供你自己使用的內部識別字串,不會在 App Store 中公開,可自由設定(如 focustimer-mas-001)。

應用程式分類必須與第 2 篇中在 Info.plistLSApplicationCategoryType 中填寫的值一致。若在 plist 中填寫了 public.app-category.productivity(效率工具),則在 App Store Connect 中也必須選擇「效率工具」類,否則審核階段會出現不符警告。

第 3 步 — 驗證兩個渠道的建置

現在同一程式碼庫擁有了兩個建置目標。這伴隨著維護成本。平時只建置直接分發渠道,MAS 目標可能在不知不覺間已經損壞。例如,新增程式碼時遺漏了 #if canImport(Sparkle) 分支,導致只有 MAS 建置編譯失敗。

防止這種情況最可靠的方法是每次製作直接分發發布時,同時也對 MAS 目標進行封存。若建置成功,則說明兩個渠道的分支完好無損。

xcodebuild -project FocusTimer.xcodeproj -scheme "FocusTimer MAS" \
  -configuration Release \
  -destination 'platform=macOS' \
  -archivePath build/FocusTimer-MAS.xcarchive \
  archive

若輸出末尾顯示如下內容,則 MAS 分支正常:

** ARCHIVE SUCCEEDED **

建議將此指令嵌入發布自動化腳本的最後一步,使其在每次發布時自動執行。即使當時並未實際將 MAS 建置上傳到 App Store,僅確認封存是否成功就足以保證兩個渠道的分支沒有被破壞。

系列小結 — MAS 發布一次性準備完成

歷經三篇的 Mac App Store 發布一次性準備工作全部完成。現在你已經準備好以下內容:

  • (第 1 篇) MAS 專用 Bundle ID + 複製的 FocusTimer MAS 建置目標
  • (第 2 篇) MAS 專用 entitlements 和 Info.plist + 建置設定 + #if canImport(Sparkle) 程式碼分支
  • (第 3 篇) 用於上傳的 ExportOptions-MAS.plist + App Store Connect 記錄註冊方法 + 兩個渠道建置驗證

至此,同一個 macOS 應用程式同時具備了直接分發(Developer ID)和 Mac App Store 兩個渠道。核心結構再次總結如下:

  • 共享同一程式碼庫,但分為兩個建置目標
  • 直接分發目標包含 Sparkle,MAS 目標排除 Sparkle。
  • 兩者的差異透過獨立的 entitlements、Info.plist、ExportOptions 檔案和 #if canImport(Sparkle) 程式碼分支來體現。

初次設定時工作量較大,但這同樣是一次建置、持續重複使用的結構。之後只需在製作直接分發發布時同時封存 MAS 建置,確認分支是否仍然正常即可。實際提交 App Store(截圖、描述、應對審核)是在此一次性準備之上進行的獨立工作,將在另一篇文章中介紹。

參考資料