
如果你的 App 只有一种语言、一年改两次截图,手动截图完全够用,参考用 iOS 模拟器导出截图即可。但只要满足下面任意一条,自动化就很划算:
fastlane 是开源的移动端发布工具链,和截图相关的是三个动作:
| 动作 | 作用 | 平台 |
|---|---|---|
snapshot(capture_screenshots) | 通过 UI Test 在多个模拟器、多种语言下自动截图 | iOS |
frameit(frame_screenshots) | 给截图套设备边框,可加背景和标题 | iOS / Android |
deliver(upload_to_app_store) | 把截图和元数据上传到 App Store Connect | iOS |
screengrab / supply | Android 的截图与上传对应工具 | Android |
在项目根目录运行:
fastlane snapshot init
它会生成两个文件:
Snapfile:配置设备、语言、输出目录;SnapshotHelper.swift:需要拖进你的 UI Test target。然后在 UI Test 里调用:
let app = XCUIApplication()
setupSnapshot(app)
app.launch()
// 导航到要截的页面
snapshot("01Home")
app.buttons["Search"].tap()
snapshot("02Search")
snapshot("名称") 的名称前缀建议用数字,这样上传顺序就是截图顺序。
devices([
"iPhone 17 Pro Max",
"iPhone 17",
"iPad Pro 13-inch (M4)"
])
languages(["en-US", "zh-Hans", "ja"])
scheme("YourAppUITests")
output_directory("./fastlane/screenshots")
clear_previous_screenshots(true)
override_status_bar(true)
几点说明:
xcrun simctl list devices 查看。选什么设备取决于你要覆盖的截图尺寸档,必传档位见必传截图 FAQ。override_status_bar(true) 会把状态栏设成整洁的时间、满电和满信号,手动处理方法见状态栏清理指南。运行:
fastlane snapshot
完成后截图按语言放在 fastlane/screenshots/<语言>/ 下,并生成一个 HTML 预览页方便检查。
frameit 依赖 ImageMagick,需要先安装(macOS 上 brew install imagemagick)。然后:
fastlane frameit
首次运行会下载设备边框素材。要加背景和标题,在 fastlane/screenshots/ 下放一个 Framefile.json:
{
"default": {
"keyword": { "color": "#FFD60A" },
"title": { "color": "#FFFFFF" },
"background": "./background.png",
"padding": 50,
"show_complete_frame": true
},
"data": [
{ "filter": "01Home", "keyword": { "color": "#FFD60A" } }
]
}
每种语言的标题文案写在对应语言文件夹的 title.strings 和 keyword.strings 里,键名对应截图名称。
frameit 的局限要心里有数:
| 局限 | 影响 | 对策 |
|---|---|---|
| 新机型边框更新可能滞后 | 最新设备可能没有可用边框 | 用相近机型或改用其他工具加壳 |
| 版式自由度有限 | 只能「标题 + 带壳截图 + 背景」 | 复杂版式在设计工具里做 |
| 加了边框后像素变化 | 输出尺寸可能不再是商店接受的精确值 | 上传前核对尺寸 |
最后一点很关键:带框图片必须仍然是商店接受的像素尺寸,否则 Connect 会报尺寸错误。很多团队的做法是 snapshot 只负责产出原生截图,再交给设计工具或在线带壳工具出最终图,例如 appshotmaker.com。
fastlane deliver --skip_binary_upload --skip_metadata --overwrite_screenshots
--skip_binary_upload:只传素材,不传构建;--skip_metadata:不覆盖名称、描述等文本;--overwrite_screenshots:先删除 Connect 上已有截图再上传。deliver 会按 fastlane/screenshots/<语言>/ 的目录结构识别语言,并根据图片像素判断设备档位,所以像素不对的图会直接失败。上传前先确认 App Store Connect API Key 或账号登录方式已配置好。
| iOS | Android 对应 | 说明 |
|---|---|---|
| snapshot | screengrab | 通过 Instrumentation Test 截图,需加 tools.fastlane:screengrab 依赖 |
snapshot("name") | Screengrab.screenshot("name") | 在测试代码里调用 |
| deliver | supply | 上传到 Google Play,截图放在 metadata/android/<语言>/images/ 下 |
Google Play 截图规格见 Google Play 截图要求。
| 现象 | 原因 | 处理 |
|---|---|---|
| 提示找不到设备 | Snapfile 里的设备名与模拟器名不一致 | 用 xcrun simctl list devices 复制准确名称 |
| 截到加载中的画面 | 截图前界面还没渲染完 | 截图前等待目标元素出现 |
| 某语言截图全是英文 | App 未按启动语言加载资源 | 检查本地化文件和 setupSnapshot 是否调用 |
| 上传提示尺寸错误 | frameit 输出尺寸变化 | 核对像素,必要时改用无框原图 |
| CI 上截图失败 | 模拟器未预装或首次启动太慢 | 预先创建并启动一次模拟器 |