你好欢迎来到我的博客我是【菜鸟学鸿蒙】我是一名在路上的移动端开发者正从传统“小码农”转向鸿蒙原生开发的进阶之旅。为了把学习过的知识沉淀下来也为了和更多同路人互相启发我决定把探索 HarmonyOS 的过程都记录在这里。️主要方向ArkTS 语言基础、HarmonyOS 原生应用Stage 模型、UIAbility/ServiceAbility、分布式能力与软总线、元服务/卡片、应用签名与上架、性能与内存优化、项目实战以及 Android → 鸿蒙的迁移踩坑与复盘。内容节奏从基础到实战——小示例拆解框架认知、专项优化手记、实战项目拆包、面试题思考与复盘让每篇都有可落地的代码与方法论。 我相信写作是把知识内化的过程分享是让生态更繁荣的方式。如果你也想拥抱鸿蒙、热爱成长欢迎关注我一起交流进步前言多模块工程走到一定规模HAR 的问题就开始浮出水面——不是 HAR 本身设计有缺陷而是它的工作方式决定了一旦被多个模块引用代码就会被分别打进每一个引用方里。这篇文章讲的是把 HAR 转换成 HSP 的过程为什么转、能不能转、怎么一步步改。一、多模块引用 HAR 时到底发生了什么HARHarmony Archive是静态共享包。根据官方文档的描述HAR 中的代码资源在编译时会被打包进引用方的模块包HAP/HSP中引用方多时会造成多个 HAP/HSP 中存在相同拷贝的代码和资源包体增大。假设工程里有三个 HAP比如 entry、feature_a、feature_b都依赖了同一个 HAR比如common_utils。编译时common_utils的代码会被拷贝三份分别打进三个 HAP 里。磁盘占用是一个方面运行时内存里同样存在多份一样的逻辑并不会因为它们来自同一个 HAR就共享内存。HSPHarmony Shared Package的设计思路正好相反HSP 中的代码资源不会被打包进引用方的模块包HAP/HSP中而是独立存在于应用安装目录下减少代码/资源冗余节省磁盘空间。多个 HAP/HSP 引用同一个 HSP 时在运行阶段共享同一份代码和资源减少内存占用。这是两种本质上不同的共享模式不是说 HSP 一定比 HAR 好而是应用场景不同。二、HAR 与 HSP 的本质差异在决定是否要转换之前先把两者的边界搞清楚。对比维度HAR静态共享包HSP动态共享包代码打包方式编译时拷贝进引用方独立存在运行时共享支持多 HAP 引用支持但每个引用方各存一份支持所有引用方共享同一份支持 pages 页面路由不支持支持API 12 起支持 UIAbility不支持不支持支持应用间共享支持发布 OHPM 三方库不支持仅限应用内$r 引用 AppScope 资源不支持API 12 起支持module.json5 type 字段harshared这里有一个前提条件值得单独说HSP 仅支持应用内共享不支持应用间共享。如果你的 HAR 是发布到 OHPM 给其他应用用的三方库就不适合转成 HSP。HSP 只适用于同一应用的多模块共享场景。三、官方要求的转换前提根据官方资料HAR 转 HSP 需要满足以下条件才能正常工作必须是应用内共享场景不能有跨应用引用需求模块必须使用 Stage 模型HAR/HSP 都只存在于 Stage 模型工程引用方必须在同一应用工程内HSP 不支持被其他应用的 HAP/HSP 引用pages 路由如有需要适配HSP 从 API 12 起才支持 pages且路由跳转路径格式与 HAP 不同Worker 的 URL 格式不同HAR 和 HAP/HSP 在创建 Worker 时使用的路径格式有区别需要特别处理。四、修改 module.json5这是最核心的一步。HAR 的module.json5中type字段是har转成 HSP 需要改为shared。HAR 原始配置转换前// harModule/src/main/module.json5{module:{name:commonUtils,type:har,deviceTypes:[phone,tablet]}}HSP 目标配置转换后// commonUtils/src/main/module.json5{module:{name:commonUtils,type:shared,description:$string:shared_desc,deviceTypes:[phone,tablet]}}name字段保持不变引用方的oh-package.json5中的依赖路径也不需要改。关键就是type从har改成shared。五、增加 pages 配置如果原有的 HAR 没有页面纯工具/组件库这一步可以跳过。如果需要在 HSP 中使用 pagesAPI 12 起支持需要两处配置第一步在 module.json5 中增加 pages 字段{module:{name:commonUtils,type:shared,pages:$profile:main_pages,deviceTypes:[phone,tablet]}}第二步在resources/base/profile/main_pages.json中声明页面{src:[pages/Index]}HSP 里的页面不能通过windowStage.loadContent直接加载必须通过路由跳转。跳转时路径格式也与普通 HAP 内的页面不同需要带上 bundle 名和模块名import{router}fromkit.ArkUI;// 跳转 HSP 中的页面格式bundle:bundleName/moduleName/ets/pages/PageNamerouter.pushUrl({url:bundle:com.example.myapp/commonUtils/ets/pages/Index});这个路径格式根据官方文档bundle:后面依次是应用的bundleName、模块名、以及页面的相对路径从ets开始。六、调整依赖引用方的oh-package.json5通常不需要修改只要本地路径引用没有变化// entry/oh-package.json5{dependencies:{commonUtils:file:../commonUtils}}需要关注的是工程级build-profile.json5。确保 HSP 模块已经被正确列入工程的modules列表// 工程根目录 build-profile.json5节选{modules:[{name:entry,srcPath:./entry,targets:[{name:default,applyToProducts:[default]}]},{name:commonUtils,srcPath:./commonUtils,targets:[{name:default,applyToProducts:[default]}]}]}HAR 转 HSP 后模块本身还在srcPath不需要变这里通常不用动。七、检查组件和 Worker 的差异自定义组件ArkUI 组件HAR 和 HSP 都支持导出自定义组件通过Index.ets对外暴露引用方的import路径也保持一致。这部分转换后一般不需要改动。Worker这是容易出问题的地方。根据官方文档HAR 和 HAP/HSP 创建 Worker 时URL 格式是不同的HAP/HSP 中创建 Worker使用模块名作为路径前缀例如// 在 HSP模块名 commonUtils中创建 Workerimport{worker}fromkit.ArkTS;constmyWorkernewworker.ThreadWorker(commonUtils/ets/workers/MyWorker.ts);HAR 中创建 Worker使用相对路径例如// 在 HAR 中创建 Workerimport{worker}fromkit.ArkTS;constmyWorkernewworker.ThreadWorker(../utils/src/main/ets/workers/MyWorker.ts);如果原来的 HAR 里有 Worker转成 HSP 之后Worker 的 URL 必须从相对路径改成以模块名开头的路径格式。另外Worker 文件还需要在模块级build-profile.json5的buildOption/sourceOption/workers字段中声明{buildOption:{sourceOption:{workers:[./src/main/ets/workers/MyWorker.ts]}}}这个配置在 HAR 里也需要通常已经有了转成 HSP 后保持不变即可。八、转换后的工程结构经过上述调整工程结构的变化主要体现在module.json5的内容上目录结构本身并不需要大改myApp/├── entry/│ ├── src/main/│ └── oh-package.json5// 依赖路径不变├── commonUtils/// 原 HAR现在是 HSP│ ├── src/main/│ │ ├── ets/│ │ │ ├── components/// 自定义组件不变│ │ │ └── workers/// Worker 文件URL 格式需调整│ │ ├── resources/│ │ │ └── base/│ │ │ └── profile/│ │ │ └── main_pages.json// 如有 pages新增│ │ └── module.json5// type 改为 shared按需加 pages│ ├── Index.ets// 对外导出接口不变│ └── oh-package.json5// 不变└── build-profile.json5// 确认 modules 列表包含 commonUtils开发经验总结几个容易理解偏的地方值得单独关注1. HSP 不是 HAR 的升级版是两种不同场景。HAR 支持应用间共享三方库HSP 只支持应用内共享。如果当前 HAR 是打算发布给其他应用用的不应该转成 HSP。2. pages 支持从 API 12 起生效。如果目标设备的 API Level 低于 12HSP 里的 pages 配置是无效的。在转换前需要确认工程的compatibleSdkVersion。3. Worker URL 格式是最容易漏掉的。HAR 用相对路径HSP/HAP 用模块名前缀两者不可混用。如果转换后 Worker 报找不到文件优先检查这里。4. (r 引用 AppScope 资源的限制。原 HAR 如果有\)r(app.string.xxx)这类引用 AppScope 资源的代码转成 HSP 后在 API 12 以下版本同样会失败API 12 起才支持。5. HSP 不能被其他应用依赖。这是在架构设计时需要确认的边界一旦有跨应用共享需求只能保持 HAR。转换本身并不复杂改动集中在module.json5的type字段、pages 配置以及 Worker 的 URL。真正需要在改之前想清楚的是这个共享模块的定位它只服务于当前应用的多个模块还是将来有可能对外发布这个问题定了选 HAR 还是 HSP 就很自然了。如果你的工程里有多个 HAR 被多个 HAP 同时引用可以对比一下转换前后的编译产物大小观察实际包体变化。包体减少的幅度取决于被引用的 HAR 代码量以及引用方的数量引用方越多、HAR 越大收益越明显。 写在最后如果你觉得这篇文章对你有帮助或者有任何想法、建议欢迎在评论区留言交流你的每一个点赞 、收藏 ⭐、关注 ❤️都是我持续更新的最大动力我是一个在代码世界里不断摸索的小码农愿我们都能在成长的路上越走越远越学越强感谢你的阅读我们下篇文章再见✍️ 作者菜鸟不学编程 本文原创转载请注明出处。