两个 HSP 都带同名 so,包体为什么没变小:HarmonyOS 7 deduplicateSo 怎么验证真正去重

DevEco Studio 26.0 Release 在工程级 build-profile.json5 的 packOptions 中新增 deduplicateSo。它针对构建 APP 时 HAP/HSP 中重复的 so,只保留一份,并且官方说明这份文件会随机打包在某个 HAP 或 HSP 中。因此某个模块包没有变小、或者 so 从 A 模块移动到 B 模块,都不能单独证明去重失败;真正需要比较的是同一 ABI 下内容相同的文件、APP 总体积和运行加载结果。

HAP HSP 中 SO 去重与运行验证

先做受控对照,不先改代码

准备 entry、featureA、featureB,后两个 HSP 都依赖同一 libimage.so;再加入一个同名但哈希不同的测试库。分别关闭和开启 deduplicateSo 构建 APP,解包记录 abi、path、basename、sha256、uncompressedSize、container、appSize 和 runtimeLoadResult。清理构建缓存后重复一次,避免增量产物污染。

同一设备、同一构建和同一操作路径只改变一个变量;每轮保存输入、工具参数与最终可观察结果,避免把偶然波动当成修复。

方案对比

方式优点风险
只比较 HSP 文件大小操作快保留位置变化会误判
只按 so 文件名查重容易自动化同名不同内容有风险
ABI+哈希清单、APP 总包、运行加载联合验证证据完整需要解包与回归

我的选择:采用第三种,包体收益和运行正确性必须同时成立。

为什么对照会分叉

同名不等于重复,内容和 ABI 必须一致

arm64-v8a 与 x86_64 不是同一运行产物;同名但哈希不同也不能合并。去重键至少包含 ABI、库名和内容摘要。

这里必须同时保存输入条件、设备或窗口形态、触发动作和最终可观察状态。工具报告用于缩小范围,任务是否可完成仍由同一条用户路径的读回结果决定。

去重发生在 APP 构建和打包层

单独编译 HSP 或查看模块中间目录,可能仍看到重复文件。应检查最终 APP 内的所有 HAP/HSP,而不是一个模块。

这里必须同时保存输入条件、设备或窗口形态、触发动作和最终可观察状态。工具报告用于缩小范围,任务是否可完成仍由同一条用户路径的读回结果决定。

保留位置不稳定,运行验证不可省

文件只留一份且可能落在不同容器。必须验证依赖模块仍能加载符号,不能为了包体数字制造运行时缺库。

这里必须同时保存输入条件、设备或窗口形态、触发动作和最终可观察状态。工具报告用于缩小范围,任务是否可完成仍由同一条用户路径的读回结果决定。

案例一:两个 HSP 的 libimage.so 哈希完全一致

开启后 APP 中同 ABI 只保留一份,总体积下降,两个功能模块运行正常。记录去重前后清单,不依赖文件最终落在哪个容器。

修复后用原始条件再次执行完整任务,并保留修改前后同一节点的可见性、可操作性和状态对照。

案例二:库名相同但编译选项不同

哈希和导出符号不同,不应强行合并。统一依赖版本与编译参数后再去重,或明确保留不同库名,避免偶发加载错误。

第二个案例选择不同形态或不同状态,用来证明方案不是对单一截图的局部修补。

工程侧模型

type SoEntry={abi:string;name:string;sha256:string;container:string;size:number}
function duplicateKey(x:SoEntry){return x.abi+'|'+x.name+'|'+x.sha256}

模型只表达稳定的决策边界,界面组件、窗口事件和工具结果通过适配器接入,避免把设备差异散落在每个页面。

可独立执行的状态断言

function groups(a){const m=new Map();for(const x of a){const k=[x.abi,x.name,x.hash].join('|');m.set(k,(m.get(k)||0)+1)}return [...m.entries()].filter(([,n])=>n>1)}
const d=groups([{abi:'arm64',name:'liba.so',hash:'x'},{abi:'arm64',name:'liba.so',hash:'x'},{abi:'x86',name:'liba.so',hash:'x'}]);if(d.length!==1||d[0][1]!==2)throw new Error('SO 重复识别错误');

这些断言验证纯状态、几何或边界计算,不代表 API 26 工程已经编译,也不代表真机、模拟器特定镜像或应用市场审核已经通过。

验收清单

  • 只在最终 APP 上验证。
  • 去重键包含 ABI 与哈希。
  • 清理缓存后做对照构建。
  • 记录文件实际保留容器。
  • 关键 Native 功能必须回归。

封装与复用

封装 SoPackageManifest,扫描最终 APP 内每个容器的 ABI、名称、哈希、大小和导出符号;构建门禁输出重复组、节省字节和运行回归结果。

复用层输出决策和证据,不强行统一所有页面视觉。每个页面仍可保留自身信息层级,但必须满足相同的任务可达性与状态连续标准。

验证边界

本文依据当前华为官方文档整理能力与约束,纯状态模型已在本机执行。当前本机 HarmonyOS SDK 为 API 24,且没有连接 HDC 设备,因此 API 26 编译、目标模拟器镜像行为、折叠真机连续性和平台审核结果仍属于待验证项。完成目标环境验证后,应把版本、设备、构建身份和读回结果补入证据包。

官方资料

最终结论

用 ABI、文件哈希、APP 总包与运行加载四层证据判断 SO 去重,而不是盯着某个 HSP 的压缩大小。 适配不是让截图“看起来差不多”,而是让关键任务在形态变化后依然可见、可操作、可恢复。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐