惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
IT之家
IT之家
Help Net Security
Help Net Security
月光博客
月光博客
N
News and Events Feed by Topic
Cloudbric
Cloudbric
博客园 - 司徒正美
L
LangChain Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tenable Blog
The Register - Security
The Register - Security
The Hacker News
The Hacker News
I
InfoQ
The Last Watchdog
The Last Watchdog
MyScale Blog
MyScale Blog
Schneier on Security
Schneier on Security
WordPress大学
WordPress大学
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
K
Kaspersky official blog
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
F
Fortinet All Blogs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Security @ Cisco Blogs
Recorded Future
Recorded Future
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
C
Cisco Blogs
N
News and Events Feed by Topic
V2EX - 技术
V2EX - 技术
Latest news
Latest news
PCI Perspectives
PCI Perspectives
T
The Blog of Author Tim Ferriss
P
Palo Alto Networks Blog
T
Tor Project blog
Project Zero
Project Zero
云风的 BLOG
云风的 BLOG
Webroot Blog
Webroot Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

肘子的 Swift 记事本 | Fatbobman's Blog

当灵感跑在了结果前面 -- 肘子的 Swift 周报 #145 当每一次写入都有了新价格 -- 肘子的 Swift 周报 #144 当 Linux 成为“空气”:容器、Agent 与不再重要的“桌面之争” -- 肘子的 Swift 周报 #143 两个 SwiftUI 动画 Bug 排查小记 SPI 加入 Apple,Swift 迈向自举 -- 肘子的 Swift 周报 #142 Swift 还让你 Excited 吗? -- 肘子的 Swift 周报 #141 从 Size Class 到可用空间,horizontalSizeClass 还可靠吗? WWDC 26:AI 帮你看完了,然后呢? -- 肘子的 Swift 周报 #140 WWDC 2026 初印象:符合预期,但更务实 -- 肘子的 Swift 周报 #139 Core Data + Observation:从属性级响应到心智解放 稳定 > 新功能 -- 肘子的 Swift 周报 #138 用自定义 Layout 化解 SwiftUI List 的行高与间距跳变 从社区路标到生态基石:Dave Verwer 的新篇章 -- 肘子的 Swift 周报 #137 消失的 WWDC 愿望单 -- 肘子的 Swift 周报 #136 CocoaPods 正在退场,SwiftPM 才刚到第二章 -- 肘子的 Swift 周报 #135 让 AI 从称手到称心 -- 肘子的 Swift 周报 #134 Swift 并发正被更广泛地接纳 -- 肘子的 Swift 周报 #133 从 OpenSwiftUI 到 DanceUI:换个方式 Dive SwiftUI -- 肘子的 Swift 周报 #132 被 Vibe 摧毁的版权壁垒,与开发者的新护城河 -- 肘子的 Swift 周报 #131 苹果的罕见妥协:当高危漏洞遇上“拒升”潮 -- 肘子的 Swift 周报 #130 一墙之隔,不同的时空 -- 肘子的 Swift 周报 #129 我的 App 审核被卡了? -- 肘子的 Swift 周报 #128 CDE:一次让 Core Data 更像现代 Swift 的尝试 50 岁的苹果和 51 岁的我 -- 肘子的 Swift 周报 #127 2026 年,为什么我仍在思考 Core Data Macbook Neo:苹果重回校园的起点 -- 肘子的 Swift 周报 #126 跨域传递 NSManagedObjectContext 为什么在 Swift 6.2 中不再报错?真正的变化不在编译器 Xcode 26.3 + Claude Agent:模型替换、MCP、Skill 与自适应配置 macOS 录屏软件开发实录:从像素抓取到元数据重现 isolated(any) 与 #isolation:让 Swift 闭包自动继承隔离域 在 tvOS 上活下來:一個非典型播放器的工程實錄 告别“可移植汇编”:我已让 Swift 在 MCU 上运行七年 独立开发者的试炼:Zipic 从 0 到 1 的产品化之路 为什么父视图无法修改子视图的 @State Partytown 实战:修复 GTM 自定义事件与 dataLayer 失效问题 Swift 6 编译加速:启用 Swift-Syntax 预构建 (Prebuilts) Swift 模块化:使用 package 关键字实现 Target 间安全共享 Monorepo 实战:解决 VSCode/Cursor 中 SwiftLint 配置失效问题 VSCode/Cursor 测试 Core Data:手动编译 xcdatamodeld 指南
逃离 Mac App Store:如何从零构建独立应用的分发与售卖体系
十里 · 2025-12-22 · via 肘子的 Swift 记事本 | Fatbobman's Blog

这是 Zipic 独立开发复盘系列的第二篇文章。在 上一篇 中,开发者 十里 分享了 Zipic 从痛点到产品的诞生过程。

本文中,将聚焦于独立开发者最头疼的“基建”问题——当决定离开 Mac App Store 的舒适区后,如何独自解决打包、公证、自动更新以及全球收款等一系列棘手难题。

嗨,大家好,我是十里👋!

在这一篇中,我想深入探讨一个更现实、也更“劝退”的话题:独立分发

AppStore vs 独立分发

很多 macOS 开发者即使完成了产品,也会被挡在“如何卖出去”的门槛外。离开 App Store 意味着失去现成的支付和更新系统,一切都要亲力亲为。但这又是 Zipic 必须走的一步路,为了更自由的权限和更直接的用户关系,我不得不啃下这块硬骨头。

Zipic Origin Story

Zipic 最初是在 Mac App Store 上架的。App Store 分发的好处明显:不用操心更新机制,也不用自己搭建支付系统。但随着迭代深入,我逐渐意识到一些难以逾越的问题:

  • 沙盒限制太多:Mac App Store 要求应用必须开启沙盒(Sandbox)。对于图片压缩工具来说,最明显的是文件读写权限——用户压缩完图片想保存并覆盖原位置,却发现没有权限。虽然可以通过 Security-Scoped Bookmark 持久化来解决目录授权,但管理复杂,用户体验也变繁琐。
  • 审核周期不可控:提交更新至少要等 1~2 天才能上线,遇到节假日甚至超过一周。用户反馈的 bug 修复本来很快,却因为审核拖得很长。
  • 分成比例偏低:默认 70%,申请小型企业计划最高 85%。

我想做的是体验流畅的工具,但 App Store 的限制让很多想法无法实现。加上后续希望上架其它平台(比如数码荔枝),总要搭建独立授权系统,权衡之后决定切换到独立分发。

如果不是万不得已,真心建议别折腾独立分发,你会变得非常不幸 😂 不如直接上架 App Store + 申请小型企业计划。

选择独立分发意味着要自己搞定打包、更新、授权、支付等整套体系。做好心理准备,这会占用很多精力,不符合快速 MVP 的原则。当然,这也是一劳永逸的工作,准备好了其他产品可以轻松复用。

DMG Canvas 打包流程

DMG Canvas Package

应用开发完成后要打包成 DMG 格式分发。用 Disk Utility 简单创建 DMG 效果比较粗糙,专业的应用 DMG 通常有漂亮的背景图、精心设计的布局、自动设置的窗口大小。手动制作很繁琐,更重要的是 macOS 的公证(Notarize)流程比较复杂,配置不对用户下载后会提示“文件已损坏”。

我用的是 DMG Canvas,所见即所得的编辑界面,可以自定义背景、图标位置、窗口样式。配置好模板后,每次打包只需选择新版本的 app 包重新 build 就行。公证流程它也做了集成,配置好 App-Specific Password 和 Team ID,勾选“Notarize”选项,打包完成后会自动上传到 Apple 服务器公证,整个流程自动化。

具体操作参考:使用 DMG Canvas 打包 macOS app 为 DMG

使用 Sparkle 实现自动更新

Sparkle

做独立应用还要解决更新机制。用户下载安装后如何及时获取新版本?手动下载覆盖安装体验很差,还要考虑安全性、确保更新包没被篡改。

Sparkle 是 macOS 平台上最常用的自动更新框架,很多知名应用都在用。支持签名验证、增量更新、发布说明展示,基本该有的功能都有了。集成过程不算复杂,主要是配置 Appcast(更新信息文件)和签名密钥,添加少量代码就能实现自动更新。Appcast 是个 XML 文件,记录最新版本号、下载地址、更新说明等信息,Sparkle 定期检查这个文件,发现新版本就提示用户更新。

具体使用步骤写在这篇文章:macOS 开发 - 使用 Sparkle 轻松实现 App 更新管理

踩坑经验:文件托管我最终用了 CloudFlare R2。相比 GitHub Releases 或自建服务器,R2 的优势很明显——全球都能访问(包括国内),存储有限额但流量无限制,还可以自定义域名,既保证分发稳定性又控制成本。

另外,Sparkle 会自动生成 delta 包(增量更新文件),可以显著减少用户下载量。但要记得把这些 delta 文件一起上传到托管服务,不然增量更新会失效,目录结构要和 appcast.xml 中的路径一致。

授权系统

Keygen

Zipic 用的是密钥验证激活方式,有免费版和 Pro 版,需要一个系统来管理许可证、验证用户购买状态。需求比较特殊:要支持多个销售平台(数码荔枝、官网商城等),每个平台的订单都要能自动生成授权码。

我选择了 Keygen.sh 的 CE(社区版)进行自部署。Keygen 本身是商业授权管理服务,但提供了开源的社区版本。功能基本够用,支持许可证生成、验证、使用统计等。自部署的好处是完全掌控数据,而且可以按需定制。用 Docker 部署在自己服务器上,配置好数据库和 Redis,系统就跑起来了。通过自实现 Webhook 服务对接各个电商平台,订单完成后自动生成授权码发给用户。

详细部署过程可以看这篇:软件授权用 Keygen.sh - 自部署服务

踩坑经验:Docker 网络配置是个坑。Keygen 需要连接数据库和 Redis,一开始用默认网络,服务启动后连不上数据库,后来建了自定义网络才解决。另外,如果直接用 Keygen 与第三方对接的话,可以通过产品 token 提供生成 License 的权限,尽量减少第三方的权限范围。

支付系统集成

Payment Stripe

独立分发还要解决一个关键问题:用户怎么付款购买?这块我踩过不少坑。

肘子注

作为一个来自中国的开发者,十里在实现全球分发,全球收款时遇到的困难会明显高于很多地区的开发者。

最开始使用的是 LemonSqueezy,功能很全——支付、密钥管理、联盟推广、邮件营销一站式搞定。但 2024 年被 Stripe 收购后,国人新账户提交申请基本不予理睬,这条路基本不推荐了。

网上有人提议用个人身份注册香港 Stripe 账号,技术上可行,但没有真实香港身份始终有合规风险,提现还需要香港银行卡,也不是长久之计。

最终我走了注册美国公司使用 Stripe 的路。过程一波三折:注册公司还算顺利,是通过 Stripe Atlas 完成的,然后开银行公户。很多人推荐水星银行,但我申请了几十次都失败,证明材料都是完整且准确的,但还是失败了,推测是姓名和某些敏感人物重名,最后注册申请空中云汇账户才办好了银行公户。注册企业 Stripe 还需要美国电话号码,我用的是 Ultra Mobile PayGo,月租仅 3 美元。

  1. 注册美国公司还有一种方式,在怀俄明州自助注册公司(约 $150),再申请 EIN 联邦税号(代理约 $39)
  2. 如果有条件的话,最好是办一些香港银行卡,推荐香港汇丰、中银香港、众安银行,港卡可以用于 Stripe 个人账号的提现、Paypal 提现(服务费很低)、Stripe 绑定的银行公户收益回流等

据我了解,不同身份适合不同方案:

  • 个人主体出海:推荐 Creem,其次是 Paddle
  • 国内企业主体:可以考虑 Paddle
  • 国外实体(美国/英国公司):建议用 Stripe
  • 只面向国内:蓝兔或 Zpay

如果对 Paddle 感兴趣,可以参考:两天内完成 Paddle 账户的注册和验证

还有一种思路:不自建支付,直接对接销售平台。比如数码荔枝,只需实现密钥分发接口就行。国外也有类似平台,如 Setapp(目前只接受 AI 应用)和 AppSquad,感兴趣可以了解。

打通支付与密钥分发

License Distribution Stripe

有了 Stripe 处理支付、Keygen 管理授权,但问题是这两个系统是独立的。用户付完款,还得手动去 Keygen 生成许可证再发邮件——这流程显然不能接受,必须打通自动化。

我的方案是搭一个 Webhook 服务作为中间层(用 n8n 搭建应该也行😉)。核心思路是建立 Stripe 产品与 Keygen 授权策略的映射关系。比如“Zipic Personal - 1 Device”在 Stripe 是一个价格 ID,在 Keygen 对应一个特定的 Policy,服务里配置好这个对应关系。然后在 Stripe 后台注册 Webhook 地址,订阅 checkout.session.completed 等支付完成事件。

用户完成购买后,Stripe 立即向服务发送通知,服务收到后自动完成:

  1. 在 Keygen 中查找或创建用户(基于邮箱)
  2. 根据购买的产品,调用 Keygen API 生成对应的许可证
  3. 通过 Resend 发送邮件,包含许可证密钥和激活说明

整个过程对用户无感,付款成功后几秒钟邮箱就收到许可证了。

踩坑经验:Webhook 幂等性很重要。Stripe 为保证消息送达,同一事件可能发送多次,不做处理用户可能收到多封邮件甚至生成多个许可证。解决方案是记录已处理的事件 ID,重复请求直接跳过。邮件发送也要考虑失败重试,我加了重试队列,同时所有发送记录入库方便排查和手动补发。

接下来

至此,Zipic 终于拥有了一套属于自己的完整分发体系:从代码提交到自动打包公证,从全球支付收款到许可证自动下发,再到用户端的无感增量更新。虽然前期搭建过程非常繁琐,涉及很多并未写在代码里的“坑”,但一旦跑通,它就是一套可以复用于未来任何产品的自动化资产。

搞定了销售的渠道,接下来终于可以回归代码本身了。

在下一篇 技术细节复盘 中,我将分享开发 Zipic 过程中遇到的纯技术挑战:SwiftUI 在 macOS 上的水土不服、如何利用 ImageIO 将内存占用降低千倍、以及 Core Graphics 处理 PDF 的黑科技。

我们下一篇见!