WRITING
从零到 TestFlight:一个人做 iPhone app 的完整路径

两周里我做了 9 个 iPhone app,其中 8 个发到了 TestFlight(苹果官方的内测渠道,装了它别人就能提前用你的 app)。
这篇不是复盘,是教程:按你从零走一遍的顺序,一共五步,每一步只讲三件事——做什么、怎么知道成了、坑在哪。看完你应该能自己走一遍,至少心里有数:每一步在等什么、别信什么。
先给一颗定心丸和一句警告。定心丸:写代码是整条链上最省事的部分,最小的一个 app 只有 367 行。警告:这条链上每一环都倾向于「安静地半成功」——不报错,但也没成。
难的不是写代码,是证明你是你——以及每一步都知道它到底成没成。
一、第 0 步:先判要不要做
做什么:动手前先过一条否决线:
只是想在手机上看一眼,而且有网络——那是个书签,不是 app。
手机 app 能干而网页干不了的,只有四件事:离线也要能用、要用相机这类硬件、要住在桌面小组件或锁屏上、要往回写数据且写的时候用到手机本身的能力(拍照、Face ID)。

怎么知道成了:你能一口说出这个点子命中四条里的哪一条。说不出来,就把网址存到手机主屏幕——五秒钟,零成本,效果一样。
坑:我自己差点栽进去一次。有个网页我每天早上打开看一眼,念头是「做成 app 多方便」。停下来问:app 版比在浏览器里打开它多了什么?答案是什么都没多——少输一次网址,换来后面五步的全部麻烦。
二、第 1 步:注册账号——先做那个不可逆的决定
先选账号,再碰任何东西
苹果的开发者身份分两档:
| 档 | 装进自己手机 | 给别人用 | 有效期 | 费用 |
|---|---|---|---|---|
| 免费 | ✅ | ❌ | 7 天,到期 app 直接打不开 | 0 |
| 付费 | ✅ | ✅ TestFlight | 1 年 | ¥688/年(中国区实付,不可退款) |
免费档适合试水。但有一条几乎没有教程会写的规则:每个 app 有一个全球唯一的识别名,用免费档签发过的识别名,永久归属那个苹果账号,谁也删不掉。
我的真实代价:先用旧账号的免费档试了 3 个 app,确认可行后,用另一个新注册的苹果账号开了付费会员。于是旧账号名下那两个识别名再也拿不回来——上传时报「识别名不可用」,一个 app 被迫改名,另一个干脆放弃分发。
所以这一步的第 0 小步是:想清楚付费会员要开在哪个苹果账号上,然后从头到尾只用这一个账号。这是整条链上唯一无法撤销的决定,而它发生在你还没意识到自己在做决定的时候。
缴费与等待
做什么:developer.apple.com → Enroll,选个人档(不需要公司资质),缴 ¥688。
怎么知道成了:收到那封「欢迎加入」的邮件。页面写「最长 48 小时」,我实测约 8 小时(早上 7 点付款、下午 3 点通过)。别按 48 小时排期,也别指望一定 8 小时;付完款页面一直显示「处理中」是正常的,不用反复重试。
立刻生成一把 API key——它决定后面能不能无人值守
付费通过后先别急着建 app,去后台(App Store Connect → 用户和访问 → 集成)生成一把 API key:一个小文件加两串编号。它的作用是让「上传 app」从此不需要人守着输密码、收验证码。
我卡了整整两天,就是因为一开始没做这一步:

怎么知道成了:那个私钥文件在你手里,两串编号存在安全的地方。
坑:私钥文件苹果只让你下载一次,当场存好,别想着回头再说。
三、第 2 步:第一个 app——先跑通一屏
环境只有一条要求
装 Xcode(苹果官方开发工具,免费)。唯一的坑:Xcode 的版本必须不低于你手机的系统版本。手机系统更新的时候,报错信息完全不会提示「该升级 Xcode 了」,只给一个看不懂的连接错误。
怎么知道成了:手机连上电脑后,Xcode 的设备列表里能看到它,没有黄色感叹号。
需求不用写文档,指着一个既有的东西说
9 个 app,我没写过一份需求文档。我把自己敲过的每句话全部拉出来数了一遍——149 条,中位数 34 个字:

最有效的提法是指着一个已经存在的东西:「这个网页/这个程序,做成 app」。既有的东西自带三样最难讲清的信息:数据从哪来、逻辑怎么算、名词是什么意思。反过来,如果一个点子只能用文字从头描述、没有任何既有的东西可指,它多半还没到该动手的时候。
(这条对「跟 AI 协作」和「自己给自己立项」同样成立。)
铁规矩:第一屏没亲眼看到之前,不写第二屏
做什么:先只做一个界面,在模拟器(Xcode 自带的虚拟手机)里跑起来,亲眼看到它,再写下一个。
为什么:界面之间怎么跳转——底部标签?列表点进去?——是整个 app 的骨架。骨架错了,写到第五个界面才发现,就是五个界面一起返工。这个错我犯过一字不差的一遍。
怎么知道成了:你在模拟器里看到了那一屏。不是「编译通过」——编译通过只说明代码没写错字。
顺便说一句体量,好让你敢动手
9 个 app 合计 124 个源码文件、19,334 行;单个 app 中位数 11 个文件、1,600 行。最小的那个 367 行,装机能用,天天在用。

四、第 3 步:装上真机——从这里开始,「没报错」会骗你
做什么:手机连上电脑(数据线或同一个 Wi-Fi),在 Xcode 里选中它,点运行。第一次装完,手机会拒绝打开,要去「设置 → 通用 → VPN 与设备管理」里手动信任你的开发者证书——这是正常流程,不是出错了。
怎么知道成了:**在手机上点开它,并且点进第二层界面。**图标出现在桌面上不算——签名有问题的 app,图标照样出现,点开就闪退。
坑:从这一步起,命令和工具会「说谎」。我收集了四对「我以为 vs 实际」:

其中两个都出在「启动」上:手机锁着屏的时候,启动命令返回「成功」,实际什么都没跑起来;app 已经开着的时候再启动一次,同样返回「成功」,实际新的启动参数根本没进去。
这一步教会我整条链上最值钱的一个习惯:**判断一件事成没成,不看命令说什么,去找它该留下的痕迹。**app 真跑起来了,服务器日志里就该多一条来自这台手机的请求;没有那条日志,打印多少个 ✅ 都不算数。
五、第 4 步:接数据——三种形态,成本差一个量级
app 的数据从哪来?只有三种形态,选哪种决定了你后面一半的工作量。我的 9 个正好三种都占:

怎么选:
- A 纯离线:数据在电脑上生成、打进安装包。看起来最省事——不联网、不要登录——但数据一变就要重新装一次机。只适合更新频率很低的内容(档案、题库这类)。
- B 联网只读:手机从你的服务器拉数据,数据常新,代价是要处理登录。
- C 联网读写:手机往服务器写回数据。这才是 app 真正比网页强的地方(对应第 0 步四条理由里的「往回写」),也是坑最深的一条。
C 形态的必踩坑,原样奉上:一个 app 要把手机拍的整页照片传回服务器。手机端我已经把图压到 2.9MB,本地测试全绿。上了真机、对着真服务器传——每次必然失败。原因:服务器默认只收 1 MB 以内的上传,超了直接拒;而本地测试环境没有这个限制,所以本地永远是绿的。
怎么知道成了:C 形态上线前,用真手机对着真服务器传一次最大的那种负载。模拟器和本地后端在这件事上证明不了任何东西。
六、第 5 步:上 TestFlight——以及整条链的验收清单
做什么,三件事:
- 后台建一条 app 记录(App Store Connect → Apps → 新建)。整条链里只有这一屏必须人点,机器代替不了。注意 app 的名字也是全球唯一的,英文常用词基本被占光,用中文名一次就过。
- 上传:用自动签名,配上第 1 步那把 API key。不需要手动去后台创建分发证书——几乎所有教程都让你建,我实测:这台电脑上分发证书数量为 0,而 8 个 app 全部上了 TestFlight。证书由苹果云端代管,自动申请、自动使用,你的电脑上一张都不落。
- 加测试员:后台把对方的邮箱加进内测名单,或者生成一个公开链接发出去。
怎么知道成了:两个痕迹,缺一不可——后台里这个构建的状态变成**「可用」;你自己手机上的 TestFlight 里真的装到了它**。
坑:「上传成功」四个字不算数——它只证明字节发出去了,不证明苹果收下并处理完了。我踩过一个更阴的:上传成功、处理完成、状态全绿,但构建没有挂到版本上——后台画廊里是一个灰色空图标。没有任何一步报错,只有肉眼能发现。
最后,把整条链的「别信什么/去看什么」收成一张表。这张表就是本文的验收清单:
| 步 | 别信什么 | 去看什么 |
|---|---|---|
| 0 判要不要做 | 「做成 app 多方便」的直觉 | 说得出命中四条理由里的哪条 |
| 1 注册账号 | 页面上的「处理中」 | 那封通过邮件 |
| 2 第一个 app | 「编译通过」 | 模拟器里亲眼看到那一屏 |
| 3 装真机 | 启动命令的「成功」 | 手机上点开、点进第二层 |
| 4 接数据(写回) | 本地测试全绿 | 真机对真服务器传最大负载 |
| 5 上 TestFlight | 「上传成功」 | 后台状态「可用」+自己手机装到 |
这条链上每一环都倾向于「安静地半成功」,所以每一步的验收都不是「没报错」,而是亲手找到它该留下的那个痕迹。做到这一点,写代码真的就是最省事的那部分——从零开始,两周,九个,够了。
订阅
新文章都先发在这里。用 RSS 订阅: /feed.xml