目 录CONTENT

文章目录

从「不会 Swift」到 App Store 过审:我用 Claude Code 又写了个 iOS App

咕咕
2026-04-24 / 0 评论 / 2 点赞 / 99 阅读 / 0 字
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
广告 广告

起点 —— 上一篇挖的坑,这一篇填了

上一篇 写完 Claude Code 魔改 Halo 主题,文末我顺手挖了个坑——说下一步想试试用 Claude 做个 iOS App。当时吹牛成分 60%、好奇成分 40%,没想到这话放出去不到一周,App 真就写完提审了。

动手之前我给自己定了两个目标。

一是摸一下 Claude 的能力边界。Halo 主题那种活,网页端改改 CSS,对 Claude 来说是舒适区。iOS 开发就不一样——SwiftUI、SwiftData、真机调试、证书签名、App Store 审核,每一环都是新坑,我想看看咕咕坐副驾这事能跑多远。

二是真有这个需求。不是为了写博客硬编的场景——我自己就囤着一堆 VPS、域名、邮箱、SaaS 订阅,哪天哪个扣费、哪天哪个到期,全靠Notion记录肉眼盯。(好吧我承认起因其实是怕自己的搬瓦工iON 等等传家宝 VPS 忘记续费 = =)。

上一篇的评论区,有朋友推荐了 Wallos——一个自托管的订阅管理工具。我确实很早之前 Docker 部署了一份(也出过教程),跑在自己 VPS 上。但 Wallos 的提醒路径是邮件——我经常忘记开邮箱…… 而且我的邮箱太多了……

手机这东西一天看 50 次。如果有一个 App 把提醒直接推到锁屏——肯定不会错过。

动机清晰了。

2026 年 4 月 21 日晚上 7 点 28 分,我在一个空文件夹里打开 Claude Code,告诉它:

「做一个 iOS App,追踪订阅和域名到期时间,本地存储,不要账号,不要云」——就这么开始。

图标 —— 一只带铃铛的鸽子

AppIcon-1024.png

整个项目里,唯一一个从一开始我就想清楚、没让 Claude 瞎发挥的东西,就是这只鸽子。

  • 🕊️ 鸽子 = 信使——按时把消息捎到
  • 🔔 铃铛 = 通知——到点了响一声
  • 🧡 粉橙渐变——压住"催债感"和"焦虑感",DueSub 做的是温柔的提醒,不是红底白字的「还有 3 天扣费!」

图标里的一图二喻,其实就是这个 App 的产品哲学——非打扰式、按时到达、不制造焦虑

功能是"续费提醒",视觉符号是"捎着铃铛的信鸽"——我只用一句话把这个意向说给 Claude 听,基本上两版就过了。这也是这次协作里我觉得最神奇的地方——你脑子里模糊的画面,只要你能用一句话说清楚它的内核,Claude 基本能把它落到像素上

当然也适配黑暗模式:

AppIcon-1024-Dark.png

成品长这样

话不多说,直接上图。

01-list.png

主列表:支出和收入同屏对照,月付、季付、年付、一次性,所有周期一个列表里理清。顶部那个粉橙色的卡片显示「30 天内还有几笔」,是我自己每天打开 App 最想第一眼看到的信息。

05-homewidget.png

主屏小组件:桌面上直接看 30 天内即将到期的 N 项,不用点进 App。对我来说这就是这个 App 存在的意义——你手机锁屏那一眼就能看到的东西,你不会忘记

04-lockscreen.png

锁屏小组件:只显示下一笔——不用解锁、不用打开 App、锁屏状态下直接看到名字和剩余天数。这个我真的挺喜欢。

整个视觉语言贯穿的还是那个「非打扰式」的产品哲学——数字不标红、不用感叹号、不搞「紧急!」这种暴力美学,就是温柔地提醒你一句。

4 天 18 个 commit

我之前没写过 Swift,一行都没有。

Xcode也没装过。

SwiftUI、SwiftData、WidgetKit(分别是苹果用来做 iOS 界面、存本地数据、做桌面/锁屏小组件的三套框架)是啥,全是边做边查。但不妨碍我 4 天写完、上架、提审。

日期 Commits 主要内容
04-21(周二) 7 初版 + 改名 + 图标 + 隐私声明 + 截图策略
04-22(周三) 4 通知 P0 三连击 + 真机验证 + 修复上线
04-23(周四) 3 多币种实时汇率(opt-in)
04-24(周五) 4 Bundle ID 改名 + ASC 元数据 + 提交审核

我大部分时间在干嘛?打字、截图、点按钮。写需求、看效果、给 Claude 反馈「这里不对、那里要改、审美再收一点」。真正「坐键盘前敲 Swift 语法」的时间——几乎没有。

但这不是说 Claude Code 是魔法。它不是。它会在一个看起来简单的地方疯狂跑偏,能爽到停不下来,也能气到想砸键盘。

下面是翻车现场合集。

翻车现场 1:改名三连跳(放了自己一鸽子)

App 一开始没专门起名字,我自用编译好之后,手机里最早就显示叫「续费提醒」。土是土了点,但直白。

第二天我觉得这名字太像 90 年代共享软件,改叫 Renewly。英文名、现代感、听起来像个 SaaS。

然后我犯了一个很愚蠢的错误——没有第一时间去 App Store 查重名。名字定了、图标调了、本地化文件改了、隐私政策的 title 也换了——一直到我准备提交审核之前,才突然想起来去搜一下。被人占了。有一个已经在跑的订阅工具 app 也叫 Renewly,功能还不完全重叠——这种重名是 Apple 审核环节大概率会让你改的那种。

这个锅就是没经验导致的。作为一个日常就在 App Store 搜 app、自己也跑一堆自托管工具的人,「发布前先查名字」这种事不用别人教。我偏偏就忘了——咕咕本咕,放了自己一鸽子

只能第三次改名。这次更彻底:英文叫 DueSub(Due + Subscription 的缝合),中文叫 续然(续是续费,然是自然、果然)。

踩完坑的经验——名字想好之后第一件事:去 App Store 和 Google Play 都搜一遍,再去 Namecheap 看看 .com 在不在(最好但不是必须),都空着再去设计图标、改代码、改本地化。我这次反过来做,付了 3 次改名的工时。

翻车现场 2:通知的三个坑(同一天翻了三次)

这个 App 最核心的功能是到期提醒——你订的 VPS 明天扣费,我提前 7 天、3 天、1 天推送,当天上午 9 点再补一刀。这个功能不对,整个 App 就是一个「带搜索框的表格」。

结果 04-22 那天我翻了三次车,一天修了三个 BUG。

坑一:九点以后打开 App,当天的提醒丢了。
调度逻辑是每天早上 9 点对「当天到期的项」推送一次。自测 OK。结果某天下午我打开 App,发现明明有一项今天到期,却没推送。根因是 App 长时间没启动,调度队列里根本没这条通知,系统自然不会补发。修法是 App 启动时 fallback 检查一次——当天有到期项、现在已经过 9 点、用户今天还没收到,就立刻补推。

坑二:自动续费的文案跟代码对不上。
设置页之前有个「自动续费项默认不提醒」的开关,文案写「你已经设置自动扣款了,不需要再提醒」。听起来很合理——但代码不是这么做的。代码里自动续费项依然推 7/3/1 天的提醒,只有当天 9 点不推。这种「你说的是 A,代码做的是 B」最阴——不 crash、不报错、但就是跟用户说好的不一样。改了文案——提前几天提一下不是坏事,是自动扣那一刻再来一下才烦。

坑三:App 开着的时候,通知横幅被系统吞了。
iOS 的默认行为——App 在前台时,系统不弹横幅。理由是 App 自己处理。这对聊天软件合理,对一个到期提醒 App 就是「你盯着屏幕的时候我就不提醒你」——有点傻缺。我真机上复现:早上 9 点 App 开着,该推的一声没响。我当时盯着屏幕看了 10 分钟,以为自己又写炸了。修法其实很简单——一行代码的事,让 App 主动告诉系统「前台也请弹」。

三个坑修完、真机回归测过,这一天我感受到了**「软件这事儿怎么每个角落都能翻车」**的经典真理。Claude 写代码很快,但它不会替你想清楚「用户下午 3 点才打开 App 会发生什么」——你得自己变成产品经理兼测试,一个个角落去踩。

翻车现场 3:Bundle ID 的最后一公里

全程最让我心里一凉的一次。

Apple 的 Bundle ID(可以理解成 App 的全球唯一身份证号)一旦在 App Store Connect 注册并提交过 build(也就是打包上传过一次安装文件),就不能改了——要改只能注册新 App ID、开新 App 记录,之前填的元数据、截图、审核资料全部作废从头来

我最早的 Bundle ID 前缀用了我日常 handle,但开发者账号实名信息是另一个名字。两边对不上,Apple 校验过不去。

只能改 Bundle ID。改它意味着:

  • Xcode 里所有 target 的 Bundle ID
  • 主 App 和小组件共享数据用的 App Group
  • 证书和描述文件要重签
  • 测试机上装过的旧版全部失效,要重装

最阴的是 App Group(让主 App 和桌面小组件共享数据的一个"命名空间",Apple 规定这个名字全球唯一)。我旧的 group 名改新的时候报冲突,说这个名字有人用过(其实是我自己,几分钟前注册的、没删)。加了个 .shared 后缀绕过——这个本来不应该存在的后缀永远留在我代码里了,作为一个「我和 Apple 的命名空间规则打过架」的纪念。

修完、重签、重装、回归——折腾好一会儿才终于走到 App Store Connect 那一步。

翻车现场 4:App Store Connect 是一个 checkbox 地狱

到这一步我才意识到:写 App 只是上架这件事的冰山一角。真正的灾难在 ASC。

让我列一下这次填过的表(不完整,凭记忆):

  • App 名称 / 副标题 / 推广文本 / 描述 / 关键词(英文中文两套
  • 主类别 / 副类别 / 年龄评级(一份 20 多题的问卷,问我「本 App 是否包含恐怖元素」——我做的是订阅提醒)
  • 版本号 / 构建号 / 上架日期
  • 隐私政策 URL(每种语言一份,英文一个、中文一个)
  • Marketing URL / Support URL
  • 12 张截图(6.9" iPhone,iPad 跳过只做 iPhone)
  • App Icon 1024×1024
  • App 隐私标签(和代码里的 PrivacyInfo.xcprivacy 是两份独立的表,要自己保证内容一致)
  • 内容版权声明(不是 App 的版权,是 App 里用没用别人的素材)
  • 出口合规性(加密算法使用)
  • IDFA 使用声明
  • DSA 欧盟合规声明(新增的,个人开发者选 Non-Trader 才不会公开家庭住址)
  • App 审核联系方式 + 演示账户 + 审核备注
  • 定价 + 可用国家地区
  • Mac / Vision Pro 兼容性(默认勾,记得关)
  • 发布方式(自动 / 手动)

整理这份清单用了一下午。一个勾一个勾过,途中踩的坑:

  • 勾了「所有国家」才发现默认包括中国大陆——国区要备案我没备,赶紧去掉
  • 英文的隐私政策 URL 填完以为就行——ASC 跳出红 banner:简体中文 - 隐私政策网址 - 此栏为必填项。每种语言要独立一个 URL
  • 以为提交时会弹「出口合规 / IDFA / 内容版权」三连问——这次居然没弹。后来才知道如果你在 Info.plist / xcprivacy / App 信息页都提前答过了,ASC 不再来烦你
  • 备注里写了 Settings 里有个 "Seed Sample Data" 按钮——结果代码里英文按钮实际叫 "Fill sample data"。自己的 App,按钮名都记错。这给 Apple reviewer 看到,他大概会觉得我连自己 app 都没摸熟

最后所有字段绿勾、红 banner 消失、「提交以供审核」按钮可点。深呼吸,点下去。

然后画面一片祥和。没有弹窗、没有「你确定吗」、没有任何仪式感——左侧栏那个黄色小点变成「正在等待审核」,就这样。

吐槽一下:上架 App 这个流程,真的太复杂了

我要认真吐一下槽。

Apple 的 App Store 是 iOS 生态的核心支柱,用户体验堪称行业标杆。但它对开发者的体验,是另一个世界。

作为一个独立开发者、副业开发者、个人开发者,你要面对:

  1. ¥688 / 年的开发者费($99)。App 一分钱不赚,每年也得续。这个我认——毕竟用了整套工具链和分发网络。但作为一个常年买小鸡的人,每年还是要叹一声——这笔钱够我买一台好的服务器了
  2. 证书体系。App ID / Bundle ID / Provisioning Profile / Distribution Certificate / Push Certificate……随便一个过期,线上炸。
  3. ASC 的 30 多个字段 + 一堆合规声明。DSA、隐私标签、xcprivacy、内容版权、出口合规、IDFA、年龄问卷、类别、定价、可用区。
  4. 审核的黑盒。什么时候过、为什么过、拒了怎么改,全靠邮件 + Resolution Center。
  5. 多语言隔离填写。每个 locale 要独立填描述、关键词、URL——漏一个返工重来。

这套流程对成熟团队(有专门的 release manager 和 compliance)是日常,对一个摸着石头过河的独立开发者——「完成率劝退」比代码本身高 10 倍。我完全理解为什么那么多做了一半的 iOS App 最后没上架——不是代码没写完,是上架的活儿没人愿意干

我这次能走完,95%的功劳给 Claude——不是它写代码快,是它陪我把这 30 多个 checkbox 一个一个过完。如果让我自己看 Apple 文档去填,我多半中途就放弃了。

顺便说一下国区(其实我想上的)

这次上架,我主动跳过了中国大陆区——但这不是我本意。

我本来是想上国区的。不是说看重国区下载量,就是觉得一个中文作者做的中文工具,中文应用商店里没它,多少有点别扭。

备案这事我是知道的。早几年折腾服务器域名的时候,我就顺手买了一个十年的 .cn 域名挂在腾讯云、老老实实走完了 ICP 备案;当时配套也买过一台大陆服务器——但国内服务器的体验真的让人一言难尽,带宽小得可怜还卖得贵,到期我就没续费了。反正我要跑的服务都在境外,非要在大陆放一台机器没必要。

这次准备上架国区,我盘算了一下以为挺简单——.cn 域名还在、备案号还在、腾讯云账号还在、实名信息跟 Apple 开发者账号对得上。填个备案号就完事了吧?

结果一查流程才发现:光域名备案不够,备案得绑定在一台「正在使用中」的境内服务器上。我那台大陆机子早停了,备案跟着就失效了——要恢复,得再租一台国内服务器

这就有意思了——我这个 App 完全离线、不联网、不部署任何东西。我不需要服务器,没有任何后端服务要跑,也没有任何 API 要托管。仅仅因为「要在国区上架」这个理由,我被强制要求去租一台我完全用不上的大陆服务器

这一点我是真的不太理解。规则的本意大概是想给在国区上架的 App 留一个可追溯的境内主体,但对一个纯离线工具来说,服务器这条要求完全是空转——我没有后端、没有数据回传、没有任何需要境内托管的东西,却要为此每年多掏一份云厂商的钱。

算一下数:国内一台够用的轻量应用服务器(能用于备案的最低配起),一年 400 块起步;加上 Apple 开发者 ¥688;加上偶尔维护备案的小成本——对一个不收费的免费 App每年多花 1000 多块为爱发电,实在不太合理

所以这次我选了 All Countries except China mainland——174 个区全部开放,国区先空着。等哪天要做付费功能,有盈利模型能把这 1000 多块年成本覆盖掉,再回头补上国区不迟。

如果你也是个人开发者、做的是免费离线工具——国区这件事可以先放一放。把其他 174 个区跑通、把用户反馈收起来、把付费模型验证出来,再回头说国内的事。

Claude Code 作为 iOS IDE 的体验

回到这次最初的目标之一——「摸一下能力边界」。

我不懂 Swift,不会 SwiftUI 的声明式语法,SwiftData 的 @Model 到现在也讲不清原理。但一点都不慌——因为我不需要懂,我只需要知道我要什么

  • 「加一个设置项,让用户切换显示货币」——Claude 去加
  • 「这个列表行高再紧一点」——Claude 去改
  • 「真机跑一下,别只编译通过」——Claude 真的会去 build、装真机、抓日志
  • 「这个通知为啥没弹,你查一下」——Claude 读上下文、看 delegate、写假设、去验证

我的角色从「写代码」变成了「定需求 + 审效果 + 做判断」。前者要懂语法,后者要懂用户。

爽的地方:你不再因为「不会 Swift」而放弃 iOS App 这个想法

不爽的地方:它跑偏的时候你得看得出来——代码能力不是凭空被替代的,你能让 Claude 写代码,但你必须能看出它写的是不是你要的。

这次 4 天我踩到的能力边界大致在:

  • 需要你当产品经理。Claude 不会主动想「用户下午 3 点打开会怎样」这种边界 case
  • 需要你当测试。它说「已修复」不等于修了,必须你跑一遍真机复现
  • 证书 / 签名 / 打包的坑它不一定记得住,要你盯着它去查 Apple 最新文档
  • ASC 的字段含义它有时候会猜错,你得自己去对官方说明

其他的——写代码、读 API、调 debug、查栈、写测试——它比我快得多得多。

成本账

粗略算一下这个 App 到目前为止的总投入:

成本
Apple 开发者账号 ¥688 / 年
Claude Code 订阅 已订的 Max 档,这次没多花
域名 + 托管 ¥0(Landing 和隐私政策挂 GitHub Pages)
服务器 ¥0(没备案,不需要)
图标 ¥0(Claude + SF Symbols + 手调)
截图 ¥0(模拟器截图 + 简单标题文字)
总计 ¥688

跳过国区之后,全部成本就剩一张 Apple 开发者年费。对一个本来一行 Swift 都没写过的人——这个投入产出比,放在 Claude Code 出现之前是完全不可想象的

写在最后

这不是一篇「你也能 4 天做 iOS App」的鸡血文。你不能,我也不能——如果换一个更复杂的 App(联网、账号、支付、音视频、AI 推理),这个周期会翻好几倍。

但有一件事值得说——「我不会写代码」,不再是做东西的理由了

过去十年,「有想法但不会写代码」是劝退无数人的天花板。想做的东西卡在「找不到技术合伙人 / 招不起开发」这一步上。今天这个天花板被 Claude Code 这类工具狠狠砸了一个洞

不是洞下面一切都容易,iOS 上架流程该复杂还是复杂,国区备案的门槛该离谱还是离谱。但写代码本身这件事,从「不可能」,变成了「要不要动手」。

当开发成本降到接近于零,真正稀缺的是什么

这次最让我想明白的一件事——开发成本的下降,反过来把产品问题推到了台前

过去「找到真实需求 + 招到靠谱开发 + 写出能用的代码」三件事捆在一起,能搞定其中任何一个都算稀罕。现在 Claude Code 把第二、第三件事的门槛降到了个人能承受的范围——那第一件事——你到底在解决一个真问题,还是在自嗨——就变成了唯一卡住你的那个门槛。

我这个 App 是我自己的小真实痛点。规模不大,也不打算做成生意。但在做的过程里我越来越相信——在今天,独立开发者是真的能吃上饭的。这两年海外 indie dev 圈里,赚到钱的人一抓一大把,有年收入几十万美金的,也有做个 $10/月小工具把生活费搞出来的。核心都不是他们代码写得多牛——而是他们找到了一小群真实付费用户的真实需求

代码这条护城河正在被填掉,用户洞察成了新的护城河。对不少想副业糊口、或者想看能不能全职独立的人,这可能是十年难遇的一个窗口期——代码能力第一次不再是硬卡点,但同时,你对用户的理解的重要性被放大到前所未有。

下一个坑

这次 DueSub 是免费 App,没盈利模型——它本来就是给我自己用的,顺手做成了产品。下一个我想挖的坑,是做一个带付费功能的 App:走一遍订阅 / 一次性内购的完整流程,去碰 StoreKit、走税务合规、看看 Apple 30% 抽水到底怎么切、体验一下从 0 到第一个付费用户的全过程。

具体做啥还没定——先把用户洞察这一步想清楚再动手。这次改名三连已经告诉我了,想清楚再动手,比手快多跑一版省事得多。

最后

回到博客侧边栏那四个字——learn or earn

这回 learn 到了 iOS 一整套流程、Claude 能力边界、App Store 审核的全部坑;earn 谈不上,免费 App 没盈利模型。但摸清一条从 0 到 1 的路径本身,就是这次最大的 earn——下一次就知道怎么走第二步了。

App 叫 DueSub / 续然,现在在审核队列里,预计 24–48 小时后上架非国区 App Store。免费、离线、不要账号——如果你也跟我一样囤着一堆 VPS 和域名、又老忘开邮箱——装一个试试。

国区的事儿,以后再说吧。

咕咕下一篇接着挖坑。

后记 · 发博客之前 App 先过审了

正文写到上面那段「在审核队列里,预计 24-48 小时」的时候,App 确实还在审核。结果博客还没来得及排版发出,苹果那边先完事了。

这篇博客发出来的时候,App 就已经在除中国大陆外的各区 App Store 可搜可下了:

DueSub: Subscription Tracker —— 免费、离线、无需登录。

2
广告 广告

评论区