@chengyu08/ipa-cli
v0.2.0
Published
CLI for IPA review risk analysis, similarity checks, baseline scanning, and static asset review.
Maintainers
Readme
screenshots 工作区说明
本目录由 ipa-cli screenshots init-config 初始化,目的是让你可以直接开始准备原始截图、编辑渲染配置并输出 App Store 上架图。
如果你当前是在仓库源码里调试,也可以把下面示例里的 ipa-cli 替换成 npx tsx src/cli.ts。
目录里有什么
screenshot.config.json:渲染配置文件,screenshots render会直接读取它。raw/:原始截图目录,建议按语言拆分子目录。README.screenshots.md:当前说明文档。
默认初始化后的目录结构如下:
.
|-- README.screenshots.md
|-- screenshot.config.json
`-- raw/
`-- zh-Hans/
`-- 01_home.png这个流程是怎么做的
screenshots 模块的链路是:
原始截图(raw)
-> 编辑 screenshot.config.json
-> ipa-cli screenshots render
-> 输出 screenshots/<locale>/<target>/*.png
-> ipa-cli screenshots check 做结果校验也就是说,这个命令不会自动操作 App 页面。你需要自己准备原始截图,常见方式有两种:
- 用
ipa-cli screenshots from-simulator从 iOS 模拟器截取页面图。 - 自己准备营销图、设计图或真实页面截图,然后放进
raw/目录。
推荐使用步骤
- 把原始截图放到
raw/zh-Hans/目录,例如raw/zh-Hans/01_home.png。 - 打开
screenshot.config.json,按你的语言、设备和文案修改配置。 - 先执行 dry-run,确认路径和渲染计划没问题。
- 正式渲染到输出目录。
- 用
screenshots check校验最终目录。
配置文件长什么样
默认配置如下:
{
"version": 1,
"platform": "ios",
"defaults": {
"backgroundPresets": {},
"background": {
"type": "solid",
"color": "#F5F7FA"
},
"titleColor": "#111827",
"subtitleColor": "#4B5563",
"fontFamily": "Inter, Arial, sans-serif",
"orientation": "portrait",
"deviceWidthRatio": 0.76,
"deviceFrame": {
"preset": "iphone-dark-01"
}
},
"targets": [
"iphone-6.5"
],
"locales": [
"zh-Hans"
],
"frames": [
{
"name": "01_home",
"raw": "raw/{locale}/01_home.png",
"title": "快速完成估价",
"subtitle": "关键流程清晰可见",
"layout": "device-with-title-subtitle"
}
]
}配置字段说明
| 字段 | 含义 | 默认值 / 备注 |
| --- | --- | --- |
| version | 配置版本号 | 当前为 1 |
| platform | 平台类型 | 当前只支持 ios |
| defaults.backgroundPresets | 可复用背景预设字典 | 例如 { "hero": { ... } } |
| defaults.backgroundPreset | 全局默认背景预设名 | 填了之后,未显式写 background 的 frame 会优先使用它 |
| defaults.background | 全局背景配置 | 兼容纯色字符串,也支持 preset、solid、linear-gradient、image、raw-blur、stack |
| defaults.titleColor | 标题颜色 | #111827 |
| defaults.subtitleColor | 副标题颜色 | #4B5563 |
| defaults.titleFontSize | 标题字号 | 单位 px;不填时按画布宽度自动计算 |
| defaults.subtitleFontSize | 副标题字号 | 单位 px;不填时按画布宽度自动计算 |
| defaults.fontFamily | SVG 文本使用的字体族 | Inter, Arial, sans-serif |
| defaults.orientation | 输出方向 | portrait 或 landscape,默认 portrait |
| defaults.deviceWidthRatio | 设备截图区域占画布宽度的比例 | 范围 0.35 到 0.95,默认 0.76 |
| defaults.deviceFrame | 全局默认手机框配置 | 支持内置 preset 或自定义 src + screen |
| targets | 要生成的设备槽位列表 | 当前支持 iphone-6.9、iphone-6.5、ipad-13 |
| locales | 要生成的语言列表 | 例如 ["zh-Hans", "en-US"] |
| frames[].name | 输出文件名 | 不写 .png 也会自动补上 |
| frames[].raw | 原始截图路径 | 相对 screenshot.config.json 所在目录解析,支持 {locale} 和 {target} 占位符 |
| frames[].title | 标题文案 | 对应带标题布局时显示 |
| frames[].subtitle | 副标题文案 | 只在 device-with-title-subtitle 布局里显示 |
| frames[].layout | 渲染布局 | 见下方布局说明 |
| frames[].rawFit | raw-fullscreen 下原图缩放方式 | 默认 cover;改成 contain 时可露出背景层 |
| frames[].backgroundPreset | 单张图引用背景预设名 | 优先级低于显式 background,高于全局默认背景 |
| frames[].background | 单张图覆盖背景配置 | 不填时继承 defaults.background |
| frames[].titleColor | 单张图覆盖标题颜色 | 不填时继承 defaults.titleColor |
| frames[].subtitleColor | 单张图覆盖副标题颜色 | 不填时继承 defaults.subtitleColor |
| frames[].titleFontSize | 单张图覆盖标题字号 | 单位 px;不填时继承 defaults.titleFontSize 或自动计算 |
| frames[].subtitleFontSize | 单张图覆盖副标题字号 | 单位 px;不填时继承 defaults.subtitleFontSize 或自动计算 |
| frames[].deviceFrame | 单张图覆盖手机框配置 | 可只写 offsetY、scale 等局部字段 |
| frames[].target | 限制只在某个 target 生效 | 例如 iphone-6.9 |
| frames[].locale | 限制只在某个 locale 生效 | 例如 en-US |
字号字段速查
如果你想在 screenshot.config.json 里调 title / subtitle 的字号,直接看这 4 个字段:
defaults.titleFontSize:全局默认标题字号defaults.subtitleFontSize:全局默认副标题字号frames[].titleFontSize:覆盖单张图标题字号frames[].subtitleFontSize:覆盖单张图副标题字号
补充说明:
- 单位都是
px,值必须是正数,例如72、38 frames[]里的字号设置优先级高于defaultssubtitle只有在layout: "device-with-title-subtitle"时显示,所以subtitleFontSize也只会在这个布局下生效- 如果这些字段都不填,渲染器会按画布宽度自动计算字号
示例:
{
"defaults": {
"titleFontSize": 72,
"subtitleFontSize": 38
},
"frames": [
{
"name": "01_home",
"raw": "raw/{locale}/01_home.png",
"layout": "device-with-title-subtitle",
"title": "快速完成估价",
"subtitle": "关键流程清晰可见",
"titleFontSize": 84,
"subtitleFontSize": 44
}
]
}iPhone 6.5 尺寸要求
如果你把 targets 设成 ["iphone-6.5"],当前可接受的上架图尺寸要求如下:
- 竖屏:
1242 × 2688px或1284 × 2778px - 横屏:
2688 × 1242px或2778 × 1284px - 当前
screenshots render在defaults.orientation: "portrait"下会优先输出1284 × 2778px - 如果改成
defaults.orientation: "landscape",当前会优先输出2778 × 1284px screenshots check会接受以上 4 组尺寸
layout 有哪些类型
当前支持 3 种 layout。它们会直接影响标题、副标题、设备外框和背景的呈现方式。
| layout | 画面效果 | 适合场景 | 注意事项 |
| --- | --- | --- | --- |
| raw-fullscreen | 原图直接铺满整个输出画布,不显示设备外框、标题或副标题 | 已经是完整营销图、KV 图、海报风页面图 | rawFit: "cover" 时只输出原图;rawFit: "contain" 时才会露出背景层 |
| device-with-title | 顶部显示一段标题,下方展示带手机框的设备截图 | 单卖点页、功能页、流程页 | 即使传了 subtitle,当前也不会显示 |
| device-with-title-subtitle | 顶部显示标题和副标题,下方展示带手机框的设备截图 | 首页、详情页、需要两级文案的场景 | 这是默认布局;不填 subtitle 时会只显示标题区 |
raw-fullscreen 示例
这个布局会让原图直接成为最终产物,适合已经设计好的整张图。
{
"name": "01_launch",
"raw": "raw/{locale}/01_launch.png",
"layout": "raw-fullscreen"
}如果你想保留完整原图并让四周露出背景层,可以改成 contain:
{
"name": "02_story",
"raw": "raw/{locale}/02_story.png",
"layout": "raw-fullscreen",
"rawFit": "contain",
"background": {
"type": "linear-gradient",
"angle": 180,
"stops": [
{ "offset": 0, "color": "#F8FAFC" },
{ "offset": 1, "color": "#DBEAFE" }
]
}
}device-with-title 示例
这个布局会在顶部保留标题区,下面展示一张居中的圆角设备截图。
{
"name": "03_search",
"raw": "raw/{locale}/03_search.png",
"layout": "device-with-title",
"title": "快速找到目标商品"
}device-with-title-subtitle 示例
这个布局会比上一种多一行副标题,适合写一句补充说明。
{
"name": "04_home",
"raw": "raw/{locale}/04_home.png",
"layout": "device-with-title-subtitle",
"title": "首页信息一眼看清",
"subtitle": "核心入口、状态和行动按钮集中展示"
}手机框配置示例
默认配置会启用内置 iphone-dark-01 手机框。原始截图会放入手机屏幕区域,并按屏幕圆角裁剪,再叠加真实手机外框。
{
"defaults": {
"deviceFrame": {
"preset": "iphone-dark-01"
}
}
}如果单张图需要把手机整体上移或下移,可以只覆盖位置参数:
{
"name": "05_profile",
"raw": "raw/{locale}/05_profile.png",
"layout": "device-with-title-subtitle",
"title": "账户信息集中管理",
"deviceFrame": {
"offsetY": -80,
"scale": 0.96
}
}如果你要使用自己的手机框素材,需要同时提供屏幕开窗区域。screen 的坐标以手机框原图像素为准:
{
"deviceFrame": {
"src": "frames/custom-phone.png",
"screen": {
"x": 112,
"y": 67,
"width": 800,
"height": 1405,
"radius": 78
},
"fit": "cover",
"position": "top"
}
}注意:
- 内置
preset当前支持iphone-dark-01和iphone-dark-02。 iphone-dark-01有透明外部区域,更适合作默认手机框。iphone-dark-02原图没有透明通道,适合你自行处理透明底后再作为自定义src使用。offsetY为负数时手机上移,为正数时手机下移。
background 有哪些类型
同一套 background 结构可以写在这 3 个位置:
defaults.background:全局默认背景defaults.backgroundPresets.<name>:背景预设frames[].background:单张图覆盖背景
frames[].background 的优先级最高;如果你只想引用预设,也可以用 frames[].backgroundPreset 这个简写字段。
1. 纯色字符串
最短写法,效果等价于一个纯色 solid 背景。
{
"background": "#F5F7FA"
}2. solid
显式声明一个纯色背景。适合你后续想统一把所有背景都写成对象结构。
{
"background": {
"type": "solid",
"color": "#0F172A"
}
}3. linear-gradient
生成线性渐变背景,适合品牌色过渡、浅色氛围底和大面积柔和过渡。
{
"background": {
"type": "linear-gradient",
"angle": 180,
"stops": [
{ "offset": 0, "color": "#F8FAFC" },
{ "offset": 1, "color": "#DBEAFE" }
]
}
}4. image
把本地图片铺成背景。适合纹理、插画、品牌海报或运营底图。
{
"background": {
"type": "image",
"src": "backgrounds/hero.png",
"fit": "cover",
"position": "center",
"blur": 0
}
}如果背景图太花,可以叠一层遮罩提升文字可读性:
{
"background": {
"type": "image",
"src": "backgrounds/hero.png",
"fit": "cover",
"overlay": {
"color": "#111827",
"opacity": 0.18
}
}
}5. raw-blur
把当前 raw 原图本身拉伸、模糊后当作背景。适合让设备图和背景保持同一视觉主题。
{
"background": {
"type": "raw-blur",
"blur": 24,
"overlay": {
"color": "#111827",
"opacity": 0.18
}
}
}6. stack
按顺序叠加多层背景。适合把渐变、纹理图、遮罩和模糊层组合在一起。
{
"background": {
"type": "stack",
"layers": [
{
"type": "linear-gradient",
"angle": 180,
"stops": [
{ "offset": 0, "color": "#F8FAFC" },
{ "offset": 1, "color": "#DBEAFE" }
],
"opacity": 1
},
{
"type": "image",
"src": "backgrounds/noise.png",
"fit": "cover",
"opacity": 0.12,
"blend": "overlay"
},
{
"type": "solid",
"color": "#0F172A",
"opacity": 0.08
}
]
}
}7. preset
先在 defaults.backgroundPresets 定义一套背景,再在单张图里引用,适合多张图复用同一视觉风格。
{
"defaults": {
"backgroundPresets": {
"hero": {
"type": "stack",
"layers": [
{
"type": "linear-gradient",
"angle": 180,
"stops": [
{ "offset": 0, "color": "#F8FAFC" },
{ "offset": 1, "color": "#DBEAFE" }
]
},
{
"type": "image",
"src": "backgrounds/{locale}/{target}/{frame}.png",
"fit": "cover",
"opacity": 0.12,
"blend": "overlay"
}
]
}
}
},
"frames": [
{
"name": "01_home",
"raw": "raw/{locale}/01_home.png",
"background": {
"type": "preset",
"name": "hero"
}
}
]
}如果你更喜欢短一点的写法,也可以这样引用同一个预设:
{
"frames": [
{
"name": "01_home",
"raw": "raw/{locale}/01_home.png",
"backgroundPreset": "hero"
}
]
}注意:
image.src是相对screenshot.config.json所在目录解析的。image.src支持{locale}、{target}、{frame}占位符。image.fit当前支持cover和contain。image.position当前支持center、top、bottom、left、right。raw-blur总是使用当前 frame 的raw原图,不需要额外提供src。stack.layers会按顺序从下到上叠加,每层都可以写opacity和blend。blend当前支持over、multiply、screen、overlay、darken、lighten、soft-light、hard-light。- 如果你不想在很多 frame 里重复写长背景配置,可以先放进
defaults.backgroundPresets,再通过backgroundPreset或{ "type": "preset", "name": "..." }按名字引用。
常用例子
先预演,不写文件:
ipa-cli screenshots render ./screenshot.config.json --dry-run --format panel正式渲染:
ipa-cli screenshots render ./screenshot.config.json --output ./screenshots --format panel检查最终产物:
ipa-cli screenshots check ./screenshots --strict --format panel从模拟器采集一张原始图到当前工作区:
ipa-cli screenshots from-simulator \
--device "iPhone 16 Pro Max" \
--output ./raw/zh-Hans/01_home.png \
--format panel如果你已经准备好多语言和多设备,可以像这样扩展:
{
"defaults": {
"background": {
"type": "linear-gradient",
"angle": 180,
"stops": [
{ "offset": 0, "color": "#F8FAFC" },
{ "offset": 1, "color": "#DBEAFE" }
]
}
},
"targets": ["iphone-6.9", "iphone-6.5", "ipad-13"],
"locales": ["zh-Hans", "en-US"],
"frames": [
{
"name": "01_home",
"raw": "raw/{locale}/01_home.png",
"title": "核心卖点",
"subtitle": "一句话说明优势",
"layout": "device-with-title-subtitle",
"titleColor": "#0F172A"
},
{
"name": "02_detail",
"raw": "raw/{locale}/{target}/02_detail.png",
"layout": "raw-fullscreen",
"rawFit": "contain",
"background": {
"type": "image",
"src": "backgrounds/hero.png",
"fit": "cover"
}
}
]
}什么时候用 from-ipa
如果你只是想先自动生成一版草稿,可以直接跳过这个工作区,执行:
ipa-cli screenshots from-ipa ./Demo.ipa \
--workspace ./screenshots-workspace \
--output ./screenshots \
--format panel这个命令会自动生成 raw/、配置文件和最终上架图,但更适合“包里已经有可复用图片素材”的场景,不等价于真实页面自动截图。
