2024年了,我们真的还需要把“首页”做成App的宇宙中心吗?
做鸿蒙应用开发这段时间,我经常被问到的一个问题不是“这个功能怎么实现”,反而是个听起来有点反常识的讨论:未来的鸿蒙 App,还需要“首页”吗?
之所以会冒出这个念头,是因为最近在复盘自己在 DevEco Studio 里折腾的几个鸿蒙 App 小项目。从基于 ArkTS 的界面搭建,到流转、服务卡片、元服务的接入,我发现鸿蒙这套系统对“入口”这件事的理解,跟过去安卓/iOS 时代很不一样。过去我们讲 App 启动,先甩给你一个首页,所有业务从首页这个端点上铺开,它既是导航站、又是流量广场、还是活动弹窗的投放位。但到了鸿蒙这里,从“原子化服务”到“MetaService”再到系统级的意图框架,处处都在渗透一个信息:用户找的是任务结果,不是你的页面层级。
这篇文章我准备从需求切入,聊聊“首页”这个概念在鸿蒙生态里为什么开始松动,再结合我自己开发过程中碰到的真实工程问题,对比一下哪些业务确实离不开首页,哪些业务其实可以拿走,以及如果我们要做“无首页”设计,具体在代码和架构上该怎么下手。
如果你是刚开始接触鸿蒙开发,或者正在准备鸿蒙面试题、想看看纯血鸿蒙下的应用到底和传统 App 有什么本质不同,这篇文章应该能给你一些比较落地的参考。
1. 内容整体设计与思路拆解
1.1 为什么“首页”会成为默认选项
在讨论要不要去掉首页之前,先得想明白首页是怎么变成“天经地义”的。
传统移动应用里,首页的核心价值有三个:第一个是流量分发效率。产品经理会把所有希望用户看到的东西浓缩在首屏,谁的入口位置靠前,谁的点击率就高,这件事在电商、新闻、社交类 App 里特别明显。第二个是业务承载。登录态、消息提醒、推荐流、运营位,全都需要一个稳定的容器来落地。第三个是心智锚点。用户习惯“打开 App 先看首页”,如果有一天打开抖音直接进到某个评论区,很多人会以为 App 出 bug 了。
这三个价值在过去十几年里被放大得越来越厉害,甚至很多 App 的首页已经从“信息展示”变成了“商业竞价排名”。结果就演变出一种畸形状态:首页越来越长、越来越重,用户真正要完成的任务被淹没在运营位、弹窗和红点里。
我在做早期的应用开发时也犯过同样的错误,一上来就把首页设计成信息中枢,结果每次启动都要拉取十几二十个接口,白屏时间一长,卸载率直线上升。后来我开始反思:首页到底是为用户服务的,还是为业务指标服务的?
1.2 鸿蒙给出的根本性变化:入口不再只有一个
鸿蒙和安卓/iOS 一个非常大的区别在于,它从设计之初就不认为“App 启动页”是唯一的服务入口。
鸿蒙的原子化服务可以理解为一种可被系统拆散、单独投放的服务形态。用户不需要先下载一个 App,也不需要在一个大而全的首页里翻找,而是通过服务卡片、碰一碰、扫码或者智能推荐,直接触达某个具体功能。比如你在商场看到一个智能饮水机,用鸿蒙手机碰一碰,不用装 App,就能在服务卡片上完成扫码购水、查看滤芯寿命这些操作。
这背后的技术底座包括:
- 元能力(Ability)的拆分。一个应用可以有多个 Ability,每个 Ability 都可能是独立的入口。
- 服务卡片(Form)可以在桌面上直接展示业务核心信息,比如快递进度、待办事项、运动步数。
- 意图框架(Intents)允许开发者把服务“语义化”地连接给系统,比如用户说“我要打车去机场”,系统可以根据意图直接分发到对应的服务,而不用你先打开某个出行 App 再输入出发地和目的地。
- 跨端流转让同一个任务可以在手机、平板、车机、智慧屏之间接续,而不是每个设备上都有一个“完整 App”。
这些机制放在一起,意味着一个非常关键的变化:用户和能力的距离被大幅缩短,首页这个中间层开始显得多余。
我参与过一个鸿蒙 App 小项目的架构调整,把原本“首页—二级页面—三级页面”的纵深结构,改成“桌面卡片直达列表页”的偏平结构。结果非常出乎意料——核心任务完成率提升了很多,而首页的 PV 和 UV 并没有出现预想中的断崖式下降,因为很多原本被首页挡住的长尾功能,反而通过服务卡片和搜索入口被重新找出来了。
1.3 无首页不是没首页,而是一张“动态首页”
这里必须澄清一点,说“鸿蒙 App 不需要首页”,不等于所有应用都要把首页彻底删掉。更准确的说法是:首页从“固定不变的大杂烩”变成“动态匹配的场景门户”。
在过去,首页的布局基本是产品经理拍脑袋定的:顶部轮播图,中间金刚区,下方信息流,再挂几个运营模块。但鸿蒙的“场景化”思路是:谁在用、在什么设备上用、处于什么任务状态,决定了用户看到什么。
举例来说:
- 一个健身运动 App,在手机上的启动首页可能是训练计划;而在手表上,首页可能直接是心率监测或运动开始按钮。
- 一个智慧办公应用,在平板上打开时首页可能是最近文档列表;在智慧屏上打开时首页可能是正在进行的视频会议入口。
- 一个购物应用,晚上打开时首页可以直接落到“今日达”订单配送进度,而不是千篇一律的“猜你喜欢”。
这种能力的基础,就来自鸿蒙对“设备形态”和“任务上下文”的感知。作为开发者,如果你还在编写一套“所有设备通用”的首页页面,那其实是把自己锁在了旧时代的开发范式里。
所以整篇的探讨,并不是为了推翻首页这个产品形态,而是想理顺一个思路:如果你在考虑做鸿蒙版本的 App,时间精力有限,是不是应该把“首页”的优先级降一降,转而把资源投向卡片、意图、流转这类更贴鸿蒙生态的能力?
2. 核心细节解析与实操要点
2.1 首页模式的四宗罪
很多团队从安卓/iOS 转到鸿蒙时,最容易犯的一个惯性错误,就是把原来的 App 结构原封不动搬过来。这倒不是说搬过来一定不行,而是你要意识到首页模式在鸿蒙生态里存在四个明显的短板。
第一,性能开销不划算。首页是信息密度最大的页面,往往需要同时启动网络请求、图片加载、数据缓存、埋点上报。但在鸿蒙的分布式场景里,用户可能从一个服务卡片点进来,目标是直接看某条订单详情,如果系统还要先经历一次完整首页的初始化,体验就大打折扣了。
第二,信息冗余严重。手机屏幕本来就那么大,硬塞进去几十个模块,用户要为不想要的信息付出注意力成本。放在鸿蒙的“服务找人”理念下,这是违背用户预期的。
第三,跨端适配极其痛苦。如果你开发的是面向手机、平板、车机、手表多端的应用,那么首页的布局逻辑、尺寸适配、交互层级都得分别处理。凡是做过车机适配的人都知道,一个复杂的首页在车机上的可用性往往非常差,驾驶场景不允许用户在信息流里翻找功能。
第四,架构上很难做到服务复用。首页高度定制化,导致 UI、业务、数据和逻辑强耦合,想拆出原子化能力时,得先跟首页这张“蜘蛛网”做斗争。
2.2 鸿蒙里的“去首页化”能力地图
在鸿蒙体系里,如果你决定弱化或者去掉传统首页,可以利用这些关键能力来承接原本首页负责的功能:
- 服务卡片:以 Form 的形式把高频信息直接放到桌面上。用户不用点进 App,就能完成查看、点击、甚至部分操作。卡片支持多种尺寸,可以显示运动步数、天气、快递状态、待办事项等。
- 元服务入口:通过碰一碰、扫码、小艺建议、应用市场等入口直接拉起元服务。开发者可以把单业务功能发布为独立元服务,用户用完即走。
- 意图框架与分发:鸿蒙把“语义理解”引入了系统级导航。比如用户想“支付停车费”,系统根据语义匹配合适的服务,推送相应的元服务卡片或免密支付卡片给用户。
- 跨端流转与接续:手机上看一半的视频,可以流转到智慧屏继续播;车机上发起导航,下车后自动流转到手机继续步行导航。这类场景根本没有“首页”的参与空间,重点在服务和状态的无缝衔接。
- 后台任务与通知:通过 NotificationKit、WorkScheduler 等系统能力,把任务状态主动告知用户,进一步降低用户主动打开 App 找信息的频率。
这些工具组合起来,相当于把原来首页承担的“找入口、看状态、做操作”三个职责,一个个拆解到系统里更轻量、更智能的位置上。
2.3 哪些类型的 App 可以大胆做减法
根据我自己和同行们踩过的坑,以下这些应用类别比较适合优先尝试“去首页化”或“首页极简化”:
- 工具类应用:比如计算器、单位换算、扫码支付、查快递、记账。用户使用路径非常明确,完全可以通过桌面卡片或元服务直达。
- 智能家居类:控制灯光、空调、窗帘,用户要的是“快”,场景触发也比信息流更能解决问题。
- 运动健康类:记录步数、心率、睡眠,卡片就是天然的展示形态,手表端展示效果远好于手机端首页。
- 出行导航类:高频操作用卡片承担,比如实时路线、车牌限行提醒、停车位置记录。
而内容消费类应用(短视频、新闻、社区)短期内其实离不开首页,因为这类产品的核心就是推荐流,用户需要不断接收新内容,首页本身就是内容载体。所以这类应用在设计鸿蒙版时,最优解不是“删掉首页”,而是“首页弱化为服务卡片以外的轻量内容feed”,同时利用鸿蒙的多设备能力把内容无缝切换到不同的屏幕上。
2.4 哪些业务还是得老老实实保留首页
同样,也有一些业务强依赖首页的聚合价值。比如大型电商平台,用户进来可能是为了签到、领券、浏览秒杀,这时候如果直接把用户送进某个商品详情页,可能会损失掉很多额外曝光。再比如金融类应用,功能多、层级深、合规要求高,首页作为导航中枢和风险提示层的意义短期内不可能被替代。
所以我的建议是,别搞“一刀切”。在鸿蒙的框架下你需要做到的是“场景化选择”。用户从桌面卡片进入,就给他卡片对应的服务;用户主动点开 App,再呈现一个完整但精简的首页。首页的存在感,应该从“唯一门户”降级为“多种入口之一”。
3. 实操过程与核心环节实现
3.1 工程架构上先为“无首页”做好准备
这段话写给正在规划鸿蒙项目工程结构的开发者。如果你已经决定做“去首页化”的尝试,第一步不是写页面,而是调整模块划分。
推荐采用HAP/HAR 分离的方式。HAP(HarmonyOS Ability Package)就是一个可独立部署的功能模块,HAR(HarmonyOS Archive)是静态共享包。简单理解,HAP 是可以单独上架、分发和安装的基本单元,HAR 则是公共代码库。
你可以把一个鸿蒙应用工程拆成多个 HAP:
- 第一个 HAP 是传统 App 壳,里面可以保留一个最简首页,用来承接用户主动点击 App 图标。
- 后面的 HAP 各自承载独立的元服务,比如一个“快递服务” HAP,里面就只有一个快递查询页面外加服务卡片。
- 公共的网路请求库、数据存储、工具函数放在 HAR 里,多个 HAP 共用。
注意:在 DevEco Studio 里配置多 HAP 工程时,要留意 module.json5 里的 module.type,以及 ability 的 export 配置。我之前刚开始配置的时候经常因为 ability 没有设置 exported 为 true,导致其他模块无法拉起,报错日志还不怎么明显,排查了半天。
代码层面,一个简单的“元服务直达页面”场景,可以用 Stage 模型来做: 启动一个页面的时候,通过want参数接收来源信息:
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit'; export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { // 通过 want.parameters 来识别用户入口来源 // 比如是从服务卡片进来的,还是从桌面图标进来的 if (want.parameters?.targetPage === 'orderDetail') { AppStorage.setOrCreate('initialPage', 'pages/OrderDetailPage'); } else { AppStorage.setOrCreate('initialPage', 'pages/HomePage'); } } }这么做的好处是,同样一个应用,入口不同,用户看到的第一个页面也不同。
3.2 用服务卡片替代首页的“状态展示”功能
服务卡片是“去首页化”最直接、见效最快的手段。它的主要价值是:高频信息无须打开应用即可看到。
我拿一个运动 App 为例,传统首页上最核心的信息是“今日步数”“卡路里消耗”“运动时长”。这些完全可以用服务卡片直接放到桌面上。卡片实现起来并不复杂,用 ArkTS 写一个 Form 的卡片 UI,再通过formBindingData更新卡片数据即可。
卡片界面的简单 ArkTS 写法大概是这个样子:
let formData = { stepCount: '8562', calories: '326', distance: '5.8km' }; let formBindingData = formProvider.formBindingData(formData);然后在FormExtensionAbility里更新:
import { formProvider, FormBindingData } from '@kit.FormKit'; import { BusinessError } from '@kit.BasicServicesKit'; export default class MotionCardFormAbility extends FormExtensionAbility { onAddForm(want: Want): formBindingData.FormBindingData { return formProvider.formBindingData({ stepCount: '--', calories: '--', distance: '--' }); } onUpdateForm(formId: string) { // 实际项目中这里应该从数据库或者健康服务里拉取最新数据,再调用 updateForm 更新到卡片 let newData: Record<string, Object> = { stepCount: '9000', calories: '388', distance: '6.2km' }; let formInfo: formBindingData.FormBindingData = formProvider.formBindingData(newData); formProvider.updateForm(formId, formInfo).catch((err: BusinessError) => { console.error(`updateForm failed: ${JSON.stringify(err)}`); }); } }我之前在实际开发时踩过的坑是卡片定时更新的频率限制。系统对onUpdateForm的触发有配额限制,不是你想刷就能无限刷。如果用 WorkScheduler 来做后台定时任务,也要注意精度和功耗之间的平衡。经验是:卡片数据优先用“被动刷新”,即数据变化时由服务端推送或端侧感知后立刻更新,而不是定时轮询。
3.3 意图框架和“无首页”的语义连接
鸿蒙的意图框架给我的感受是,它真正在尝试把“找功能”这件事系统化。
比如用户使用“小艺建议”,系统会按照时间、地点、用户习惯,主动推送相关的元服务卡片。作为开发者,我可以在module.json5里声明服务的意图能力。
一段简化的意图声明:
{ "skills": [ { "actions": [ "action.weather.query", "action.express.query" ], "entities": [ { "name": "expressCompany", "value": "sf_express, zto, yto" } ] } ] }这种方式等于告诉系统:我这个服务能处理“查天气”和“查快递”这两个动作,用户在系统层面发起这些请求的时候,我的服务就会被推荐甚至直接拉起。
实际体验下来,这套机制对开发者最大的挑战不在“接入”,而在“语义边界”。你把自己能干什么描述得越具体,系统分发就越精准。但如果描述得过窄,又可能错过潜在流量。我见过有的团队把元服务声明成“万能助手”,结果意图匹配率极低,系统根本听不懂它想表达什么。
3.4 数据层如何支撑“动态首页”和“无首页”决策
无论是保留一个轻首页,还是彻底走“卡片+元服务”的路线,背后都离不开一套统一的数据层来支撑场景决策。
我强烈建议做鸿蒙应用时,不管页面形态怎么变,数据层都单独抽一层,至少在以下几个方面做好基础:
- 统一用户标识:跨端流转的前提是人识别一致,不然手机上的数据到平板上就断片了。
- 场景化数据结构:例如同一个运动数据,在卡片上只需要聚合值,在首页可能需要折线图、排行榜、历史记录。接口设计上最好一次给全,由端侧按场景裁剪。
- 本地缓存与同步:鸿蒙应用特别依赖原子化场景,这意味着用户可能在离线状态下拉起卡片。一定要把最近一次的有效数据放在本地数据库中,不能一没网就白屏。
我自己的做法是,所有从卡片或者元服务入口进来的请求,都走同一个数据仓库层,页面只负责消费 ViewModel 里的数据。这样将来无论你是调整首页布局,还是把某个模块改成卡片,都不需要改业务逻辑。
3.5 从“首页为王”到“任务直达”,怎么过渡
实操中最稳妥的路径不是“今天删首页,明天上卡片”,而是分成四个阶段:
- 盘点高频任务:把现有首页上的功能按“使用频率”和“操作深度”排序。找出前20%的高频任务,它们是最适合卡片化和元服务化的对象。
- 做一套轻量首页:保留必要的信息架构和大促活动位,但把重复轮播、低效入口全部去掉,后台做好灰度开关。
- 卡片和意图逐个落地:每拆一个高频任务,就把对应的亏损数据(点击率、完成率、崩溃率)上线前、上线后各拉一周,确认没有负向影响。
- 逐步走向设备差异化:手机端保留轻首页,手表端用卡片取代首页,车机上直接把首页替换为纯语音任务流。
注意:在整个过渡阶段,千万不要忽略“降级方案”。一旦服务卡片或者意图框架拉起的页面在某个系统版本上出现兼容问题,用户点桌面卡片没反应,是很伤用户体验的。卡片相关内容要加 try/catch 兜底,入口失败时至少能降级到打开主应用的首页。
4. 常见问题与排查技巧实录
4.1 服务卡片数据刷新失败
这是我上手开发时第一个遇到的坑。服务卡片添加成功后,一直显示“--”,怎么调都不出数据。后来发现在 DevEco Studio 里,卡片刷新有两个不同的链路:一种是onAddForm时写入的静态数据,另一种是后续通过formProvider.updateForm更新的数据。
如果你在onAddForm之后立刻调用updateForm,大概率会被系统忽略。正确做法是,在onAddForm里只返回初始数据,然后在onUpdateForm或者自己触发的事件中更新。另外还要检查form_config.json里有没有配置updateEnabled为 true,默认并非总是打开。
4.2 跨端流转不成功
跨端流转对工程代码的要求是“模块尽量无状态”。如果你的页面里到处是全局变量、单例对象、进程内缓存,流转过去后另一台设备就会“失忆”。
我碰到的典型问题:手机上的视频页面流转到平板后,URL 参数传过去了,但播放进度丢掉了。排查许久发现播放进度存在一个局部的静态变量里,并没有写入公共的分布式数据源。
解决方案是使用鸿蒙的分布式数据服务或者把关键状态随流转参数同步过去。一个小技巧是,在流转前把页面状态序列化成一个 JSON 字符串塞进want.parameters,目标端再反序列化恢复。
4.3 元服务入口被系统“冷落”
理论上接入意图框架后,系统会在合适时机推荐你的服务。但实际你会发现,如果刚上架、没有任何用户数据,系统大概率不会轻易推荐。
鸿蒙的做法有点像一个“智能推荐系统”,它需要积累用户使用习惯,才会把合适的服务推到前台。所以不要指望第一天接入意图框架就有大量分发。更好的策略是:同时布局服务卡片、碰一碰入口,把线下和桌面场景的流量先做起来,再让系统后台慢慢学习用户的好感度。
4.4 首页和卡片的埋点体系冲突
团队最容易被忽略的地方是数据口径。过去所有行为都往“首页曝光”“首页点击”上归因,现在很多任务从卡片完成了,首页数据大幅下跌,老板一看就慌了。
我建议从设计开始就把“任务完成率”作为北极星指标,而不是“首页PV”。卡片、元服务、首页都是完成任务的路径,数据报表里应该统一归因到任务维度,按入口分组查看占比,这样才能真实反映“去首页化”有没有带来收益。
| 排查点 | 可能原因 | 解决思路 |
|---|---|---|
| 卡片不更新 | updateEnabled 未开启 / 刷新频率超限 | 检查 form_config;改用重要事件触发更新 |
| 流转后页面空白 | 目标设备没有对应 HAP 或 Ability 未导出 | 检查 module.json5 的 exported 配置;确认目标设备已安装对应模块 |
| 意图匹配不准 | skills 的 actions 描述太宽泛或太窄 | 收敛动作语义,参考系统推荐的 action 列表 |
| 首页数据跌幅大 | 用户迁移到了卡片/元服务路径 | 按任务维度重新归因,不要只看首页指标 |
| 卡片内图片不显示 | 本地资源路径在卡片中不可直接引用 | 使用 media 资源或通过 Base64/URL 方式传递图片 |
| 动态首页卡顿 | 首屏一次性拉取数据过多 | 精简单模块加载,冷启动时只渲染首屏必要组件 |
5. 开发环境与工程配套
5.1 DevEco Studio 与鸿蒙应用工程落地
聊了这么多思路,还是要回到工程上。在真机或者模拟器上跑一个支持“卡片+元服务”的鸿蒙项目,需要用到的核心工具还是 DevEco Studio。现阶段纯血鸿蒙应用的开发,基本都依赖这个 IDE 来配置签名、打包 HAP、调试卡片和元服务。
如果你是刚入手,建议先理解这几个概念:
- API Version:不同版本的系统对应不同的 API 等级,很多新接口只在较新的 API 上开放。
- HAP 与 HAR:HAP 是可部署的功能包,HAR 是共享静态库。项目大了之后,拆模块是线性的必然选择。
- module.json5:每个 HAP 的配置文件,里面可以声明 ability、skills、元服务信息、卡片配置等。
- Entry/HAP 的安装方式:真机调试卡片时,需要把 HAP 安装到设备上,再在桌面手动添加卡片。模拟器的卡片支持也比较成熟,但跨端流转能力的测试基本得靠真机。
工程搭建阶段有个小建议:直接创建“Empty Ability”模板时,默认生成一个 MainAbility 和一个 Index 页面。你在这个基础上去扩展卡片、元服务、流转能力会轻松很多,不要一上来就套复杂的 MVVM 框架,鸿蒙原生状态管理@State、@Prop、@Link、@Observed这些用好了,小项目完全足够。
5.2 使用模拟器和真机测试时的差异
模拟器在开发阶段确实方便,但它不能完全替代真机。尤其是涉及服务卡片、跨端流转、分布式数据管理这类系统级能力,模拟器经常表现得很“理想化”,真机上才会暴露网络权限、硬件能力、功耗调度等真实问题。
我印象比较深的一次:模拟器上卡片刷新特别流畅,一到真机上就频繁失败。后来定位到是真机的后台调度策略更严格,WorkScheduler的最小间隔限制和电池优化策略把定时任务给掐了。所以建议大家在开发鸿蒙应用时,有条件一定要准备至少一台真机,并且保持系统版本尽量新,毕竟鸿蒙迭代速度不慢,旧版本设备对新接口的支持往往会有差别。
6. 结尾:我的实操体会
从“首页是宇宙中心”到“服务应该主动找用户”,这个转变不只是一次 UI 改版,而是整个产品思维和技术架构的调整。我个人在动手做鸿蒙 App 小项目时收获最大的,并不是学会了多少新 API,而是被迫重新去思考:用户真的需要一个“ App”,还是只需要一个“结果”?
如果你现在正准备从零做一个鸿蒙应用,我的建议是,别急着把安卓/iOS 那套首页设计搬过来。先把业务里最高频的几个任务列出来,思考它们在卡片上的形态是什么,在语音场景下怎么表达,在手表上如何呈现。你会发现,当你想明白这些问题时,“首页”到底该长什么样、该承载什么,答案会自己浮现出来。
最后再分享一个小技巧:在做服务卡片或者元服务时,不要只在代码里测试,多花点时间在桌面和小艺建议里真实点一点。很多时候你觉得“这样肯定没问题”的交互,在实际桌面上会暴露出各种细节问题。鸿蒙生态的体验,恰恰就藏在这些细节里。