爱意满满的作品展示区。
MagicCoder

开发了一个进阶版 Apple 健康

  •  
  •   MagicCoder · 16h 43m ago · 1698 views

    前言

    使用 iPhone + Apple Watch 组合有段时间了,当初买的时候,想着用它来记录我的跑步数据,但是坚持了没多久,我就懒惰了,手表最大的作用就成了睡眠监测工具了,由于作息一直比较规律(晚 11 ~早 7 ),就没怎么关注过这些。

    最近半年时间,时不时的熬夜写开源项目,我开始关注自己的健康状况了,打开系统自带的的健康 app 把玩了一番,发现它的数据特别全,但是有几个不好用的地方:

    • 首页的内容比较分散,指标都是以列表的形式进行展示的
    • 指标层级较深,需要切来切去,很多指标我更希望将他们展示到一个大的分类里
    • 指标太单一,大多数时候我并不是只想看某个数据,而是把睡眠、恢复、心率、压力、活动放在一起看,给出更完整的身体状态视角。
    • Apple 只会在你静息心率过高的时候给你发出提醒,而我日常会更关心“最近状态怎么样?哪里变好了?哪里需要注意?”

    IMG_4989

    寻找替代品

    Apple Watch 的销量这么好,肯定不止我一个人觉得自带的软件不好用的。经过一番查找后,找到了几个看着还不错的,把他们都下载下来体验了下,综合下来给我的感觉是:

    • 功能做的太多了,我一眼看过去有点恍惚,接下来我该点什么?
    • 界面做的太卡通了,我比较喜欢简约风格的东西,更贴近系统的设计风格

    自己开发

    体验了 5 款这类软件,始终没找到适合我的,那就只能花点时间开发一个了⚒️

    产品设计

    我给这个应用取名为 VirPulse ,它并不是想取代 Apple 健康,而是把 Apple 健康里已经记录好的数据重新整理一遍,让我能更快看懂自己的状态。

    在设计产品时,我先给自己定了一个原则:不要把 Apple 健康里的所有数据重新抄一遍,也不要一打开软件就塞给用户几十个指标。

    所以整个软件只保留了 3 个主要入口:

    • 首页:快速看懂今天的状态
    • 分析:把多个指标放在一起看
    • 搜索:直接找到某个具体指标

    可能很多人会好奇,为什么这个应用叫VirPulse

    我的上一个作品叫NginxPulse,它将 Nginx 访问日志转换成直观的图表,就像在查看 Nginx 的“生命体征”一样。

    健康数据记录的是一个人每天的身体状态,而心跳又是生命最直接的信号,所以我还是想保留 Pulse 这个词。

    一开始本来想叫 LifePulse ,但是 App Store 里已经有了同名应用。后来我继续从生命力、力量相关的词里寻找灵感,最终从拉丁语Virtus中取了前面的Vir,再和Pulse组合,于是就有了VirPulse这个名字。

    首页

    首页是我每天打开次数最多的地方,所以这里没有放太多复杂的图表,而是先给出一个今日状态评分,再展示睡眠、静息心率、HRV 、步数和活动消耗等信息。

    这个评分不是简单取某一个指标,而是会结合睡眠恢复、身体恢复、活动完成度以及最近一段时间的变化趋势进行计算。

    比如昨晚睡眠时间不够、HRV 下降、静息心率又比平时高,那么软件就会提醒我最近可能需要多休息,而不是只展示几个冷冰冰的数字。

    IMG_4927

    这里的评分主要用于观察个人趋势,不作为医疗诊断。

    分析

    分析页是这个软件的核心功能,我把健康数据分成了运动、睡眠、代谢和压力几个大的分类。

    IMG_4928

    每个分类都不是只看一个数据,例如睡眠分析会同时参考:

    • 睡眠时长和睡眠阶段
    • 入睡、起床时间是否规律
    • 夜间心率和 HRV
    • 血氧、呼吸频率和腕温

    压力状态也不是手表直接提供的数据,而是结合睡眠变化、HRV 、静息心率、活动节律等数据进行估算。

    image-20260622024136831

    时间范围支持近 7 天、近 30 天、近 90 天和自定义日期,可以用来判断某个变化是偶尔出现,还是已经持续了一段时间。

    如果某些数据缺失,软件不会简单按 0 分计算,而是只使用当前已有的数据,并提示这次分析的依据是否完整。

    趋势和搜索

    有时候我并不想看综合分析,只是想确认某个具体指标最近有没有变化,所以做了一个搜索入口。

    IMG_4990

    在这里可以直接搜索睡眠、心率、HRV 、血氧、体重、体脂、腕温等指标。点进去后,可以查看最近记录、平均值、最高值、变化趋势以及这个指标和其他健康状态之间的关系。

    IMG_4991

    IMG_5076

    IMG_5077

    首次连接 Apple 健康时,会先同步最近 90 天的数据,之后再在后台补全近 400 天的历史趋势。

    小组件

    为了减少打开软件的次数,我还做了多套桌面小组件,可以直接查看今日状态、睡眠评分、活动进度、压力状态和生命体征趋势。

    同时也适配了待机显示,晚上给手机充电时,就可以把它当成一个简单的健康状态面板。

    IMG_4933

    界面风格

    界面上没有加入太多卡通元素,整体以深色背景、半透明卡片和系统图标为主,不同颜色只用来区分睡眠、心率、活动等指标。

    image-20260622024656545

    页面切换、下拉刷新、图表拖动和底部 Tab 也尽量遵循 iOS 原生的交互方式,用起来不会有太强的学习成本。

    IMG_4931

    image-20260622024943489

    数据隐私

    健康数据比较敏感,所以 HealthKit 读取到的原始数据、趋势和分析结果都保存在设备本地,相关计算也是在本地完成的。

    服务端主要用于 Apple 账号登录、用户资料和会员状态,不会上传每天的睡眠、心率、步数这些健康记录。

    技术栈

    这是一个原生 iOS 项目,最低支持 iOS 17 ,并针对 iOS 26 的新 Tab 和 Liquid Glass 系统进行了深度适配。

    客户端全部使用 Apple 官方提供的框架,没有引入第三方 UI 和数据处理库,主要技术栈如下:

    • SwiftUI:负责整个软件的界面和交互
    • HealthKit:读取 Apple 健康中的睡眠、心率、HRV 、活动等数据
    • SwiftData:在本地保存健康数据、分析结果和趋势缓存
    • Swift Charts:绘制趋势图、睡眠阶段和指标详情图表
    • WidgetKit:实现桌面小组件和待机显示
    • StoreKit 2:处理月付、年付、永久买断、恢复购买和兑换代码
    • AuthenticationServices:实现通过 Apple 登录
    • URLSession + async/await:和后端接口进行通信
    • Keychain:保存登录令牌

    首次授权时读取最近 90 天数据,后续按天增量同步,同时在后台分批补全近 400 天历史数据。这样既不会让第一次进入软件等待太久,也能保留足够长的趋势数据。

    图表数据比较多时,如果直接在页面切换过程中读取和计算,会明显感觉到卡顿。所以详情页会先打开一个轻量页面,再异步准备数据,等页面切换完成后再挂载图表。

    业务实现主流程:

    3333

    服务端是基于我现有的 Java 项目继续开发的,主要技术栈如下:

    • Spring Boot + Java:提供账号和会员相关接口
    • MyBatis + MySQL:保存用户资料、登录令牌和订阅记录
    • JWT:处理访问令牌和刷新令牌
    • App Store Server API:校验 Apple 交易和会员状态
    • App Store Server Notifications:接收续订、过期和退款等订阅变化

    健康分析并不依赖服务端,服务端主要负责确认“这个用户是谁”和“这个用户是否拥有 Pro 会员”。即使网络暂时不可用,已经同步到本地的健康数据依然可以正常查看。

    获取应用

    VirPulse 现已在全球 App Store 上架,打开 App Store 搜索“VirPulse”即可下载。

    IMG_4992

    写在最后

    至此,文章就分享完毕了。

    我是神奇的程序员,一位前端开发工程师。

    如果你对我感兴趣,请移步我的个人网站,进一步了解。

    33 replies    2026-06-26 00:09:06 +08:00
    GoogolChrome111
        1
    GoogolChrome111  
       16h 13m ago via iPhone
    已下载,点赞
    xy2401
        2
    xy2401  
       16h 4m ago
    居然有服务端吗。我还以为就是读取 apple 数据做一个界面展示的 app
    MagicCoder
        3
    MagicCoder  
    OP
       15h 6m ago
    @xy2401 对,做了服务端的,我做软件喜欢做到极致🤣
    MagicCoder
        4
    MagicCoder  
    OP
       15h 5m ago
    @GoogolChrome111 登陆后还有个抽奖活动的,随机发放永久、年度、月度会员
    CLOUDUH
        5
    CLOUDUH  
       14h 55m ago
    提个建议哦,移动网络和 Wi-Fi 的权限应该在登录之前获取,不然会登录失败一次。
    Lin0936
        6
    Lin0936  
       14h 52m ago
    iOS27 HealthKit 有改动,首次请求权限时默认只给近 30 天的数据
    jonsonk
        7
    jonsonk  
       14h 20m ago via Android
    体验很棒,已经用上了。能增加表盘样式或把桌面小组件的样式添加到表盘就更好了。
    MagicCoder
        8
    MagicCoder  
    OP
       14h 2m ago
    @jonsonk 嗯嗯 我后面开发这功能
    MagicCoder
        9
    MagicCoder  
    OP
       14h 2m ago
    @Lin0936 哦哦哦 这样,我晚点适配下
    MagicCoder
        10
    MagicCoder  
    OP
       14h 2m ago
    @CLOUDUH 奇怪了,我设置的在第一个步骤就请求网络权限了
    Ealrang
        11
    Ealrang  
       13h 8m ago
    支持一下,抽了个年度会员哈哈哈
    erquren
        12
    erquren  
       12h 22m ago
    这个数据是不是能直接用 icloud 存,不用放到服务端
    MagicCoder
        13
    MagicCoder  
    OP
       12h 9m ago
    @erquren 是的,不过我现在没存储用户的这些健康数据,全部放用户本地的,icloud 也没放。我的服务器只放用户的苹果 id 、昵称、头像这些,用来鉴权的
    GoogolChrome111
        14
    GoogolChrome111  
       11h 48m ago via iPhone
    @MagicCoder 谢谢你。我抽到年度会员
    Litchi824
        15
    Litchi824  
       10h 32m ago
    支持, 已下载, 抽到了一个月会员
    粗看了一下数据展现得很清晰明了(对比 AutoSleep), 打算继续体验一段时间

    遇到一个问题, 兑换会员码的时候卡在界面了, 只能强制退出重新进, 然后点几下就又卡着了~(iPhone air)
    mankismi
        16
    mankismi  
       10h 22m ago
    支持一下,另外回报个问题,因为手机是繁体,于 app 内设置语言切换无效,需要到系统设置那边设定语言
    另外求个繁体中文~
    MagicCoder
        17
    MagicCoder  
    OP
       10h 2m ago   ❤️ 1
    @Litchi824 行,我今晚修复下这个兑换问题
    MagicCoder
        18
    MagicCoder  
    OP
       10h 2m ago
    @mankismi 目前只支持简体中文和英文,后面我弄下😂
    keyileba
        19
    keyileba  
       9h 33m ago via iPhone
    已下载,感谢创造分享
    gotOwt
        20
    gotOwt  
       9h 25m ago
    老哥的工作学习态度真的是值得学习。。
    我现在已经摆烂了。。
    从掘金那时候认识你, 一晃你还在学习。。
    加油
    keyileba
        21
    keyileba  
       9h 21m ago via iPhone
    反馈:会有 Apple watch 的小组件吗?比如 hrv 曲线图或者其他总览之类的?或许可以参考同类 app 。
    lifeintools
        22
    lifeintools  
       9h 21m ago
    支持一下
    russ44
        23
    russ44  
       9h 14m ago
    已下载, 在应用内修改语言只能改一部分
    Webpoplayer
        24
    Webpoplayer  
       8h 26m ago
    已下载使用,抽中一次月费
    elboble
        25
    elboble  
       8h 4m ago
    以安装,申请了会员。

    不过我不喜欢戴表睡觉,所以没有睡眠数据,其他资料挺好
    MagicCoder
        26
    MagicCoder  
    OP
       7h 8m ago
    @keyileba 后面会开发 Apple watch 端
    wonderfulcxm
        27
    wonderfulcxm  
       6h 26m ago via iPhone
    哥们,你这静息心率有点高了!
    tyhunter
        28
    tyhunter  
       5h 38m ago
    感谢,抽到了一个年度会员
    MagicCoder
        29
    MagicCoder  
    OP
       4h 22m ago via iPhone
    @wonderfulcxm 现在软件上线了,我可以好好休息了😂 这个软件用了一个月的下班时间写的,天天干到凌晨 2 点,周六日猛猛睡
    wonderfulcxm
        30
    wonderfulcxm  
       3h 58m ago via iPhone
    @MagicCoder 心血之作啊,加油
    hayhong123
        31
    hayhong123  
       3h 51m ago
    支持一下 抽中了个永久会员
    muayang
        32
    muayang  
       1h 5m ago
    感谢创造,下载了 抽中了个永久会员
    SingeeKing
        33
    SingeeKing  
    PRO
       Just Now
    我竟然中了 Lifetime !感谢
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2439 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 82ms · UTC 16:09 · PVG 00:09 · LAX 09:09 · JFK 12:09
    ♥ Do have faith in what you're doing.