我做了一个把专注计时变成「声音护照」的 iOS App,聊聊数据可视化和成长系统的设计思路

最近上线了一个叫「声境护照」的 iOS App,做的事情说起来很简单:番茄钟 + 环境音 + 数据可视化。但我想聊的不是功能本身,而是做这个 App 过程中一些有意思的设计决策------尤其是「把专注数据包装成旅行叙事」这条路到底值不值得走。

从一个具体的厌倦感出发

我用过很多专注类 App,Forest、潮汐、番茄ToDo,都挺好用。但用着用着有个感受:完成了专注,然后呢?数字加一,然后就没了。

说实话,这种「完成即消失」的感觉有点可惜。你花了 25 分钟认真写东西,这件事值得被记住。所以我想做一个让每次专注都留下「印记」的工具。

护照的比喻就是从这里来的------每次专注是一次起飞,声景是目的地,累计时长变成飞行里程,连续打卡天数是你的「航班记录」。

成长系统的数据结构设计

游戏化成长系统是这个 App 最核心的部分,我在 ExpeditionModels.swift 里把整个探险体系建模成章节 + 任务的结构:

swift 复制代码
struct ExpeditionChapterDefinition: Identifiable, Codable, Equatable {
    let id: String
    let sceneId: String
    let cityName: String       // 对应一个声景目的地
    let tagline: String
    let bonusBounces: Int
    let missions: [ExpeditionMissionDefinition]
}

enum ExpeditionMissionKind: String, Codable {
    case sessionCount    // 完成 N 次专注
    case focusMinutes    // 累计 N 分钟
    case deepFocusCount  // 深度专注 N 次
}

每个「城市章节」绑定一个声景 ID,完成章节里的任务才能解锁下一个城市。这样声音选择就不只是 UI 装饰,而是有推进感的目标。

ExpeditionMissionKind 只有三种,我故意控制得很少。试了几个方案,加过「连续打卡天数」「特定时段专注」等类型,最后都删了------任务类型越多,用户反而不知道该干什么。

会话战报的「下一步建议」逻辑

每次专注结束会弹出一张战报,这个战报除了展示当次数据,还会给出下一次专注的建议。这个逻辑在 SessionReportSheetViewModel 里:

swift 复制代码
func nextActionAdvice(taskCompleted: Bool) -> SessionNextActionAdvice {
    let remainingTodayPlan = max(0,
        store.weeklyPlanTodayTargetSegments - store.weeklyPlanTodayActualSegments
    )
    let streakHint: String
    if store.streakDays >= 5 {
        streakHint = "你已连续 \(store.streakDays) 天,重点是稳定复用。"
    } else if store.streakDays >= 2 {
        streakHint = "再坚持 1-2 天可进入稳定习惯区。"
    } else {
        streakHint = "建议先连续 3 天完成每日最小闭环。"
    }
    // ...
}

这里有个取舍:建议文案是写死的字符串模板,不是 AI 生成的。我考虑过接 LLM,但一来成本不好控制,二来我发现这类「行为引导」场景其实不需要千变万化的文案,固定的几条反而更有仪式感,用户知道这是 App 在认真跟踪自己的状态。

连续天数的分层(1天 / 2-4天 / 5天以上)是我根据习惯养成的一般规律拍的,不是什么严格实验得出的结论。连续 3 天是个心理门槛,5 天以上用户大概率已经进入节奏了,策略应该从「建立习惯」切换到「维持节奏」。

分享卡片:让专注数据变成内容

这是我觉得最值得展开讲的部分。

专注类 App 的自然增长渠道几乎只有两条:AppStore 搜索,和用户分享。Forest 靠的是「种了一棵树」的视觉,潮汐靠的是精美的音景截图。我的切入点是「数据卡片」------把当次战报或周回顾渲染成一张可以直接发朋友圈的图片。

ShareCardFormatter 负责格式化卡片里的时间信息,战报卡片、成就徽章卡片、周回顾卡片用的日期格式各不相同(yyyy/MM/dd HH:mm vs yyyy/MM/dd),看起来细节,但如果格式乱掉整张卡片的质感就垮了。

卡片设计我做了三个版本,第一版太「仪表盘」,数字密密麻麻;第二版太「极简」,信息量不够,朋友看不出你做了什么;第三版找到了平衡------突出时长和等级称号,次要展示声景和任务名,底部放一行小字的里程数。

StatsService 和 GrowthService 的分层

统计相关的逻辑我拆成了两个 Service:

  • StatsService:纯数据聚合,负责按时间范围汇总 FocusLog,输出 StatsData
  • GrowthService:负责把 FocusLog 转换成 GrowthProfile,计算等级、经验值、称号

这两个 Service 都是无状态的纯函数风格,输入 logs 数组输出结果,在多个 ViewModel(StatsSheetViewModelProfileSheetViewModelWeekReviewSheetViewModel)里复用。

有一个小设计:当 focusLogs 为空时,会调用 StatsService.createDemoFocusLogs() 生成演示数据。新用户第一次打开统计页不会看到空白界面,而是看到一个「如果你用了两周会是什么样子」的预览。这个 onboarding 细节我觉得挺重要------空页面对新用户很劝退。

现在的状态和一些遗憾

App 刚上线 1.3 版本,下载量还很少,老实说基本还在 0 起步阶段。

有几个功能是做到一半放在 _disabled_features 目录里的------统计报告、周回顾、分享卡片这些模块代码都写完了,但 UI 打磨还不够,我没有在 1.3 开放。这种「功能写完了但藏起来」的状态有点难受,但比发出去然后体验很差要好。

声景库目前内容量不够丰富,「东京雨夜」「咖啡馆白噪音」这类场景音是有的,但城市章节太少,探险系统的推进感不强。这是接下来要重点补的。

还有一个我没想清楚的问题:护照 + 飞行里程这套叙事对喜欢旅行的用户很有共鸣,但对完全不在意这个比喻的用户来说可能显得有点奇怪。这个产品定位的边界到底在哪,我还在摸索。


如果你也在做类似的「工具 + 游戏化」方向的 iOS App,或者对专注类产品有什么看法,欢迎在评论区聊聊------我对「游戏化到底会不会让用户厌倦」这个问题挺好奇的,想听不同角度的判断。

相关推荐
SameX1 小时前
我用 SpriteKit 给存钱罐装了个物理引擎
ios
开心就好20252 小时前
Charles配置HTTP和HTTPS抓包完整指南
后端·ios
JarvanMo2 小时前
7 个开源 iOS 应用,让你成为更好的开发者
前端·ios
白玉cfc2 小时前
OC底层原理:alloc&init&new
c++·macos·ios·objective-c·xcode
ZZH_AI项目交付2 小时前
一个 iOS 埋点 SDK 从 0 到 1,再到真实项目接入打磨
ios·app·ai编程
2501_915918413 小时前
使用快蝎IDE进行iOS开发:从项目创建到真机调试全流程
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
iFlyCai3 小时前
iOS开发进阶:深入理解 Getter 与 Setter 的用法(超详细)
ios·objective-c·xcode
2501_9160088916 小时前
深入解析iOS应用启动性能优化策略与实践
android·ios·性能优化·小程序·uni-app·cocoa·iphone
美狐美颜SDK开放平台17 小时前
短视频/直播双场景美颜SDK开发方案:接入、功能、架构详解
android·ios·美颜sdk·第三方美颜sdk·视频美颜sdk