测试员发消息:“你这 beta 打不开了,提示 ‘This beta has expired’。” 你打开 App Store Connect → TestFlight → Builds,看到那个跑了两个月的 build 现在显示 Expired。部分测试员还能启动(设备上缓存了几天,取决于 iOS 版本),但新安装和大部分老安装都被挡。整个外部测试周期就此暂停,你也无法”延长”过期的 build。
TestFlight build 有从上传日起 90 天的固定有效期。Apple 强制执行,无账号级例外,无延期机制。修法不是把死的 build 救回来——而是上传一个版本号相同或更高的新 build 替换掉它,在测试员的 TestFlight App 里挤掉旧的。
常见原因
按命中率排序。
1. Build 到了 90 天 TestFlight 生命周期
90 天时钟从上传起,不是从第一次安装起。90 天后 Apple 在 App Store Connect 标 build 为 Expired,TestFlight App 拒绝启动并提示 “This beta has expired”。没有任何延期机制。
如何判断:App Store Connect → TestFlight → Builds 看 build 上传日。85+ 天前的就快过期或已过期。
2. 过期前没传新 build
你为一个长跑 beta 只传过一个 build 从不轮换。第 91 天 build 过期,测试员被锁出去,你手头没有备用 build。
如何判断:TestFlight Builds 标签下数 “可用” build 数量。只有一个还很旧就有风险。
3. 留着旧 build 同时撤回了新 build
你传了新 build 挂给测试员后发现回归 bug 撤了。测试员退回到老 build,老 build 在你修 bug 时过期。
如何判断:Activity 日志里看最近的 “withdrawn” 动作。当前唯一 “active” build 超过 60 天就有轮换缺口。
4. 新 build 传了但没挂上 group
你传了新 build 处理完了,Builds 里显示 “Ready to Submit”,但忘了加进外部测试 group 或发给内部测试员。旧的过期了,测试员看不见新的。
如何判断:TestFlight → 你的 group,查挂的 build 列表。最新 build 没在 group 里就要挂上。
5. 新 build 在等 Beta App Review
你及时上传了,但新 build 在 Beta App Review 排队。等的时候旧 build 过期,测试员两个都看不到。
如何判断:新 build 状态 “Waiting for Beta App Review”。用内部测试做兜底,或者等 Beta 审核。
动手前先确认
- 确认 build 真的是过期不是暂停——Apple 显示不同状态。
- 决定上一个全新版本还是只 bump build 号——都能替换过期 build。
- 改之前把当前 archive 备份本地。
- 弄清你这个 App 历来 Beta 轮换节奏是否合规,预防比修复重要。
需要收集的信息
- 过期 build 的上传日期(90 天计算用)。
- 过期 build 的版本(
CFBundleShortVersionString)和 build 号(CFBundleVersion)。 - 任何 pending build 的状态(Processing、Waiting for Review 等)。
- 过期 build 和 pending build 各自的 group 挂载状态。
- 测试员投诉时间戳(如果你要沟通修复时间)。
最短修复路径
Step 1:找对 “下一个” build
App Store Connect → TestFlight → Builds 找:
- 已处理且版本 ≥ 过期 build 版本、build 号更高的。
- 没有就要上新的。
不能复活过期 build,只能用替换。
Step 2:打新 archive
Xcode:
- 递增
CFBundleVersion(如47→48)——必须,因为 47 还在 Apple 记录里。 - 这是真功能更新就一并 bump
CFBundleShortVersionString。 - Product → Clean Build Folder。
- Product → Archive(Generic iOS Device)。
或用 xcodebuild:
agvtool next-version -all # bump build 号
xcodebuild -workspace Acme.xcworkspace -scheme Acme \
-archivePath build/Acme.xcarchive archive
xcodebuild -exportArchive -archivePath build/Acme.xcarchive \
-exportPath build/ipa -exportOptionsPlist exportOptions.plist
xcrun altool --upload-app -f build/ipa/Acme.ipa \
-t ios -u "$ASC_USER" -p "@keychain:ASC_PASSWORD"
Step 3:等处理完成
Apple 处理 build(典型 10-60 分钟)。状态走 “Processing” → “Ready to Submit”(挂上并审核通过后切 “Ready to Test”)。
# 可选:用 App Store Connect API 监控
curl -H "Authorization: Bearer $JWT" \
"https://api.appstoreconnect.apple.com/v1/builds?filter[app]=$APP_ID&sort=-uploadedDate" \
| jq '.data[0].attributes.processingState'
Step 4:(外部测试)提 Beta App Review
如果是新版本(如 2.8 vs 过期的 2.7),新版本第一个 build 要 Beta App Review。同版本 + 新 build 号通常不用重审(自动批)。
App Store Connect → TestFlight → External Testing → 你的 group → Build → Submit for Beta App Review。
Step 5:挂上测试组
变 Ready to Test 后:
- TestFlight → External Testing → 你的 group → ”+” → 选新 build。
- TestFlight → Internal Testing → ”+” → 选新 build(不用审核)。
Step 6:通知测试员
App Store Connect → TestFlight → External Testing → 你的 group → “Notify Testers”。会给测试员发邮件附深链跳更新。
写一份测试员看的发布说明,这就是 “What’s New for testers” 字段。把替换专属信息写上(如 “请更新——上一个 build 已过期”)。
怎么确认已经修好
- 过期 build 状态保持 “Expired”,新 build 显示 “Ready to Test” 或 “Available”。
- 通过 TestFlight 更新的测试员看到新 build 的发布说明。
- 干净设备用 TestFlight 邀请链接冷装拿到的就是新 build。
- 新 build 的到期日(App Store Connect 可见)是上传日 +90 天。
如果还是没修好
- 新 build 测试员看不到就核查它是不是挂上了对的 group 且 Ready to Test(不是还在 Waiting for Review)。
- 让测试员强刷 TestFlight:杀进程重开;或在 TestFlight 登出再登入。
- 检查测试员是不是在没挂新 build 的 group 里;他们还在看老(过期)build。
- Beta 审核异常慢就看 Beta App Review 太慢。
预防建议
- 任何长跑 beta 在上传日 +80 天加日历提醒。
- 维护”轮换”节奏:至少每 60 天传一个新 TestFlight build,即使代码改动很小。
- 活跃外部 group 始终挂着至少一个 60 天内的 build。
- 每轮测试都 bump build 号,让向前滚成为机械操作。
- 在
BETA.md里记录 TestFlight 轮换流程,责任不只压在一个人身上。