将构建发送到 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)。记录是容纳应用在应用商店中展示的所有信息的容器,包括应用名称、描述、截图、价格等。

应用记录可以在实际首次提交前再创建。在一次性准备阶段,只需提前了解"需要确定哪些项目、如何确定"即可。特别是下面的 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 — 仅供你自己使用的内部标识字符串,不会在应用商店中公开,可自由设定(如 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(截图、描述、应对审核)是在此一次性准备之上进行的独立工作,将在另一篇文章中介绍。

参考资料