当前位置: 首页 > news >正文

做了一个 iOS 订阅管理 App「订阅斩」,用 SwiftData 让「砍掉订阅」变成一件有爽感的事

背景:一笔 ¥68 的扣费引发的项目

上个月翻信用卡账单,发现一笔 ¥68 的扣费,愣了半天才想起来是去年试用的某个 PDF 工具自动续费了。不是因为钱多,而是完全不记得自己还在为它付费。

作为开发者,订阅制产品真的太多了:GitHub Copilot、JetBrains 全家桶、各种云服务、流媒体……每一笔单独看不多,加一起可能占月收入的 5%-10%。

所以我做了「订阅斩」——一个帮自己(也帮别人)管理和砍掉不必要订阅的 iOS App。目前已上架 App Store,版本 v1.2,从立项到上架花了大约 6 周业余时间。

技术选型:SwiftData + 纯 SwiftUI

项目从一开始就决定只支持 iOS 17+,因为我想用 SwiftData。

用过 Core Data 的都知道,NSManagedObject+NSFetchedResultsController+.xcdatamodeld那套写法有多啰嗦。SwiftData 用@Model宏直接标注数据类,配合 SwiftUI 的@Query属性包装器就能自动驱动 UI 刷新,开发体验提升非常明显。

核心数据模型:

@ModelfinalclassSubscription{varid:UUIDvarname:Stringvarprice:Doublevarcycle:Int// 0=月付, 1=季付, 2=年付varisTrial:BoolvarnextBillingDate:Datevarstatus:Int// active / killedvarkilledDate:Date?varisShared:BoolvarmembersCount:Intvaricon:StringvarunsubscribeURL:Stringvarsource:IntvarcategoryStorage:String?}``` 一个 `@Model` 类搞定持久化,不需要 `.xcdatamodeld` 文件,不需要手写 migration policy。至少在目前 v1.2的复杂度下,SwiftData完全够用。 ## 核心计算:统一换算月支出 订阅管理最基本的需求——用户录入的可能是月付 ¥15,也可能是年付 ¥298,需要统一展示「你每个月到底花了多少」。 ```swiftenumBillingCycle:Int,CaseIterable{casemonthly=0casequarterly=1caseyearly=2varmultiplierToMonthly:Double{switchself{case.monthly:1case.quarterly:1.0/3.0case.yearly:1.0/12.0}}}``` 仪表盘汇总时,把每条订阅的 `price*multiplierToMonthly` 求和就是月度总支出。逻辑简单,但很多用户之前从没认真算过这个数。有人录完发现自己每月光订阅就 ¥800+,当场就想取消几个。 ## 「斩」这个交互的设计思路 取消订阅在技术上就是把 `status` 从 active 改成 killed,再记录一个 `killedDate`。没什么复杂的。 但我花了不少时间在交互感受上。普通做法是一个"删除""归档"按钮,我把它包装成了「斩」:动词带攻击性,配合震动反馈(Haptics)和动画,让用户觉得自己在主动止损,而不是在做一个无聊的列表操作。App里有个 `unsubscribeCompletionCount` 计数器,记录用户总共「斩」了多少个订阅,后续计划做成就系统。目前 v1.2先埋了数据。 从用户反馈看,这个设计确实让「取消订阅」这件事变得没那么无聊了。 ## 风险检测:提醒你哪些订阅该斩了 我给每个订阅加了风险等级判断:-**高危**:试用期订阅+距离下次扣费 ≤3天(用户很可能忘了取消试用)--**中危**:超过60天没有打开对应服务(目前靠用户自己标记,后续考虑接ScreenTimeAPI--**低危**:正常使用中的订阅 高危订阅在首页用红色标签高亮,配合本地通知在扣费前7天、3天、1天分别提醒。提醒时间可以在设置里逐个开关。 这个功能实际效果很好——试用期忘记取消是最常见的「冤枉钱」场景,提前提醒能直接帮用户省钱。 ## 降低录入门槛:预设库+OCR手动录入订阅名称、价格、周期,如果太麻烦用户就不会用。所以我做了一个预设库(`SubscriptionCatalog`),内置了几十个常见服务:NetflixYouTubePremiumSpotify、iCloud+NotionGitHubCopilot等。 每个预设包含默认图标、推荐周期、参考价格、是否适合拼车、拼车人数等信息。用户输入名称时做模糊匹配(aliases 数组+字符串包含判断),命中就自动填充,录入时间从30秒缩短到5秒左右。 v1.2还加了一个实验功能:拍账单截图OCR识别订阅信息。做了免费次数限制(按月重置),体验还行但识别准确率不够理想,后面继续优化。 ## 一些技术取舍**iCloud 同步**:用SwiftData+CloudKit做的,默认开启。踩了一个坑——SwiftDataCloudKit同步在 iOS17.0-17.1有偶发的合并冲突问题,升到17.2之后基本稳定。加了手动开关让不信任云同步的用户可以关掉。**多币种**:用户可能有美元订阅(AppStore美区)、港币(AppleTV+港区)等,做了货币符号设置,默认根据设备 locale 推断,覆盖了USD/EUR/GBP/JPY/KRW/TWD/HKD等主要币种。**一个删掉的功能**:最初想做自动跳转到各平台取消订阅页面(存在 `unsubscribeURL` 里),实测发现大部分取消流程都需要登录态,跳过去用户还是得自己操作,引导意义有限。最后保留了URL字段但降低了展示优先级。 ## 给想做工具App的开发者一些建议 这个项目技术难度不高,SwiftData确实降低了不少数据层的工作量。 我觉得订阅管理这个品类最大的挑战不在技术,在于「用户录入意愿」。再好的功能,如果要用户花10分钟手动填20个订阅,大部分人第一步就放弃了。所以预设库、OCR、快速录入这些降低门槛的事情,比花哨的图表功能优先级高得多。 如果你也在做类似的个人工具项目,建议把「减少用户输入」排到 P0。---AppStore搜索「订阅斩」可以下载体验。如果你对SwiftData实践或者工具类App开发有想法,欢迎评论区交流。
http://www.jsqmd.com/news/728226/

相关文章:

  • LoRaWAN网关和节点‘对不上频’怎么办?一文搞懂同频与异频配置(附CN470频段避坑指南)
  • matplotlib
  • 废品回收计价程序,重量,品类,价格上涨,避免商贩虚报压价。
  • 告别环境搭建烦恼:手把手教你用EB Tresos Studio搞定NXP S32K14x的MCAL配置
  • 长芯微LDC081S051完全P2P替代ADC081S051,是一款8位的 ADC 芯片
  • Dify 2026 API网关安全加固:1个配置项禁用GraphQL内省、2行代码启用请求体加密、3分钟验证OpenID Connect Conformance
  • Wireshark ExpertInfo是什么?一文讲透异常分级、适用场景、和传统抓包阅读的区别与排查标准
  • AI智能体记忆系统实战:向量化存储与语义检索架构解析
  • Windows安卓应用无缝安装方案:APK Installer的轻量级革命
  • Atcoder-ABC-455-D [Card Pile Query]
  • 从Python到CAPL:数据转换的思维切换与函数对照手册(Vector CANoe环境)
  • ComfyUI-Manager完整指南:三步掌握节点管理终极技巧
  • python3 安装
  • Android 10 AudioService音频路由实战:手把手教你实现通话时扬声器/听筒的智能切换
  • 从电源到驱动:手把手教你用STM32F407和TPS54360搭建伺服电机控制板(附PCB设计要点)
  • 为什么你的Dify集成总在测试环境崩?揭秘3类隐蔽性OAuth2.1令牌劫持场景及防御型配置模板(含YAML速查表)
  • 保姆级教程:用STC8H的PWMB模块捕获霍尔编码器信号(附完整代码)
  • 观察Taotoken在流量高峰期的API延迟与稳定性表现
  • 告别公式!用C语言查表法搞定NTC测温,附MF52E 10K完整代码与对分查找优化
  • 2026办公室咖啡机推荐:打造高效办公咖啡时光 - 品牌排行榜
  • 【DeepSeek】GRUB介绍
  • 抖音内容下载全攻略:从技术原理到价值延伸的完整解决方案
  • K-Means实战:用Java给你的用户分个群,从数据准备到结果可视化全流程
  • 长期使用 Taotoken 服务后对其模型广场选型便利性的感受
  • 独立开发呼吸训练 iOS App:Swift 帧率自适应动画方案分享与踩坑记录
  • UE5蓝图Cast节点保姆级避坑指南:从接口转换到组件获取的实战技巧
  • 别再只会用shutdown了!Windows计划任务schtasks保姆级教程,定时关机、备份、清理一键搞定
  • Go语言机器人框架golembot:模块化设计与事件驱动架构实践
  • iPhone+UE5.2:用Live Link Face App零成本搞定你的第一个MetaHuman表情动画
  • 轻松掌握Steam成就管理:从入门到精通的全方位指南