mcpField
W
wjs-publishing-appstore

wjs-publishing-appstore

github.com/jianshuo云与 DevOps13760 次安装今天更新
代码仓库

关于 wjs-publishing-appstore

用于将已有 TestFlight 构建提交至 App Store 审核的技能,涵盖商店资料与截图准备。它在已配置的 TestFlight 流程上增加独立的 fastlane release 通道,提交需手动触发。

主要功能

  1. 01生成 App Store 资料模板
  2. 02拍摄本地化商店截图
  3. 03添加手动触发的 fastlane release 通道
  4. 04提交前预览商店页面
  5. 05复用已处理的 TestFlight 构建

适用场景

  1. 01准备 App Store 审核所需的本地化资料
  2. 02为商店页面拍摄模拟器截图
  3. 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.rb
scaffold-metadata.sh
shoot.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:match App Store 证书、ASC_API_* 密钥、可正常工作的 beta lane,且至少有一个构建已上传到 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 中的 release fastlane lane

评论

支持 Markdown