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

HarmonyOS应用实战-启示散页-09-HAP、HAR、HSP 不要混着放:用模块边界守住答案之书

HarmonyOS应用实战-启示散页-09-HAP、HAR、HSP 不要混着放:用模块边界守住答案之书

答案之书虽然是轻量应用,但工程结构里已经出现主入口、公共模型、功能页面、资源和发布配置。如果 HAP、HAR、HSP 混着放,短期不一定编译失败,长期一定会出现资源找不到、依赖反向、公共层引用页面层这类问题。模块边界不是大项目专属,小应用越早守住边界,后续迭代越轻。

这篇文章会把问题拆成四个可落地的点:

  1. 区分 entry HAP、公共 HAR、功能 HSP 的责任。
  2. 资源跟随模块归属,不让页面跨模块偷资源。
  3. 公共层只放模型、常量和无 UI 业务工具。
  4. 用依赖方向和发布构建验证模块拆分是否健康。


1. 先定义模块责任

HAP 是应用入口,负责 Ability、窗口、路由挂载和发布配置;HAR 更适合放模型、常量、工具和纯逻辑;HSP 可以承载可独立复用的功能页面或资源。答案之书不需要为了拆而拆,但已经拆开的部分必须有清晰归属。

entry HAP:EntryAbility、pages/Index、module.json5、启动图标 common HAR:models、constants、id、formatter、validation feature HSP:DrawingPage、题库功能页、局部资源

边界的目标是让依赖方向稳定,而不是追求目录数量。

2. 公共层不能引用页面层

最危险的反向依赖是 common 里为了方便拿 Toast、NavPathStack 或页面资源。公共层一旦引用页面层,所有模块都会被迫知道 UI 细节。答案之书的 common 只放类型和纯函数,页面行为留在 entry 或 feature。

// common/src/main/ets/models/Deck.tsexportinterfaceDeck{id:string;name:string;builtIn:boolean;answers:Answer[];createdAt:number;updatedAt:number;}

模型可以被所有层引用,但模型不能知道页面怎么展示、怎么跳转、怎么弹 Toast。

3. 服务层依赖 Repository,不依赖页面

DeckService、FavoriteService、HistoryService 可以依赖 Repository 和模型,但不应该引用具体页面。这样 DrawingPage、DeckEditorPage、HistorySheet 都能复用同一套业务能力。

exportclassDeckService{asyncsave(payload:SaveDeckPayload):Promise<Deck>{constdeck:Deck=this.createDeck(payload);awaitDeckRepository.saveDeck(deck);AppStorage.setOrCreate(AppStorageKey.LastDeckUpdateAt,deck.updatedAt);returndeck;}}

Service 可以发刷新信号,但不要知道哪个页面会刷新。页面订阅信号,业务层只表达数据变化。

4. 资源跟着拥有者走

模块拆分后,资源最容易错放。DrawingPage 的局部背景、动画素材如果属于 feature,就放 feature 的 resources;应用图标、启动页图标属于 entry。不要让 HSP 页面长期引用 entry 的私有图片,否则拆包后路径很容易断。

{"module":{"name":"entry","type":"entry","abilities":[{"name":"EntryAbility","icon":"$media:app_icon","startWindowIcon":"$media:startIcon"}]}}

资源引用要能回答“这个资源归谁发布”。如果答案不清楚,后面做包体压缩和上架素材核对会很痛苦。

5. 路由表不要散在多个页面

如果使用 Navigation,路由名和页面构建器应该集中管理。首页 push DrawingPage,收藏页 push DeckEditor,都应该使用同一套 RouteName,避免字符串散落导致点击无响应。

exportclassRouteName{staticreadonlyDrawing:string='DrawingPage';staticreadonlyDeckEditor:string='DeckEditorPage';staticreadonlyFavorites:string='FavoritesPage';}

路由名属于工程协议。集中后,模块迁移或页面改名时才有确定修改点。

6. HSP 边界要看依赖方向

HSP 可以承载能力,但不应该反过来依赖 entry。比如 DrawingPage 如果放在 HSP,它可以依赖 common 的模型和服务接口,但不能直接读 entry 的EntryAbility或 entry 私有资源。

{"dependencies":{"common":"file:../common","drawingFeature":"file:../drawingFeature"}}

依赖应该从入口指向功能,从功能指向公共。反过来就说明模块边界已经被打穿。

7. 包体优化要以模块为单位看

答案之书的资源压缩和包体控制不能只看最终 HAP 大小。要知道哪些图片属于启动页,哪些属于动画,哪些 rawfile 是默认题库。模块边界清楚后,包体变大时才能定位到具体模块。

Get-ChildItem.\entry\build\default\outputs-Recurse-Filter*.hap|Select-ObjectFullName,LengthGet-ChildItem.\libraryHSP\src\main\resources\base\media|Sort-ObjectLength-Descending|Select-Object-First 10 Name,Length

包体排查不是最后一步才做的事。模块资源归属越清楚,发布前越容易解释体积变化。

8. 模块拆分后要跑构建闭环

只看源码目录不能证明模块边界正确。拆分、迁移资源、调整依赖后,要跑hvigorw assembleHap --no-daemon,并重点看资源找不到、依赖循环、路由目标缺失这类错误。

&'.\hvigorw.bat'assembleHap--no-daemon hdc shell hilog|Select-String'RouteName|ResourceManager|EntryAbility'

构建通过说明依赖和资源基本闭合,但路由点击和资源展示仍需要真机或模拟器走一遍。

9. 验证与排障

模块边界验证要从依赖、资源、路由、发布四个角度看。页面能打开只是其中一项,更要确认公共层没有引用页面、功能资源没有借 entry 私有资源、发布构建没有临时文件。

验证点: 1. common 中不出现 pages、promptAction、NavPathStack 2. feature 页面引用自己的 media 或公共资源 3. RouteName 集中定义,没有散落字符串 4. assembleHap --no-daemon 成功 5. 真机点击首页、题库、收藏、历史入口都能进入目标页

如果拆包后资源缺失,优先查资源归属和模块依赖,不要先把图片复制到所有模块。

还有一个实用判断:如果一个文件移动到别的模块后,需要顺手改一堆业务规则,说明它本来就不该被当成公共能力;如果只需要调整 import 和资源引用,说明边界相对健康。答案之书这种轻量应用不需要复杂架构,但要避免页面、服务、资源和发布配置互相绑死。

拆模块时也不要把“复用”理解成所有东西都上移。题库模型、答案模型、时间格式化这类稳定能力可以放公共层;DrawingPage 的动效参数、启动页插图、收藏页布局属于具体体验,留在功能或入口模块更合适。公共层越克制,后面越少出现所有模块都被迫重新构建的情况。

发布前还可以做一次反向搜索:在 common 里搜索pages/EntryAbilitypromptActionNavPathStack,在 feature 里搜索 entry 私有资源名。搜索结果不一定全是错误,但每一处都值得解释清楚。

解释不清的依赖,通常就是下一次维护的故障点。

验证清单

  • 清应用数据后从冷启动进入,确认默认数据、页面状态和日志分支符合预期。
  • 对本文涉及的写路径准备正常、空值、重复、越界四类输入,确认错误停在 Service 或 Repository。
  • 页面返回、重新进入、切换题库、收藏、历史或删除后,确认对应刷新信号触发重新读取。
  • 修改资源或模块归属后重新构建,确认 HAP、HAR、HSP 的依赖方向没有反转。
  • 涉及真机体验、备份恢复、发布素材的内容,单独记录是否已经在设备或平台侧验证。

常见问题与处理

现象先看哪里处理方式
拆包后图片不显示资源是否放在页面所属模块把局部资源迁到 feature,公共资源放公共资源模块
common 编译依赖 entry公共层是否引用页面 APIcommon 只保留模型和纯工具
点击入口无响应RouteName 是否散落或拼错集中路由协议并逐入口验证
包体突然变大资源是否重复放多模块按模块统计 media/rawfile 大小

小结

HAP、HAR、HSP 的边界不是形式,而是依赖方向、资源归属和发布可控性。小应用先把边界守住,后面加动画、导入、收藏和发布清单才不会越写越乱。

http://www.jsqmd.com/news/1236294/

相关文章:

  • nebula.gl核心功能解析:10个必学的EditableGeoJsonLayer使用技巧
  • 常见问题解决:grunt-responsive-images错误排查与调试技巧大全
  • 希音SHEIN的ESG治理包括哪些方面?从环境治理、社会责任与公司治理看全球经营韧性
  • 终极指南:如何在Switch上快速安装手柄优化的B站客户端wiliwili
  • 数据科学项目实战:结合Data-Science-EBooks资源的学习方法
  • 昆山全域打井报价明细!家用井 / 工厂水井 / 工地降水井 10-100 米 50-100 元一米全包 - 瑞溪泉水利
  • 异地上班族不用跑腿,函授死档线上激活指南 - 资讯在线
  • Simple-Unity-Audio-Manager实战:3个案例教你玩转游戏音效
  • 【小程序毕业设计】基于微信小程序的传统中医文化科普系统 中医知识库查询与养生推荐小程序设计(源码+文档+远程调试,全bao定制等)
  • PHP Agentic框架:构建智能代理系统的实践指南
  • 【小程序毕业设计】基于 SSM + 微信小程序的小区物业综合服务系统 轻量化社区物业便民服务管理小程序(源码+文档+远程调试,全bao定制等)
  • 终极指南:如何在iOS/macOS应用中快速集成CocoaMQTT 5.0客户端
  • AI短视频完播率断崖式增长:3类被92%运营团队忽略的注意力锚点设计法则
  • 5分钟快速部署指南:让开源GIMP拥有Photoshop专业体验
  • 微信聊天记录本地化解析:如何构建个人数据主权与价值挖掘系统
  • 2026巴彦淖尔第三方验房检测排名 TOP5 CMA 资质提供房屋质量检测、水电验收、墙面地面检测一站式服务 联系方式推荐 - 科信检测
  • 实战秘籍:EmojiOne Color彩色字体让你的设计瞬间出彩
  • 成考死档激活全解析:毕业生政审被卡,根源都在自持档案 - 资讯在线
  • Spring Boot 3 + Vue 3 + MySQL 苗族刺绣数字化平台源码 前后端分离实战项目
  • 《时序数据模型KES TimeSeries:如何构建在KES融合数据库架构原生能力》
  • 【小程序毕业设计】民宿房源展示与订单管理系统(SSM) 基于 SSM 的民宿住宿服务运维小程序(源码+文档+远程调试,全bao定制等)
  • BilibiliDown终极指南:高效解决B站视频下载难题的跨平台工具
  • AI技术前沿动态简报(2026.07.21)
  • 大盘高位出金指南!海口无克扣黄金回收门店全盘点,全天在线估价 - 奢侈品回收知识分享
  • 【JAVA毕设源码分享】基于springboot社区团购系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 解密apt-offline:智能离线包管理的5个高效工作流
  • 2026深圳劳动仲裁公司排名:预算档位推荐表 - 资讯纵览
  • YOLOv8-Face未来 roadmap:即将推出的5大新功能预览
  • 成都纹绣培训怎么选靠谱不踩坑?新风格合规教学更有保障 - 资讯纵览
  • Pi.Alert与家庭网络安全:如何利用设备监控防范未知入侵