HarmonyOS 应用包体积优化:从 HAP 结构到资源与 so 裁剪

举报
yd_260750576 发表于 2026/11/06 09:00:15 2026/11/06
【摘要】 一、先搞清楚体积花在哪 HarmonyOS 应用上架时提交的是 App Pack(.app),安装到设备上的单位是 HAP。一个典型的工程里,体积主要来自四块: 组成 位置 常见占比 字节码与 JS bundle ets/、modules.

一、先搞清楚体积花在哪

HarmonyOS 应用上架时提交的是 App Pack(.app),安装到设备上的单位是 HAP。一个典型的工程里,体积主要来自四块:

组成位置常见占比
字节码与 JS bundleets/、modules.abc20%~40%
原生库libs/<abi>/*.so20%~50%(有 C++ 依赖时更高)
资源resources/、resources.index15%~35%
三方 HAR/HSP依赖打包产物视依赖而定

优化前必须先量一遍。把构建产物里的 HAP 后缀改成 .zip 解出来,逐目录看大小:

unzip -l entry-default-signed.hap | sort -k1 -n -r | head -30

不看这个列表就开始删东西,通常会删错方向——很多人第一反应是压图片,结果 libs 里躺着一个 40MB 的 libopencv.so。

二、so 裁剪:只留 arm64-v8a

这是投入产出比最高的一步。HarmonyOS 真机目前以 arm64-v8a 为主,但不少工程为了兼容模拟器,把 x86_64 也打进去了,体积直接翻倍。

在模块的 build-profile.json5 里显式指定 ABI:

{
  "buildOption": {
    "externalNativeOptions": {
      "abiFilters": ["arm64-v8a"]
    }
  }
}

代价是模拟器跑不起来,因为开发机上的模拟器一般是 x86_64。折中方案是维护两套构建配置:日常调试用带 x86_64 的 debug,出包用只留 arm64-v8a 的 release。这点配置成本远比每次上传几十 MB 划算。

如果用的三方 SDK 提供了多个 ABI 的 so,同样要在依赖层做排除,而不是等打包完再删——后者会在签名校验时报错。

三、资源:不是「压一遍」就完事

资源优化最容易做成形式主义。真正有效的是三条:

1. 图片格式与尺寸对齐实际使用场景。

一张 3000×2000 的 banner 放在 360vp 宽的卡片里,无论压得多狠都是浪费。正确做法是按最大目标显示尺寸(含 2x/3x 倍图上限)导出,格式优先 WebP。HarmonyOS 的 Image 组件原生支持 WebP,不需要额外解码库。

2. 干掉重复与未引用资源。

多轮迭代后,resources/base/media 里通常会沉淀一批没人引用的图。DevEco Studio 的 Code Linter 能扫出未引用资源,构建时也会提示冗余项;resources/rawfile 下的离线包、示例数据最容易被忘记。

3. 按需分包,别把「可能用到」都塞进主包。

resources 里的大文件(教程视频、离线词库、初始模型)应该拆到独立 HSP,首次进入对应功能时再下载或按需加载。主包里只留启动路径真正需要的资源。

四、字节码与混淆:ArkGuard 的正确用法

release 构建默认会做一定程度的压缩,但混淆需要显式开启。在 build-profile.json5 中配置:

{
  "buildOption": {
    "arkOptions": {
      "obfuscation": {
        "ruleOptions": {
          "enable": true,
          "files": ["./obfuscation-rules.txt"],
          "consumerFiles": ["./consumer-rules.txt"]
        }
      }
    }
  }
}

混淆能显著减小字节码体积,也会把类名、属性名改成短名。只要代码里有反射、序列化、动态属性访问,就必须配白名单,否则运行时报「找不到属性」。常见的需要保留的:

  • 与后端 JSON 字段一一对应的数据类字段名;
  • JSON.parse 后按字符串下标访问的属性;
  • 通过 router.pushUrl 字符串匹配的页面路径;
  • 三方 SDK 要求保留的类与方法。

一个实用习惯:把「不能改名的字段」集中放在 @ObservedV2 之外的数据传输类里,并在 obfuscation-rules.txt 中按类名整体保留。散落在各处的 -keep-property-name 会让规则文件迅速失控。

五、拆包:HAP / HSP / HAR 怎么选

三者的定位经常被混淆:

  • HAP:可独立安装的运行单元,一个应用至少一个 entry HAP;
  • HSP:动态共享包,多个 HAP 可共享同一份代码与资源,运行时按需加载;
  • HAR:静态共享包,编译期被引用方打进自己的产物,本质是「源码/资源复用」。

想减主包体积,靠的是 HSP,不是 HAR。把「非首屏功能」抽成 HSP 后,主包只保留壳与路由,用户首次进入该功能时才加载对应 HSP。

但 HSP 有两个硬约束必须提前想清楚:

  1. 版本一致性:HSP 与宿主 HAP 的版本号要匹配,热更新场景下版本错配会直接加载失败;
  2. 依赖不能循环:HSP 之间互相引用会导致构建期报错,拆包时按「功能域」切,不要按「工具类」切。

六、优化的验收标准

体积优化必须有数字对比,否则很容易做出「感觉小了」的错觉。建议固定三个观测点:

  1. 安装包大小:release 构建产物的 .app 体积;
  2. 首屏加载耗时:冷启动到首帧的时间,拆包过度会把这个指标做坏;
  3. 运行时内存:HSP 按需加载后,峰值内存是否下降。

经验上,一个中等规模的鸿蒙应用做完上面四步(so 裁剪、资源治理、混淆、HSP 拆包),体积下降 30%~50% 是常见区间;但如果首屏耗时反而变长,说明拆得过头了——把启动路径上的模块拆成 HSP,等于把「一次加载」变成「两次加载 + 一次调度」。

七、小结

包体积优化不是「压缩图片」这一件事,而是按体积构成逐项处理:so 按 ABI 裁、资源按实际尺寸和引用关系清、字节码靠混淆、功能靠 HSP 拆。每一步都要有前后数字,并且盯着首屏耗时这个反向指标——只减体积不管启动速度,是另一种形式的体验倒退。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。