尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

鸿蒙健康App开发实战:ArkTS实现计步、提醒与桌面卡片

鸿蒙健康App开发实战:ArkTS实现计步、提醒与桌面卡片 简介该案例是一套基于HarmonyOS开发的健康管理应用源码面向初入鸿蒙移动开发的学习者演示饮食记录、热量统计与运动消耗等核心功能模块。项目包含登录授权流程、饮食统计页面、食物列表及详情页用户可手动添加食品并对应热量结合日期选择与首选项持久化实现数据留存。压缩包共427个文件以ets、js、ts等源码文件为主搭配json配置和png/svg界面资源整体约23.25MB目录结构清晰便于按页面拆解学习。资源目前已有788人学习下载适合需要参考完整鸿蒙项目架构、理解状态管理与页面跳转逻辑的开发者。通过源码可快速掌握欢迎页授权判断、统计图表展示、列表交互等典型场景的落地写法并可直接二次扩展为完整健康管理工具。 健康类App一直是我比较愿意花时间研究的品类用户需求清晰功能边界也容易划清楚。最近我用HarmonyOS的ArkTS把一套完整的健康管理App从零到一做了出来覆盖计步、心率记录、用药提醒、饮食打卡、数据统计和桌面卡片也踩了不少坑。如果你正准备用鸿蒙开发健康方向的应用或者刚上手ArkTS想找一套能跑通的项目结构这篇文章值得多看几遍。文中操作基于DevEco Studio 5.0.3 Release和HarmonyOS 5.0API 12实践过但大部分思路在API 9之后也能复用核心逻辑不受版本限制。先说明一点健康类App最容易踩的坑不是UI写不出来而是权限、传感器、后台调度、数据一致性这些“看不见”的部分。所以我不打算只贴几个页面截图而是把整个项目的拆分方式、关键代码、遇到的问题和排查路径都讲清楚尽量让你在动手之前就把雷排掉。1. 案例定位与整体设计思路1.1 为什么选鸿蒙做健康App鸿蒙做健康方向有天然优势主要体现在三点。第一是系统级的传感器与健康能力接入。计步、心率、睡眠等数据不需要自己造轮子系统提供了统一接口比Android里各家厂商做各种定制适配要省心不少。第二是服务卡片。健康数据非常适合放在桌面卡片上用户不点开App也能看到步数和提醒这对健康类应用的使用频率和用户粘性帮助很大。第三是鸿蒙当前处于应用生态扩张期健康类精品应用还没有完全饱和现在进入的时间窗口相对友好。劣势也明显开发资料比Android/iOS少论坛里答案质量参差不齐很多API在版本之间变更较大。所以我建议以官方文档为主社区经验只做辅助尤其是权限和传感器部分版本不同差异可能很大。1.2 功能模块拆解与选型这套案例我规划了六个核心模块每个模块对应不同的鸿蒙系统能力功能模块核心需求使用到的系统能力计步记录每日步数、展示趋势Sensor Service Kit、RDB数据库心率记录支持手动录入和趋势统计自定义表单、图表组件用药提醒按时弹出通知代理提醒ReminderAgent打卡记录喝水、饮食、体重本地数据库、列表与统计数据看板按日/周/月汇总SQL聚合查询、图表绘制桌面卡片不打开App直接看核心数据Form Extension Ability选型上我没有一开始就引入复杂后端。MVP阶段全部用本地存储数据表结构设计好后续要接云同步时直接加一层网络同步即可。这样做的好处是开发节奏快不需要处理登录、token、服务器部署等一系列问题适合作为学习和起步阶段的案例。1.3 工程结构规划工程我拆成了三个部分而不是全部堆在一个entry模块里entry模块主应用入口负责页面跳转、UI展示、权限申请。common模块HAR放公共工具类、常量定义、数据库管理类。卡片模块在entry内部建Form Extension Ability负责桌面卡片数据与更新。实际目录结构大致如下/AppScope /entry /src/main/ets /entryability /pages // 主页面 /view // 列表、图表、卡片组件 /common // 工具类、常量 /database // RDB建表与DAO操作 /service // 计步、提醒服务封装 /src/main/resources // 资源文件 /src/main/module.json5这种拆分的好处是公共逻辑不会和页面耦合后续如果需要做平板适配或元服务独立版本可以直接复用common模块不用到处复制代码。2. 开发环境准备与工程搭建2.1 DevEco Studio版本与SDK选择开发工具优先选择DevEco Studio最新稳定版。我使用的是5.0.3 Release配套SDK API 12编译目标也是API 12。如果你下载的版本更高比如API 13或API 14也问题不大但要注意接口变更尤其是传感器和提醒相关的API。这里有一个很多人忽略的点模拟器对健康类App支持非常有限。模拟器里能跑UI、看布局但计步传感器数据是模拟的心率就更不用说了。所以做健康数据功能建议尽早申请一台真机作为调试设备。哪怕不是最贵的新机型只要是支持鸿蒙NEXT的普通手机就够用。2.2 创建工程与module配置在DevEco Studio里选择Empty Ability模板包名建议用域名反写比如com.example.healthapp。工程创建后会自动生成module.json5后续权限声明和卡片配置都在这个文件里做。以下是module.json5里比较基础的部分只保留健康App相关的权限占位实际权限名需要以你使用的SDK为准{ module: { name: entry, type: entry, requestPermissions: [ { name: ohos.permission.ACTIVITY_MOTION, reason: 用于记录每日步数和运动状态, usedScene: { abilities: [EntryAbility] } } ] } }注意权限的reason字段在应用市场上架审核时会重点检查不要写“用于改善用户体验”这种模糊表述。要具体说明该权限用于哪个功能比如“用于统计每日步数”通过的几率会高很多。2.3 真机调试签名配置工程默认使用自动签名但前提是你在DevEco Studio里登录了账号并且手机开启了开发者模式。真机连接后在Project Structure里检查Signing Configs勾选Automatically generate signature确保证书、profile和包名匹配。很多新手在模拟器上跑通后一上真机就报签名错误或安装失败90%是因为自动签名没有正确同步。遇到这类问题先断开手机重连再重新登录账号让DevEco Studio重新生成签名文件通常能解决。3. 核心功能实现与代码解析3.1 计步模块传感器读取与基准步数处理计步是健康App最基本的功能。鸿蒙的Sensor Service Kit提供了STEP_COUNTER传感器可以读取设备累计步数。import { sensor } from kit.SensorServiceKit; let stepCount 0; sensor.onSensorData(sensor.SensorId.STEP_COUNTER, (data: sensor.SensorData) { stepCount data.steps; console.info(当前累计步数: ${stepCount}); });这里有一个非常关键的坑STEP_COUNTER返回的是设备从开机到现在的累计步数不是你打开App之后的步数。如果直接把这个数字展示给用户重启手机或者长期使用后数字会异常大用户完全看不出当天走了多少步。我的处理方式是在本地数据库存一个“基准步数”字段。用户当天第一次进入App时把当时的传感器步数记为baseline之后用当前步数减去baseline得到今日步数。到了第二天零点重新读取一次传感器值作为新基准。const currentTodaySteps currentSensorSteps - baselineSteps;再配合日期判断就能实现“每天清零但物理累计不丢”的效果。这个逻辑看着简单但如果不提前想清楚后面数据会非常混乱。建议在设计表结构时就把baseline字段单独存。3.2 健康数据存储RDB关系型数据库步数、心率、饮水、体重这些都是结构化数据我选用鸿蒙自带的Relational StoreRDB数据库。建表语句如下CREATE TABLE IF NOT EXISTS health_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT NOT NULL, value INTEGER NOT NULL, unit TEXT NOT NULL, record_date TEXT NOT NULL, create_time INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS idx_record_date ON health_data(record_date);type字段用来区分数据类型比如step、heart_rate、water、weightrecord_date统一用yyyy-MM-dd格式的文本存储方便按天、按周、按月进行GROUP BY聚合查询。在ArkTS中操作RDB的大致流程是import { relationalStore } from kit.ArkData; let store: relationalStore.RdbStore; const config: relationalStore.StoreConfig { name: health.db, securityLevel: relationalStore.SecurityLevel.S1 }; relationalStore.getRdbStore(this.context, config, (err, rdbStore) { if (err) { console.error(创建数据库失败: ${err.message}); return; } store rdbStore; store.executeSql(CREATE TABLE IF NOT EXISTS ...); });创建好store之后所有插入、查询都通过这个store实例操作。这里建议做一个统一的DataManager单例把所有SQL都封装成方法比如saveSteps、queryByDate、getWeeklyStatistic。不要在页面里直接写SQL否则后续改表结构时页面的代码会乱成一团。3.3 今日数据看板与图表呈现数据看板是让用户感知到App价值的地方。我的实现是首页顶部显示今日步数、今日喝水杯数、最近一次心率和体重下面用一张曲线图展示最近7天的步数变化。曲线图可以使用鸿蒙自带的Canvas绘制也可以用第三方图表库。如果你不想太早引入依赖可以先画一个简单的柱状图用Row容器每个柱子的高度根据步数值等比例换算。这种方案胜在代码量少、易调试数据变化也能直观展示。柱状图高度计算时要注意除零问题。步数最大可能值不确定建议用最近7天最大值作为分母每个柱子的高度比例限制在0.1到1之间避免某天数据异常导致整个图表变形。3.4 用药提醒代理提醒与权限吃药提醒这类功能不能只靠App在前台时弹一个对话框用户关掉App就失效了。鸿蒙提供了代理提醒能力可以把提醒任务交给系统即使App不在前台也能按时触发。创建提醒任务的关键代码思路import { reminderAgentManager } from kit.BackgroundTasksKit; let reminderInfo { reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM, title: 用药提醒, content: 该吃降压药了, triggerTime: { hour: 8, minute: 30 } }; reminderAgentManager.publishReminder(reminderInfo) .then((reminderId: number) { console.info(提醒创建成功ID: ${reminderId}); }) .catch((err: Error) { console.error(创建提醒失败: ${err.message}); });注意代理提醒需要在module.json5里声明对应权限并且在运行时动态申请用户授权。如果用户拒绝了提醒权限需要引导用户去系统设置里开启。另外提醒文案不要诱导用户“立即点击”应当只作为信息提示避免审核问题。3.5 桌面卡片让健康数据一眼可见桌面卡片是鸿蒙体验上和Android/iOS拉开差距的地方。我实现了2x2和2x4两种卡片分别展示“今日步数”和“今日打卡完成度”。卡片开发原理是在entry模块里创建FormExtensionAbility通过formBindingData提供数据系统负责渲染卡片UI。卡片需要支持数据更新我的做法是通过定时刷新机制每隔30分钟重新拉取一次本地数据库的最新数据然后调用formProvider.updateForm更新卡片。卡片的数据获取逻辑要和App主线程分开不能直接依赖某个页面实例。建议把卡片数据查询封装成一个独立工具类只依赖Context和数据库store这样可以避免页面生命周期和卡片刷新互相影响。4. 真机调试、打包与发布要点4.1 模拟器能做的事和不能做的事如果用模拟器做健康App你会发现UI布局、数据库操作、页面跳转都能正常但传感器回调可能完全没有数据或者返回固定模拟值。这会导致你误以为代码写错了。我的建议是把模拟器当成“UI调试器”把所有传感器相关功能放到真机上验证不要浪费太多时间尝试让模拟器模拟计步。心率部分如果也是读取传感器真机上还需要稳定放置一段时间才能有数据。测试时不要把手机拿在手里晃否则数据波动会很严重你会误以为是采样代码写错了。4.2 HAP、HSP、HAR怎么分很多新手分不清这三者的差别简单讲HAP是应用安装包一个应用可以有多个HAP但至少有一个entry类型HAP。HAR是静态共享包编译时会打包到引用方适合放工具类、常量、基础组件。HSP是动态共享包运行时加载适合多个HAP共享业务代码体积优化更明显。健康App这种项目初期不需要把模块拆得过于复杂。我建议把common和database做成HAR引用即可。等后续要开发手表版、平板版多个HAP需要共用逻辑时再把公共部分改成HSP。打包成App Pack时DevEco Studio会自动处理签名和包结构。注意一点HAR被修改后依赖它的模块必须重新编译否则可能出现改了代码但运行效果没变的诡异情况。遇到这种问题先Clean Project再重新Build。4.3 上架审核中健康类App特别容易被卡的地方健康类应用涉及到个人健康数据审核会比普通工具类严格不少。我提炼了三个必须提前处理好的点。第一隐私政策里必须明确列出收集哪些数据、存哪里、用于什么目的。本地存储也不能说“不收集”因为步数、体重这些本身就是健康数据。第二权限申请说明要具体。ACTIVITY_MOTION这种权限申请理由不能是“提升用户体验”要写“记录每日步数以展示运动趋势”。审核人员会对照功能实际使用情况检查。第三谨慎处理“医疗建议”相关表述。如果App只是记录数据就不要在文案里出现“辅助治疗”“诊断”等词汇。我在案例里统一用“健康数据管理”来定位避免被误判为医疗类应用而要求额外资质。5. 常见问题与排查技巧实录5.1 授权成功了但传感器没有回调这个问题我遇到过两次。一次是手机系统设置里“运动与健康”权限被关了本身App申请了权限但系统级开关没打开传感器不会返回数据。另一次是代码在页面onPageShow里注册了监听但页面退到后台后监听被系统回收。排查建议先看系统设置里是否允许该应用使用运动数据再检查onSensorData注册时机。如果页面不可见应该把传感器监听放到Ability或Service中页面只负责展示数据。5.2 App切后台一段时间后步数不更新健康App最尴尬的情况是用户带着手机走了一万步打开App一看还是早上那个数字。原因是传感器监听是前台短时任务App切后台后一段时间系统可能挂起进程回调自然就断了。我的方案是前台页面始终实时监听App退到后台后通过代理提醒或后台任务机制每30分钟拉一次系统传感器最新值同步到数据库。这里不需要保持传感器一直不释放那样既耗电又容易被系统判定为异常。5.3 RDB插入数据后列表不刷新如果你用ForEach渲染数据库列表插入新记录后没有刷新最常见的写法错误是先更新了数据库但页面绑定的数据源没有变化。必须记住页面数据源是一个普通数组或状态变量数据库不会自动通知页面更新。正确做法是插入数据库后重新执行一次查询把最新结果赋值给数据源this.dataList await this.dataManager.queryByDate(today);如果是并发写入频繁的场景还要注意查询和插入不能同时抢store实例可以在DataManager内部用队列把写入操作串行化避免SQLite锁冲突。5.4 桌面卡片一直显示旧数据卡片刷新不及时大概率是更新机制没有搭对。卡片有两种更新路径一种是定时刷新受系统节电策略影响最短间隔有限制另一种是主动推送更新由App端调用formProvider.updateForm。健康App要展示步数只靠定时刷新很容易滞后建议在关键节点主动推送比如用户打开App主动刷新一次或者步数变化超过500步时更新一次。如果检查发现主动更新调用了但卡片没变先看更新时传入的formId是否和卡片创建时拿到的formId一致。这个formId在卡片每次创建时都可能不同不能写死缓存。最后再分享一个我做这套案例时感受很深的点健康App最核心的不是某个炫酷页面而是把数据从传感器/用户输入到数据库到UI展示再到卡片和提醒的整条链路打通。这个过程中最耗时间的往往不是UI开发而是数据一致性、权限合规和后台场景适配。如果你正卡在某一个环节希望上面的排查思路能帮你少走几步弯路。本文还有配套的精品资源点击获取
返回列表