ArkGuard混淆常见问题排查与解决方案
功能异常排查流程
当应用在启用混淆后出现运行异常,建议按以下步骤进行定位:
- 首先在
obfuscation-rules.txt中添加-disable-obfuscation选项关闭所有混淆,验证问题是否由混淆引起。 - 若确认为混淆导致的问题,请查阅相关配置项说明:
-enable-toplevel-obfuscation:控制顶层标识符(如类、函数)的重命名行为。-enable-property-obfuscation:影响对象属性名称的混淆。涉及网络请求、JSON解析、动态字段访问或Native调用等场景,需通过-keep-property-name保留关键属性。-enable-export-obfuscation:用于模块间导出符号的混淆。若外部接口不可变,应使用-keep-global-name避免其被重命名。-enable-filename-obfuscation:对文件路径进行混淆。若存在动态加载或运行时路径引用,必须用-keep-file-name保护特定路径。
- 参考典型报错案例,快速匹配并处理相似问题。
- 若无对应案例,可依据配置逻辑逆向分析:若某功能无需混淆,则直接移除对应配置。
- 崩溃日志分析方法:
- 打开 DevEco Studio 的崩溃弹窗或查看运行日志,获取完整的调用栈。
- 混淆后的堆栈行号和方法名均为编译产物,需结合编译输出文件定位原始代码。
- 根据崩溃位置判断哪些名称不能被混淆,并加入白名单。
- 非崩溃型功能异常(如界面空白)分析:
- 启用 HiLog,搜索与异常功能相关的日志记录。
- 结合日志定位具体执行路径。
- 在疑似问题代码中增加字段打印日志,观察数据流转状态。
- 通过日志对比确认是否因属性名混淆导致数据无法正确读取。
- 将受影响的关键属性加入
-keep-property-name白名单。
意外混淆行为排查
若发现混淆效果超出预期,可能源于依赖库中启用了某些混淆规则。例如主模块未开启 -compact,但中间代码被压缩成单行,此时应检查:
- 查看
oh-package.json5中的dependencies字段,识别所依赖的本地模块或三方库。 - 在项目目录下搜索所有
obfuscation.txt文件,重点检查:- 本地库中的
consumer-rules.txt - 工程根目录下的
oh_modules内部各模块的混淆配置文件
- 本地库中的
注意:三方库的 consumer-rules.txt 不应包含以下开关,否则会在主模块启用混淆时产生副作用,甚至引发崩溃:
-enable-property-obfuscation-enable-string-property-obfuscation-enable-toplevel-obfuscation-remove-log-compact
建议联系库维护者移除上述配置并重新发布。
属性混淆典型问题与修复
数据库字段混淆导致 SQL 错误
现象:报错:table Account has no column named a23 in 'INSERT INTO Account(a23)'
原因:SQL 中使用的字段名被混淆,而数据库表结构仍保持原始名称。
解决:使用 -keep-property-name 保留数据库字段名:
-keep-property-name
accountName
age
Record<string, Object> 类型属性被错误混淆
现象:原属性 linkSource 被混淆为 i,导致系统无法识别参数。
示例:
// 混淆前
parameters: {
linkSource: 'com.other.app'
}
// 混淆后(错误)
parameters: {
i: 'com.other.app'
}
原因:由于类型为泛型 Record<string, Object>,混淆工具无法推断内部属性语义,因此默认进行混淆。
解决:显式声明白名单:
-keep-property-name
linkSource
跨文件属性混淆不一致
现象:文件1中保留了属性,文件2中该属性被混淆,导致调用失败。
示例:
// file1.ts
export interface MyInfo {
age: number;
address: { city1: string; }
}
// file2.ts
import { MyInfo } from './file1';
const person: MyInfo = { age: 20, address: { city1: "shanghai" } };
混淆后:
address: { i: "shanghai" }
原因:仅对文件1使用 -keep 并不能保证其内部嵌套类型的属性不被混淆。
解决方案:
- 方案一:通过独立接口定义提升可识别性:
// file1.ts
export interface AddressType {
city1: string;
}
export interface MyInfo {
age: number;
address: AddressType;
}
-keep-property-name
city1
未开启字符串属性混淆却发生混淆
现象:代码中 person["age"] 被混淆为 person["b"]。
原因:上游依赖模块开启了 -enable-string-property-obfuscation,其规则被合并到主模块。
解决:
- 方案一:检查并禁用依赖模块中的该配置项。
- 方案二:若无法定位源头,可在主模块中直接将关键属性名加入白名单:
-keep-property-name
age
导入导出名称不一致问题
动态导入类名混淆冲突
现象:定义处类名为 Test1,动态导入后仍为 Test1,但实际类已被重命名为 w1,导致找不到符号。
原因:类作为顶层标识符被混淆,但动态导入使用的是原始名称,而导出的名称已改变。
解决:使用 -keep-global-name 保护该类名:
-keep-global-name
Test1
namespace 方法导出名称不一致
现象:命名空间内方法 person1 在定义处被混淆为 b2,但调用方仍使用 ns1.person1,造成调用失败。
原因:未开启 -enable-property-obfuscation,导致属性访问名未参与混淆,而类名已混淆。
解决:
- 方案一:开启
-enable-property-obfuscation,统一处理属性名。 - 方案二:使用
-keep-global-name显式保护该方法名:
-keep-global-name
person1
模块间依赖混淆问题
HSP 模块接口被错误混淆
现象:主模块调用 HSP 接口时,方法名被混淆为 a1,调用失败。
原因:当同时启用 -enable-export-obfuscation 与 -enable-toplevel-obfuscation 时,不同模块独立编译,导致导出符号名称不一致。
解决:确保主模块与 HSP 模块共享一致的白名单配置:
- 在 HSP 模块中创建白名单文件(如
hsp-white-list.txt),列出需要保留的接口名。 - 在主模块的混淆配置中引入该文件,通过
files字段指定路径。
此方式可避免重复维护,保障一致性。配置示意如下:
HAP/HSP 共享本地 HAR 导致单例异常或调用失败
现象:
- 文件名混淆后,同一 HAR 在 HAP 与 HSP 中生成不同混淆名,破坏单例机制。
- 不同文件名被混淆为相同名称,导致资源冲突。
- 接口调用失败,因名称不一致。
原因:HAP 与 HSP 独立构建,各自对本地 HAR 进行混淆,导致名称不一致。
解决:
- 方案一:将共享的本地 HAR 改为字节码 HAR,避免二次混淆。
- 方案二:以 release 模式构建打包,确保文件名与接口名不被混淆。