HarmonyOS 7 ArkGuard 配了 -keep-uncompact 却没生效?先查 -compact 和相对路径

HarmonyOS 7 ArkGuard 配了 -keep-uncompact 却没生效?先查 -compact 和相对路径
一个模块升级后,Debug 包能跑,Release 包却在某个反射或动态调用入口出错。看到 API 26 新增的 -keep-uncompact,很容易把它当成“不要动这个文件”的总开关,往规则文件里写一行就收工。我更愿意先停一下:这个选项只排除代码压缩,不等于保留所有类名、属性名或文件名。
华为 2026-09-10 更新的 ArkGuard 保留选项文档写了三个边界:-keep-uncompact 从 API 26.0.0 开始;只有启用了 -compact 才生效;路径是相对于混淆规则文件所在目录的相对路径。远程三方包要按项目级 oh_modules 中的真实路径配置。本文只谈这个新选项如何生效,不把它说成所有混淆问题的万能修复。
验证范围:下方 Node.js 小脚本在本机跑通了规则前置检查。它只验证配置文本与路径计算,没有执行 HarmonyOS 7 的 ArkGuard 构建。最终是否保留目标结构,要以装有 API 26 SDK 的工程 Release 构建产物和功能回归为准。
先把三个选项分清
| 规则 | 解决的问题 | 不负责什么 |
|---|---|---|
-compact | 开启代码压缩 | 不替你处理动态访问的名字兼容 |
-keep-uncompact | 将指定相对路径排除在代码压缩之外 | 不等于 -keep,也不自动保留所有属性名 |
-keep / -keep-property-name | 按规则保留名称 | 不应为了一个小范围问题就无差别保留整个工程 |
先确定故障原因是压缩改变了目标代码的组织,还是混淆改了外部协议依赖的名称。例如 JSON 序列化字段名变化,应该检查对应属性保留规则;单独给这个目录加 -keep-uncompact 并不能解释字段名为什么变化。反过来,若名字已经正确保留,但压缩后的产物行为异常,才进一步对比排除压缩前后。

案例一:只写排除规则,忘了开启压缩
假设规则文件位于 entry/obfuscation-rules.txt,目标文件位于 entry/src/main/ets/bridge/LegacyAdapter.ets。这段配置不会让排除规则生效:
# entry/obfuscation-rules.txt
-keep-uncompact
./src/main/ets/bridge/LegacyAdapter.ets
因为本来就没有 -compact。如果 Release 包没有压缩,排除压缩当然观察不到差异。对照组应写成:
# entry/obfuscation-rules.txt
-compact
-keep-uncompact
./src/main/ets/bridge/LegacyAdapter.ets
这并不是建议所有项目马上打开 -compact。若工程原本没启用压缩,先确认是否真的要引入它,再做完整 Release 回归;不能为了验证一条新规则,顺手改变整个应用的构建行为。
我会准备两个 Release 产物做比较:保持其他构建选项相同,只改变排除规则;记录包体、目标模块产物和相同测试用例。若两组都没有启用压缩,比较结果不能证明 -keep-uncompact 有用。
案例二:entry 写了两次,保护到不存在的位置
规则文件在 entry/ 下时,./ 从这个文件所在目录出发,不是从仓库根目录出发。把工程树想成:
project/
entry/
obfuscation-rules.txt
src/main/ets/bridge/LegacyAdapter.ets
应写 ./src/main/ets/bridge/LegacyAdapter.ets。如果写成 ./entry/src/main/ets/bridge/LegacyAdapter.ets,实际相对到 project/entry/entry/...,根本没有命中那个文件。路径错误不会因为规则名字看起来正确而自动修好。
三方包还有一层容易踩的坑:官方要求对远程三方包指向项目级 oh_modules 中的真实路径,不能只凭编辑器里看见的模块级软链接位置猜路径。包升级后真实目录若变化,规则也要复查。
本地可运行的规则预检
这段脚本不冒充 ArkGuard。它只把上述两个前置条件做成自动检查:是否有 -compact,以及相对路径是否解析到已知目标。为方便复现,脚本用内存中的工程文件集合,不改你的项目。
import assert from 'node:assert/strict';
import path from 'node:path';
const configDir = 'C:/demo/entry';
const files = new Set([
'C:/demo/entry/src/main/ets/bridge/LegacyAdapter.ets',
'C:/demo/oh_modules/vendor/src/index.ets'
]);
function inspect(rules, target) {
const lines = rules.split(/\r?\n/).map(s => s.trim())
.filter(s => s && !s.startsWith('#'));
const compact = lines.includes('-compact');
const at = lines.indexOf('-keep-uncompact');
const relative = at < 0 ? '' : lines[at + 1];
const resolved = relative && relative.startsWith('.')
? path.posix.normalize(path.posix.join(configDir, relative)) : '';
return {
compact,
resolved,
targetExists: files.has(target),
pathMatches: resolved === target,
ready: compact && files.has(target) && resolved === target
};
}
const target = 'C:/demo/entry/src/main/ets/bridge/LegacyAdapter.ets';
const noCompact = inspect('-keep-uncompact\n./src/main/ets/bridge/LegacyAdapter.ets', target);
assert.equal(noCompact.ready, false);
assert.equal(noCompact.pathMatches, true);
const wrongPath = inspect('-compact\n-keep-uncompact\n./entry/src/main/ets/bridge/LegacyAdapter.ets', target);
assert.equal(wrongPath.ready, false);
assert.equal(wrongPath.pathMatches, false);
const correct = inspect('-compact\n-keep-uncompact\n./src/main/ets/bridge/LegacyAdapter.ets', target);
assert.equal(correct.ready, true);
const packageTarget = 'C:/demo/oh_modules/vendor/src/index.ets';
const packageRule = inspect('-compact\n-keep-uncompact\n../oh_modules/vendor/src/index.ets', packageTarget);
assert.equal(packageRule.ready, true);
console.log('4 checks passed: switch, wrong path, correct path, project-level package path');
保存为 arkguard-rule-check.mjs 后运行 node arkguard-rule-check.mjs。本机输出应为 4 checks passed...。这是配置预检,不是产物检验;目标在真实工程里可能因目录结构、构建配置或 SDK 差异而不同,不能拿这行输出代替 Release 回归。
真正接入工程怎么验
- 在目标 API 26 SDK 下确认项目是否启用了源码混淆、
-compact是否开启,规则文件实际被哪个模块的构建配置引用。没被加载的规则文件改得再对也没用。 - 从规则文件所在目录计算目标文件的相对路径;对项目级三方包使用真实路径。先缩到一个文件或目录,不要一上来排除全部模块。
- 固定相同源码、构建模式和依赖版本,分别构建有排除规则和无排除规则的 Release 包。比较目标产物,同时跑反射、序列化、动态调用等真正出问题的入口。
- 若产物仍异常,分开排查名称混淆与代码压缩:名称问题查
-keep、-keep-property-name等对应规则;不要继续堆-keep-uncompact。 - 记录规则引起的包体与性能变化。保护范围越大,潜在优化收益损失越大;只保留能用回归用例证明必要的最小范围。
这些检查比“配置了规则,Debug 能跑”严格得多。Debug 正常只能说明另一种构建条件下正常,不能证明 Release 的压缩排除已经命中。
什么时候不该用它
如果根因是 JSON 字段名被改、NAPI 导出名不匹配或路径字符串依赖文件名,那么 -keep-uncompact 就不是第一选择;先用对应的名称保留规则和官方混淆助手定位。如果根本没有开启 -compact,这个选项没有效果。如果只在某一机型异常,先拿相同构建产物复现,别把设备差异误判成压缩问题。
我的结论很简单:API 26 给了我们更细的“排除代码压缩”工具,但它的价值在于小范围、有对照、有验收。先证实开关、路径、规则文件归属,再看真实产物和故障入口。不要拿它当“关掉一切混淆”的总开关。
参考资料(核对日期 2026-09-18):
更多推荐



所有评论(0)