2026年4月30日 · 15 分钟阅读

Fastlane: Make and Ship App Store Screenshots (2026 Guide)

fastlane 是一个用于自动执行 iOS 和 Android 应用发布中繁琐环节的 Ruby 工具链。它的三个与截图相关的操作 —— snapshotframeitdeliver —— 覆盖了完整的流水线:在 XCUITest 中驱动您的应用以捕获原始图像,将其包裹在带有营销文案的设备框架中,并将结果推送到 App Store Connect。本指南将通过您运行它配置所需的文件、车道(lane)定义和 CI 工作流,端到端地梳理该流水线。

在结束时,您将拥有:一个使用 Ruby Bundler 锁定版本的设置、一个 App Store Connect API 密钥、一个正常工作的 Snapfile + SnapshotHelper.swift、一个带有每张截图关键字和标题的 Framefile.json、一个专门针对仅上传截图进行调整的 Deliverfile、一个包含四个车道的 Fastfile,以及一个在 macos-26 运行器上运行整个流程的 GitHub Actions 工作流。

1. 前提条件与思维模型

在安装 any Ruby 之前,先理清概念。截图流水线包含三个独立的阶段,每个阶段由不同的 fastlane 操作负责:

  1. 捕获 —— XCUITest 在模拟器上运行,并在您希望记录的瞬间调用 snapshot("01-Home")。fastlane 的 snapshot 操作会启动正确的模拟器,将每个模拟器切换到正确的语言环境(locale),运行测试,并将生成的 PNG 提取到 fastlane/screenshots/<locale>/ 中。
  2. 框架化 —— frameit 读取每个 PNG,根据图像分辨率选择设备框架,可选地合成背景和营销标题,并在原始图像旁写入一个 _framed.png
  3. 上传 —— deliver 遍历截图文件夹,将每张图像与 App Store Connect 显示类型(例如 iPhone 6.9"、iPad 13"),并通过 App Store Connect API 替换可编辑 App Store 版本上的截图集。

每个阶段都是独立可运行的。您可以只截取屏幕截图而不上传它们,也可以为其他工具生成的截图添加框架,或者直接上传预先制作好的截图,而完全无需调用模拟器。

2. 推荐的 fastlane 安装方式:Bundler

不要使用 brew install fastlane。建议在项目中使用 Bundler 锁定项目的 fastlane 版本,以便构建项目的每台机器(您的笔记本电脑、同事的笔记本电脑、CI)都运行相同的版本。在项目根目录下执行:

# system Ruby on macOS 14+ is fine, but rbenv/asdf is cleaner
gem install bundler
bundle init
echo 'gem "fastlane"' >> Gemfile
bundle install --path vendor/bundle

# from now on, run fastlane via:
bundle exec fastlane <lane>

提交 GemfileGemfile.lock。将 vendor/bundle 添加到您的 .gitignore 中。现在,在项目中初始化 fastlane:

bundle exec fastlane init
# choose option 4: "Manual setup"

这会创建一个包含 FastfileAppfilefastlane/ 目录。在 Appfile 中填写您的 bundle 标识符和团队 ID:

# fastlane/Appfile
app_identifier("com.example.myapp")
apple_id("[email protected]")     # only needed if you fall back to legacy auth
team_id("ABCDE12345")           # Developer Portal team ID

3. App Store Connect API 密钥

对于新账户,用户名/密码认证已被弃用,并且对所有人都启用了双重认证保护,这使其在 CI 上无法使用。请改用 App Store Connect API 密钥 。在 App Store Connect → 用户和访问集成App Store Connect API 中:

  1. 生成 API 密钥(每个团队只需执行一次;丢失的 .p8 文件无法重新下载)。
  2. 为其分配 App 管理 角色。开发人员 权限不足以上传截图,而 管理 权限超出了您的实际需求。
  3. 记录 密钥 ID(10 位字符,例如 ABCD1234EF)以及团队的 签发商 ID(页面顶部的 UUID)。
  4. 下载 AuthKey_ABCD1234EF.p8 文件。

fastlane 会从 JSON 文件中读取密钥。将其保存为 fastlane/asc_api_key.json(并将此路径加入 .gitignore 中):

// fastlane/asc_api_key.json
{
  "key_id": "ABCD1234EF",
  "issuer_id": "57246542-96fe-1a63-e053-0824d011072a",
  "key": "-----BEGIN PRIVATE KEY-----\nMIGTAg...truncated...A==\n-----END PRIVATE KEY-----",
  "duration": 1200,
  "in_house": false
}

duration 是每个生成的 JWT 的有效期(秒);Apple 接受的最大值为 1200(20 分钟)。key 字段是 .p8 文件的完整内容,包括 BEGIN/END PRIVATE KEY 行,换行符使用字面量 \n

在 CI 上,切勿将该 JSON 文件提交到仓库中。应将 JSON 内容存为单个机密变量(例如 ASC_API_KEY_JSON),并在运行时写入文件 —— 下文的 GitHub Actions 部分有相关示例。

4. snapshot —— 在 XCUITest 中捕获截图

snapshot 通过在您的 UI 测试目标中注入 un 小型 Swift 辅助工具来工作。该辅助工具会挂载到测试运行时,使测试中对 snapshot("name") 的每一次调用都能截取模拟器屏幕、为其命名,并写入 fastlane 已知路径的磁盘位置。

生成辅助工具

bundle exec fastlane snapshot init

这会创建 fastlane/Snapfile fastlane/SnapshotHelper.swift。将 SnapshotHelper.swift 添加到 Xcode 中您的 UI 测试目标中(将其拖入,确保 "MyAppUITests" 是唯一勾选的目标 —— 切勿将其包含在应用二进制文件中)。

Snapfile

Snapfile 告知 snapshot 应启动哪些设备、在哪些语言环境下运行测试,以及调用哪个 UI 测试方案:

# fastlane/Snapfile

devices([
  "iPhone 17 Pro Max",     # 6.9"  -> 1320 x 2868 (required slot in 2026)
  "iPhone 17 Pro",         # 6.3"  -> 1206 x 2622 (optional, nicer in store listings)
  "iPad Pro 13-inch (M4)", # 13"   -> 2064 x 2752 (required if you ship an iPad build)
])

languages([
  "en-US",
  "de-DE",
  "fr-FR",
  "es-ES",
  "ja",
])

scheme("MyAppUITests")           # the UI-testing scheme that runs Snapshot tests
output_directory("./fastlane/screenshots")
clear_previous_screenshots(true)
override_status_bar(true)        # 9:41, full battery, full signal
concurrent_simulators(true)
stop_after_first_error(true)
number_of_retries(1)

亮点:

  • devices —— 名称必须与 xcrun simctl list devices 输出的名称完全匹配。Apple 每年都会更改名称(例如用 "iPhone 17 Pro Max" 代替 "iPhone 16 Pro Max")。如果设备名称错误,snapshot 会默默跳过它。
  • languages —— 传递类似于 "en-US" 的区域代码或类似于 "ja" 的基础语言代码。每个条目都会在 output_directory 下生成一个文件夹。
  • override_status_bar(true) —— 使用 simctl status_bar override 使每张截图都显示 9:41、满电量和满信号。Apple 技术上并不强制要求这一点,但大多数审核人员都期望看到这样的截图。
  • concurrent_simulators —— 并行运行多个模拟器。这能大幅缩短测试总耗时(大约缩短至设备数的比例),但每个模拟器大约需要消耗 3 GB 内存,因此对资源不足的 CI 运行器来说压力非常大。
  • clear_previous_screenshots —— 在每次运行开始时删除 fastlane/screenshots/<locale>/。如果不配置此项,已移除测试用例的旧截图将会永久堆积。

在 XCUITest 中接入 snapshot

SnapshotHelper 暴露了两个全局函数:setupSnapshot(_:)(每个测试调用一次)和 snapshot(_:)(在您希望记录帧的位置调用)。

// MyAppUITests/MyAppUITests.swift

import XCTest

final class MyAppUITests: XCTestCase {
    override func setUpWithError() throws {
        continueAfterFailure = false
        let app = XCUIApplication()
        setupSnapshot(app)               // injects the locale + screenshot bridge
        app.launchArguments += [
            "-UITests",
            "-AppleLanguages", "(\(Snapshot.deviceLanguage))",
            "-AppleLocale", Snapshot.currentLocale,
        ]
        app.launch()
    }

    func testScreenshots() {
        let app = XCUIApplication()

        snapshot("01-Home")              // tap pattern: drive UI, then snapshot

        app.tabBars.buttons["Library"].tap()
        snapshot("02-Library")

        app.cells.element(boundBy: 0).tap()
        snapshot("03-Detail")

        app.navigationBars.buttons.element(boundBy: 0).tap()
        app.tabBars.buttons["Settings"].tap()
        snapshot("04-Settings")
    }
}

几点实用建议:

  • 通过启动参数传入 -UITests 并检查该参数,用以在应用中禁用数据分析、替换为确定性的种子数据、跳过引导页或模拟网络请求。审核人员(以及未来的您自己)会为此感谢您的。
  • snapshot 会阻塞直到屏幕截图完成,因此您可以在此之后立即执行下一次交互。
  • 如果界面有动画,可在启动参数后添加 UIView.setAnimationsEnabled(false)。截屏时如果有动画进行,会导致图片模糊。
  • 为截图名称加上数字前缀(01-, 02-),以便文件名顺序与 App Store Connect 的显示顺序匹配。deliver 会按字母顺序进行上传。

运行 snapshot

bundle exec fastlane snapshot

# or, equivalently, in a Fastfile lane:
#   capture_ios_screenshots

输出结果会保存在 fastlane/screenshots/<locale>/iPhone 17 Pro Max-01-Home.png 等路径下。Snapshot 还会生成一个 screenshots.html 文件,您可以直接打开它,在一个页面中快速预览所有语言和设备下的截图。

5. frameit —— 添加设备框架与标题

原始截图只是裸露的设备视口。frameit 会将它们包裹在物理设备框架中,并可选地添加背景、营销标题以及上方更小的“关键字”行。

# Download device frames once (cached under ~/.frameit/)
bundle exec fastlane frameit download_frames

# Frame everything in fastlane/screenshots, including subfolders
bundle exec fastlane frameit --use_platform IOS

对于截图目录树中的每一个 foo.pngframeit 都会在其旁边写入一个 foo_framed.png。原始文件会被保留;如果存在框架版本,deliver 会自动读取框架版本(不存在时则回退到原始版本)。

Framefile.json

默认的框架看起来就像开发测试图片 —— 黑色外框、没有背景、没有文本。您可以通过 fastlane/screenshots/Framefile.json 来配置它们:

// fastlane/screenshots/Framefile.json
{
  "device_frame_version": "latest",
  "default": {
    "keyword": {
      "font": "./fonts/Inter-SemiBold.ttf",
      "color": "#FFFFFF",
      "padding": 50
    },
    "title": {
      "font": "./fonts/Inter-Bold.ttf",
      "color": "#FFFFFF"
    },
    "background": "./background.png",
    "padding": 80,
    "show_complete_frame": false,
    "title_below_image": false,
    "stack_title": true
  },
  "data": [
    {
      "filter": "Home",
      "keyword": { "color": "#9F7AEA" },
      "frame": "BLACK"
    },
    {
      "filter": "Settings",
      "keyword": { "color": "#3B82F6" },
      "frame": "WHITE"
    }
  ]
}

关键字段:

  • background —— 被包围的设备所合成到的背景 PNG。尺寸应宽于您输出的最大截图。frameit 默认会垂直居中设备;title_below_imageshow_complete_frame 用于控制文本与外框的交互方式。
  • data[] —— 针对特定截图的覆盖配置,以截图文件名的子字符串作为过滤键。上面的第二条仅适用于名称中带有 “Settings” 的文件。可以用于针对不同的功能行进行不同的色彩搭配。
  • frame —— 覆盖匹配文件的设备框架颜色。frameitFramefile.json 中识别的值包括 BLACKWHITEGOLDROSE_GOLD。框架素材本身会在执行 fastlane frameit download_frames 时从 Apple 营销资源的 Sketch 文件中下载。

分语言环境的 title.strings 和 keyword.strings

营销文案来自于两个平行的分语言环境 strings 文件 —— 标题使用 title.strings,上方较小的标签使用 keyword.strings。键为不带扩展名或设备前缀的截图文件名:

/* fastlane/screenshots/en-US/title.strings */

"01-Home"     = "Track every match.\nIn one tap.";
"02-Library"  = "Your full history,\nalways with you.";
"03-Detail"   = "Drill into any session.";
"04-Settings" = "Sync across all devices.";
/* fastlane/screenshots/en-US/keyword.strings */
/* keywords are rendered above the title, smaller */

"01-Home"     = "FAST";
"02-Library"  = "ORGANIZED";
"03-Detail"   = "DEEP";
"04-Settings" = "EVERYWHERE";

翻译文件放入 fastlane/screenshots/de-DE/title.stringsfastlane/screenshots/de-DE/keyword.stringsfastlane/screenshots/ja/title.strings 等路径下。换行使用 \n。缺失翻译的语言环境会直接显示未翻译的截图(不渲染标题) —— 这里没有自动退回到英文的机制。

字体

将 TTF 或 OTF 文件放入 fastlane/screenshots/fonts/ 中,并在 Framefile.json 中使用相对路径进行引用。支持可变字体。如果您引用了不存在的字体,frameit 会默默地退回到默认的无衬线字体,而生成的结果可能在没有任何警告的情况下看起来是错的。

6. deliver —— 上传到 App Store Connect

deliver 遍历截图文件夹,将每个 PNG 与 App Store Connect 显示类型进行匹配,然后通过 App Store Connect API 替换当前可编辑版本上的截图集。配置好 API 密钥认证和精简的 Deliverfile 后,上传步骤只需一条命令即可搞定。

目录布局

deliver 需要平铺的分语言环境目录结构 —— 不能包含设备子文件夹。显示类型是根据图像分辨率检测的(在有歧义时,会根据 snapshot 已经加入的文件名设备前缀进行检测):

fastlane/screenshots/
├── en-US/
│   ├── iPhone 17 Pro Max-01-Home_framed.png       # 6.9" iPhone
│   ├── iPhone 17 Pro Max-02-Library_framed.png
│   ├── iPad Pro 13-inch (M4)-01-Home_framed.png   # 13" iPad
│   ├── title.strings
│   └── keyword.strings
├── de-DE/
│   └── ...
└── Framefile.json

Deliverfile

# fastlane/Deliverfile

app_identifier("com.example.myapp")
team_id("ABCDE12345")

# Auth via App Store Connect API key (preferred over username/password).
api_key_path("./fastlane/asc_api_key.json")

# Where to read screenshots / metadata from.
screenshots_path("./fastlane/screenshots")
metadata_path("./fastlane/metadata")

# Only push screenshots — leave the binary, pricing, IAPs, etc. alone.
skip_binary_upload(true)
skip_metadata(false)
skip_screenshots(false)
skip_app_version_update(true)

# Don't ask for confirmation in CI.
force(true)
overwrite_screenshots(true)
run_precheck_before_submit(false)
submit_for_review(false)

# Match a screenshot file against the right App Store display family.
# Useful when fastlane's resolution-based detection is ambiguous.
ignore_language_directory_validation(false)

最重要的参数:

  • skip_binary_upload —— 如果不配置此项,deliver 会寻找 IPA 包,如果没有则会拒绝运行。
  • skip_metadata —— 如果您只想更新截图且没有 fastlane/metadata/ 目录,可将其设为 true。设为 false 则可以在同一次调用中一并提交本地化的标题、描述、关键字和促销文本。
  • force(true) —— 跳过 deliver 在推送前显示的确认提示。在 CI 上为必填项。
  • overwrite_screenshots(true) —— 在上传新图前清空每个显示类型中已有的截图。如果不开启,新上传的图会追加在老图后面,直到达到 10 张的限制,然后报错。
  • run_precheck_before_submit(false) —— precheck 会扫描元数据中是否有风险词汇(“Beta”、竞品名称、敏感词等)。这在提交审核前很有用,但对于仅更新截图的操作来说并不适用。

干跑测试与正式发布

# verify which display families and locales will be touched, no upload
bundle exec fastlane deliver --verify_only

# inspect the resolved configuration
bundle exec fastlane deliver --print_resolved_options

# real upload
bundle exec fastlane deliver

在第一次实际上传时,deliver 会在 fastlane/preview.html 中生成一个 HTML 预览文件,并暂停等待确认(除非设置了 force(true))。在引入新设备族时,请务必先打开预览文件查看,因为这是发现显示类型不匹配的最佳时机。

7. 完整的 Fastfile 文件

这一个文件定义了四个车道,涵盖了捕获、框架化、捕获+框架化以及完整发布。本地开发使用一个车道,而 CI 运行则使用另一个车道。

# fastlane/Fastfile

default_platform(:ios)

platform :ios do
  desc "Capture screenshots with snapshot"
  lane :screenshots do
    capture_ios_screenshots         # alias for snapshot
  end

  desc "Frame screenshots with frameit"
  lane :frame do
    frame_screenshots(
      path: "./fastlane/screenshots",
      use_platform: "IOS"
    )
  end

  desc "Build framed screenshots end-to-end"
  lane :build_marketing do
    capture_ios_screenshots
    frame_screenshots(path: "./fastlane/screenshots", use_platform: "IOS")
  end

  desc "Upload screenshots to App Store Connect"
  lane :upload_screenshots do
    upload_to_app_store(             # alias for deliver
      skip_binary_upload: true,
      skip_metadata: true,
      skip_app_version_update: true,
      force: true,
      overwrite_screenshots: true,
      run_precheck_before_submit: false
    )
  end

  desc "Full release pipeline: capture, frame, upload"
  lane :ship_screenshots do
    capture_ios_screenshots
    frame_screenshots(path: "./fastlane/screenshots", use_platform: "IOS")
    upload_to_app_store(
      skip_binary_upload: true,
      skip_metadata: true,
      skip_app_version_update: true,
      force: true,
      overwrite_screenshots: true
    )
  end
end

capture_ios_screenshotsframe_screenshotsupload_to_app_store 分别是 snapshotframeitdeliver 的规范别名。短名称仍然有效,但长名称更加清晰,且不会遮蔽 Ruby 关键字。

8. 在 GitHub Actions 上配置 CI

截图速度较慢(5 种语言 × 3 款设备通常需要 15 分钟),但可以通过模拟器并行进行。一个运行在 macos-26 上的并行模拟器工作流通常就足够了。

# .github/workflows/screenshots.yml

name: Screenshots

on:
  workflow_dispatch:
  push:
    paths:
      - "fastlane/**"
      - "MyAppUITests/**"

jobs:
  screenshots:
    runs-on: macos-26       # Xcode 26.x default; macos-15 also works with explicit xcode-select
    timeout-minutes: 90
    env:
      LC_ALL: en_US.UTF-8
      LANG: en_US.UTF-8
      FASTLANE_SKIP_UPDATE_CHECK: "1"
      FASTLANE_HIDE_CHANGELOG: "1"

    steps:
      - uses: actions/checkout@v4

      - name: Select Xcode
        run: sudo xcode-select -s /Applications/Xcode_26.3.app

      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"
          bundler-cache: true

      - name: Write App Store Connect API key
        run: |
          mkdir -p fastlane
          echo "$ASC_API_KEY_JSON" > fastlane/asc_api_key.json
        env:
          ASC_API_KEY_JSON: ${{ secrets.ASC_API_KEY_JSON }}

      - name: Capture, frame, upload
        run: bundle exec fastlane ios ship_screenshots

      - name: Archive framed screenshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: screenshots
          path: fastlane/screenshots

让 CI 运行更可靠的技巧:

  • 锁定 Xcode 版本。 使用明确的路径调用 sudo xcode-select -s。GitHub 托管的运行器附带了多个 Xcode 版本,默认版本是他们本月选定的版本。
  • 锁定运行器镜像。 使用类似 macos-26macos-15 的带版本号镜像,不要使用 macos-latest。在版本发布前三周遇到运行器升级,绝对是您最不想面对的“惊喜”。
  • 缓存 Bundler 安装。setup-ruby 中使用 bundler-cache: true 可以让每次运行节省一到两分钟。
  • 从单个机密变量中写入 API 密钥。key_idissuer_idkey 存为多个独立的机密变量更方便密钥轮换,但更容易配置出错。对于小团队来说,使用单个 JSON 格式的机密变量就足够了。
  • 将框架化的截图上传为工件,即使上传步骤失败也是如此。在重新运行之前,您几乎总是想检查一下究竟生成了什么图。

9. 常见错误及解决方法

"Could not find a device matching..."

Snapshot 中的设备名称必须与 xcrun simctl list devicetypes 完全一致。Apple 每年都会发布最新的旗舰设备,而 Apple 基于年份的版本命名逻辑意味着工具链更新换代非常快。"iPhone 17 Pro Max"Xcode 26(2025 年秋季发布)一同推出;在 Xcode 16 上,6.9 英寸的设备名为 "iPhone 16 Pro Max"。在每次 Xcode 升级后,建议重新运行 xcrun simctl list devicetypes | grep iPhone 并更新您的 Snapfile

"Unable to verify upload" / 401 Unauthorized

您的 JWT 在上传中途过期、API 密钥被吊销或其角色权限被降级。请检查 asc_api_key.json 中的 duration 是否小于等于 1200,然后重新签发密钥。

"App Store Connect is locked"

您正在上传的版本正处于“正在审核(In Review)”或“等待开发者发布(Pending Developer Release)”状态。在这些状态下,截图是只读的。请创建一个新版本(“准备提交”状态)并重新运行。

截图进入了错误的显示类型

deliver 是根据图像分辨率来匹配显示类型的。如果您导出了一张 1320 × 2868 分辨率的 6.9 英寸 iPhone 截图,它会落入 6.9 英寸的插槽;如果您将其缩放到了 1284 × 2778 分辨率,它会落入旧版的 6.5 英寸插槽。如果您的应用版本中同时存在这两种显示类型,请在文件名中指明设备系列 —— 也就是 snapshot 已经自动生成的文件名前缀。手动导出的截图往往会漏掉这个前缀。

"Screenshot has alpha channel" / 意外的透明度

App Store Connect 历史上一直拒绝带透明通道的 PNG 图像,并且当 deliver 发现 Alpha 通道时仍然会发出警告。虽然 Apple 当前的截图规范页面不再明确声明此规则,但去掉 Alpha 通道是最稳妥的做法。可以使用 sips -s format png 配合 PNG 色彩配置处理该文件,或者重新导出为不带 Alpha 通道的文件。frameit 合成的输出始终是不透明的;但如果您的根视图是不透明的,原始的 simctl io ... screenshot 输出仍然可能会包含 Alpha 通道。

"Locale ru-RU does not exist for this app"

deliver 只会上传到您当前版本中已经创建 of App Store Connect 语言环境。请先在 App Store Connect 后台添加该语言环境(或在 deliver 中设置 force_create_app(true) + 元数据),然后重新运行。

并行模拟器吃光了所有内存

每个在调出键盘状态下启动的 iPhone 17 Pro Max 模拟器都会消耗大约 2.5 GB 内存。在 16 GB 内存的 MacBook 上同时运行三个模拟器会导致频繁使用 Swap 并在测试中途崩溃。建议在本地将 concurrent_simulators(false) 设为 false,将并行测试留给配置更高的 CI 运行器来执行。

10. 何时 fastlane 会显得大材小用

在以下情况下,fastlane 的截图流水线非常好用:

  • 您已经拥有一个 UI 测试目标,且团队能够熟练维护 XCUITest 桩数据。
  • 您希望将截图作为 CI 构建产物,在每次发布时重新生成。
  • 您支持多语言本地化,且希望通过代码一次性定义好版式,而不是针对每种语言单独绘制。

在以下情况下,它不是一个好选择:

  • 您想对每张截图进行极致的艺术设计 —— 排版、构图、装饰性元素等。frameit 是一个模板引擎,而非设计工具。
  • 您需要发布某项在应用中尚未实现、或仅在测试目标无法触及的 Feature Flag 之后的营销级精美截图
  • 您是一名独立开发者,宁愿在 Mac 或 iPad 应用中设计一次并直接点击 上传。维护 Ruby 工具链、XCUITest 以及锁定 Xcode 版本带来的实际维护成本是相当高的。

对于设计优先的工作流,Screenshot Bro 涵盖了相同的领域 —— 本地化布局、设备框架、使用相同 API 密钥的一键上传 App Store Connect,且无需任何复杂的 XCUITest 配置。

一页纸备忘单

# Setup (once)
bundle init && echo 'gem "fastlane"' >> Gemfile && bundle install
bundle exec fastlane init
bundle exec fastlane snapshot init
bundle exec fastlane frameit download_frames

# Per release
bundle exec fastlane ship_screenshots

这就是完整的流水线。安装时执行两个命令,每次发布时执行一个命令。复杂性都被封装在了上述配置文件中,一旦配置好,它们几乎不需要改动。

想知道是完全自己搭建这套系统,还是使用 Mac 桌面端应用来完成同样的工作?您可以查阅 Fastlane snapshot 对比 Screenshot Bro 来了解两者的直接对比和“混合使用”工作流。

想要无需 XCUITest 流水线的相同上传流程?只需一款 Mac 和 iPad 应用即可设计并交付 App Store 截图。

在 App Store 获取

查看演示