关于 wjs-publishing-appstore
用于将已有 TestFlight 构建提交至 App Store 审核的技能,涵盖商店资料与截图准备。它在已配置的 TestFlight 流程上增加独立的 fastlane release 通道,提交需手动触发。
主要功能
- 01生成 App Store 资料模板
- 02拍摄本地化商店截图
- 03添加手动触发的 fastlane release 通道
- 04提交前预览商店页面
- 05复用已处理的 TestFlight 构建
适用场景
- 01准备 App Store 审核所需的本地化资料
- 02为商店页面拍摄模拟器截图
- 03提交现有 TestFlight 构建以供审核
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jianshuo/ claude-skills --skill wjs-publishing-appstore安装后在 Claude Code 中输入/wjs-publishing-appstore确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
scripts/release_lane.rbscaffold-metadata.shshoot.sh详细介绍
wjs-publishing-appstore
将已成功构建到 TestFlight 的 iOS 应用发布到 App Store:准备好 截图 + 描述/元数据,然后使用现有的 fastlane 提交审核。
这是 wjs-publishing-testflight 对应的 App Store 流程,而后者是一个 前置条件——该技能负责构建 / 签名(match)/ CI / beta lane。本技能假设这些都已完成,只添加应用列表信息 + 一个经过审慎设计的 release lane。参考实现:VoiceDrop、Cathier。
心智模型
git push → main → beta lane → TestFlight (unchanged, automatic)
fastlane release → release lane → metadata + screenshots → submit for review
提交审核是高风险操作,因此绝不会由推送触发——只有你主动运行的明确 fastlane release 命令才会触发。
前置条件
- 已设置
wjs-publishing-testflight:matchApp Store 证书、ASC_API_*密钥、可正常工作的betalane,且至少有一个构建已上传到 TestFlight(这也会创建 App Store Connect 应用记录)。 - Apple 凭据 / ASC API 密钥:参见 [[apple-developer-credentials]] 和
wjs-publishing-testflight中的前置条件表——此处不要重复列出密钥(此技能会自动发布到公开仓库)。 - 如果 App Store Connect 应用记录尚不存在,请创建一次:
bundle exec fastlane produce -u [email protected] -a <BUNDLE_ID> --app_name "<Name>"。
步骤
1. 搭建元数据目录结构
scripts/scaffold-metadata.sh # from this skill; run at the repo root
创建 fastlane/metadata/{zh-Hans,en-US}/*.txt + review_information/ + 顶层类别/版权信息,并填入可编辑的 VoiceDrop 文案作为初始内容。重新运行时绝不会覆盖现有文件。
2. 撰写实际文案
编辑每个 .txt 文件。注意字符数限制:名称 30 · 副标题 30 · 关键词 100(逗号分隔,不含空格)· 推广文本 170 · 描述 4000。填写 review_information/(电话号码;仅在需要登录时填写演示账号)和隐私政策 URL。
App Store 的 name 必须全局唯一。 简短常见的名称(“VoiceDrop”)几乎肯定已被其他账号使用——提交时会在 upload_to_app_store 失败,并显示 “The app name you entered is already being used.”。这仅指显示名称;主屏幕名称(CFBundleDisplayName)是独立的,可以保持你喜欢的名称。请选择一个有辨识度的字符串(例如添加一个词或中文后缀——“VoiceDrop 口述”);越长越安全。名称按语言区域设置区分,也可以在后续版本中更改,因此并非永久不变。
3. 拍摄截图
scripts/shoot.sh # default: iPhone 16 Pro Max (6.9"), zh-Hans
LOCALE=en-US scripts/shoot.sh # second locale
编辑 shoot.sh 中的 drive_screens(),以展示每个营销界面(3–6 个,命名为 01_*、02_*……)。该脚本会启动模拟器、构建、安装应用,并将截图保存到 fastlane/screenshots/<locale>/。FRAME=1 会添加 frameit 边框。
**必需尺寸:**只需提供 **6.9" 显示屏(1320×2868)**的截图,该尺寸适用于仅支持 iPhone 的应用。仅当 TARGETED_DEVICE_FAMILY 包含 iPad 时,才需要添加 13" iPad 的截图流程(VoiceDrop 仅支持 iPhone → 一个尺寸即可)。
**麦克风权限注意事项:**如果应用请求麦克风/录音权限,iOS 会显示一个无法通过 xcrun simctl privacy grant microphone 隐藏的对话框(这是 iOS 26 模拟器的实际限制)。打开 Simulator.app,点按“允许”/Allow 一次——授权会在安装期间持续有效,因此再次运行 shoot.sh 就能截取干净的画面。(simctl 不支持 tap;不要尝试通过脚本点击——使用 osascript 执行模拟点击需要运行环境不具备的 macOS 辅助功能权限。)
iOS 26 模拟器的其他截图注意事项:
- 如果某个界面必须点按才能进入,临时将应用启动到该界面(使用受环境变量控制的
DebugRoot),并通过应用自身的令牌为其填充数据(模拟器在每次重新安装时都会重新生成同步型 Keychain 标识——没有 iCloud 账号——因此,注入到旧标识下的数据不会显示;真机上的标识则会保留)。 - 即使是只有两个标签页的简单
TabView,模拟器也会在灵动岛附近绘制一层淡淡的TabView标签残影——这是仅出现在模拟器中的 Liquid Glass 伪影,并非你的应用所致。不要对此进行排查;请在设备上验证。
4. 添加 release lane
将 scripts/release_lane.rb 粘贴到现有的 fastlane/Fastfile 中,位置在
platform :ios do … end 内。它会上传元数据和屏幕截图(TestFlight lane
设置 skip_metadata/skip_screenshots: true;此 lane 将它们设为 false),
然后设置 submit_for_review: true 并填写加密/IDFA 合规性答案,同时通过
guard_not_in_review 进行保护。
5. 先预览,再提交
# dry-run the listing without submitting (writes an HTML preview, no upload):
bundle exec fastlane deliver --skip_binary_upload true --submit_for_review false --force false
# real submit (uses the build already on TestFlight for this version):
bundle exec fastlane release skip_build:true # reuse the TestFlight build
bundle exec fastlane release # or build a fresh one first
在本地运行,或通过 CI 的 workflow_dispatch 运行(前提是你的 build.yml 将
appstore 选项路由到 fastlane release;参见 wjs-publishing-testflight 第 3 步)。
稳妥的两步发布方式(实际验证有效): git push → beta lane
构建并上传到 TestFlight,等待 Apple 完成处理 → 然后触发 appstore →
fastlane release skip_build:true 复用已处理完成的构建。在 release lane 中构建新二进制文件,
可能导致在构建处理完成前就提交。CI 会检出 main,因此触发前必须先将元数据和屏幕截图
提交到 main。
取消屏幕截图的忽略设置。 仅用于 TestFlight 的配置通常会在 .gitignore 中加入
fastlane/screenshots/(该流程使用 skip_screenshots)。此 lane 会上传这些截图,
因此必须将它们提交到仓库——移除该忽略规则(只保留对 frameit 额外文件的忽略),
否则 CI 不会上传任何内容。
App Store Connect 首次提交时的一次性注意事项
这些设置位于 ASC 网页控制台中,不在 fastlane 元数据里;未设置前,fastlane
会拒绝提交。在首次运行 fastlane release 前一次性完成所有设置——这些设置会保留
(后续版本无需重新设置)。如果提交在最后一步遇到这些问题而失败,元数据和屏幕截图
已经上传,因此只需修正控制台设置并重新触发即可,无需重新上传。实际错误信息会一次列出
所有缺失属性(violenceCartoonOrFantasy、ageAssurance、contentRightsDeclaration、
"App is not eligible for submission until pricing has been set" 等)。
- 年龄分级问卷——对于实用工具类应用,所有项目均选择 None/No。Apple
在 2025 年扩展了该问卷(新增字段:
ageAssurance、parentalControls、messagingAndChat、healthOrWellnessTopics等),fastlane 的分级配置并未完全涵盖 这些字段,因此请在网页控制台中填写,而不是通过 fastlane 填写。 - 定价与销售范围——将价格设为 Free,并设置销售地区。设置前会显示: "App is not eligible for submission until pricing has been set."
- 内容权利声明(App Information)——大多数应用选择“does not use third-party content”(不使用第三方内容)。
- App 隐私“营养标签”——申报数据收集情况。VoiceDrop:音频属于用户内容,存储在用户自己的存储空间;位置信息为可选/粗略信息(仅用于文件名);通过 Apple 登录使用匿名标识符;不进行追踪。
- 出口合规性——由 lane 处理(
export_compliance_uses_encryption: false);无需在控制台中操作。 - 审核前必须关联一个构建(由 lane 完成)。
更新已在审核中的版本
版本处于等待审核状态时,guard_not_in_review(以及 Apple)会阻止重新提交。
若要替换为较新的构建、修正文案或添加屏幕截图,请在 ASC 中打开该版本 → 选择
“Remove this version from review”(恢复为可编辑状态)→ 然后重新触发
fastlane release skip_build:true。系统会选中新构建,重新上传元数据和屏幕截图,并再次提交。
屏幕截图必须与二进制文件一致(指南 2.3.3)。 不要放入审核中构建尚未包含的功能截图—— 要么在提交的构建中加入该功能,要么将截图留到包含该功能的版本再提交。
验证清单
-
fastlane/metadata/**中没有...FILL_ME.../ 必填字段为空的情况 - 每种语言的
fastlane/screenshots/<locale>/中至少有 1 张 6.9" PNG,文件名为NN_* -
fastlane deliver预览(步骤 5 的试运行)能够正常显示应用列表信息 - 已在 ASC 控制台中设置 App Privacy、年龄分级和定价
-
fastlane release→ "Submitted X for App Store review";存在release/X标签 - App Store Connect 显示版本状态为 Waiting for Review
常见错误
| 症状 | 修复方法 |
|---|---|
Could not find app … on App Store Connect | 缺少应用记录 → 执行 fastlane produce(步骤 / 前提条件)。 |
| "The app name you entered is already being used" | name 已被全局占用 → 选择一个唯一的显示名称(步骤 2)。 |
| 提交失败,提示 "missing screenshots" / CI 未上传任何截图 | 没有 6.9" 截图、尺寸不正确,或 fastlane/screenshots/ 仍被 git 忽略(取消忽略)。 |
缺少 violence… / ageAssurance / contentRightsDeclaration / "pricing has been set" | 首次提交所需的控制台项目尚未设置 → 在 ASC 网页控制台中填写年龄分级、pricing=Free、内容权利和 App Privacy。 |
Another version is in review / 触发 guard_not_in_review | 若要更新正在审核的版本,请在 ASC 中选择 "Remove this version from review",然后重新分发。 |
| 关键词字段被拒绝 | 关键词必须以逗号分隔、不能包含空格,总长度不得超过 100 个字符。 |
| 提交了错误的构建版本 | 使用 release skip_build:true,为此 MARKETING_VERSION 复用完全相同的 TestFlight 构建版本。 |
此技能中的文件
scripts/scaffold-metadata.sh— 创建deliver元数据目录树(预置 VoiceDrop 文案)scripts/shoot.sh— 脚本化的simctl截图采集scripts/release_lane.rb— 要粘贴到 Fastfile 中的releasefastlane lane