Back to Blog
·1 min read

收钱的那条路径,只有一种成功信号:流程走完,到达"已解锁"状态

收钱的那条路径,只有一种成功信号:流程走完,到达"已解锁"状态。其余一切——编译通过、paywall 正常渲染、购买 API 被调用过、失败后重跑变绿——都与"订阅按钮在真正点下去

收钱的那条路径,只有一种成功信号:流程走完,到达"已解锁"状态。其余一切——编译通过、paywall 正常渲染、购买 API 被调用过、失败后重跑变绿——都与"订阅按钮在真正点下去的那一下冻结或报错"完全兼容。

最近一次抓到这个问题的方式,本身就是答案:一个 UI 测试把购买流程真的点到头,断言已解锁状态,它红了。同一份代码,所有静态检查全绿。这不是矛盾,是结构性的:静态检查量的是产物(能不能编译、文件在不在、截图对不对),而冻结活在运行时里,活在审核员或真实用户的那一次点击上。围绕边缘的绿灯说明零件没问题,不代表产品的主流程被执行过。"能装不能买"正是 App Review 2.1(a) 的经典拒因,同一个拒因我遇过两次,两次都是静态检查全绿的包。

针对这类问题的修复模式,按重要的顺序:

1. 先把"成功"定义成状态,而不是动作。断言已解锁状态在 UI 里可观察,而不是"按钮被点了"或"商品列表加载了"——后者全过,前者照样死。 2. 用一个 UI 测试驱动全链路,每个阶段一条独立断言:商品加载了 → 事务开始了 → 系统确认弹窗处理了 → 已解锁可见了。这样一次卡死会自己报告卡在哪一段,而不是只留一句 failed。 3. 把发版的门压在这一个测试上。失败之后的"再跑一次绿了"只是多了一个样本,不是结案——复现失败的那次、找到卡住的阶段,才叫修复。间歇性的购买失败本身就是缺陷按它自己的失败率在被采样,不是可以重试过去的抖动。

一分钟自检:翻你的测试套件,有没有任何一个测试把购买一路驱动到"已解锁"的断言?还是只断言了 paywall 渲染、API 被调?如果是后者,你今天的全绿对这条唯一的收钱路径什么都没说。手工版更快:模拟器里打开 paywall,点购买,盯三件事——价格出现、系统确认弹窗出现、完成后 UI 真的显示已解锁。

#build-log

Written by

Peter Zhang

Building local-first Mac & iOS productivity apps at Obelisk Club.