-enable-toplevel-obfuscation为顶层作用域名称混淆开关。
-enable-property-obfuscation为属性混淆开关。配置白名单的主要场景包括网络数据访问、json字段访问、动态属性访问、调用so库接口等。需要使用-keep-property-name来保留指定的属性名称。
-enable-export-obfuscation为导入/导出名称混淆。一般与-enable-toplevel-obfuscation和-enable-property-obfuscation选项配合使用。配置白名单的主要场景为模块对外接口不能混淆。需要使用-keep-global-name来保留指定的导出/导入名称。
-enable-filename-obfuscation为文件名混淆。配置白名单的主要场景为动态import或运行时直接加载的文件路径。需要使用-keep-file-name来保留这些文件路径及名称。
打开应用运行日志:选择HiLog,检索与功能异常直接相关的日志,定位问题发生的上下文。
定位异常代码段:分析日志,找到引发功能异常的代码块。
增强日志输出:在疑似异常的功能代码中,增加日志打印以检查数据是否正常。
分析并确定关键字段:通过分析新增的日志输出,判断数据异常是否由混淆导致。
配置白名单以保护关键字段:将混淆后对应用功能有直接影响的关键字段添加到白名单中。
若出现预期外的混淆效果,检查是否由于依赖的本地模块或三方库开启了某些混淆选项。
假设当前模块未配置-compact,但混淆的中间产物中代码都被压缩成一行,可按照以下步骤排查混淆选项:
从API version 18开始,主模块默认不合并三方库的obfuscation.txt文件中的混淆选项,保留选项仍然有效。
三方库中的consumer-rules.txt不建议配置以下开关选项。这些选项在主模块开启混淆时会生效,可能导致意外的混淆效果,甚至应用运行时崩溃。如果发现三方库的obfuscation.txt文件中包含以下开关选项,建议联系发布该三方库的团队删除这些选项并重新打包发布。
-enable-property-obfuscation
-enable-string-property-obfuscation
-enable-toplevel-obfuscation
-remove-log
-compact
问题现象
混淆规则配置如下所示:
-enable-property-obfuscation
示例代码如下:
// 示例JSON文件结构(ImportJson.json):
/*
{
"jsonObj": {
"jsonProperty": "value"
}
}
*/
// 混淆前
import jsonData from './ImportJson.json';
// ...
let jsonProp = jsonData.jsonObj.jsonProperty; // 混淆后 import jsonData from "./ImportJson.json"; let jsonProp = jsonData.i.j;
问题原因
开启属性混淆后,源码会被混淆,但JSON文件不会。源码中通过jsonData.i访问属性时,由于属性名称已经被混淆,JSON数据中并不存在对应的字段,导致获取的值为undefined。
解决方案
将JSON文件中的字段配置到属性白名单中。
-keep-property-name jsonObj jsonProperty
场景一:导出namespace中的方法时,该方法定义处被混淆,调用时未被混淆
问题现象
混淆规则配置如下所示:
-enable-toplevel-obfuscation -enable-export-obfuscation
示例代码如下:
// 混淆前
// ExportNs.ts
export namespace NS {
export function foo() { }
} // Index.ets
import { NS } from './ExportNs';
// ...
NS.foo(); // 混淆后
// ExportNs.ts
export namespace i {
export function j() {}
}
// Index.ets
import { i } from './ExportNs';
i.foo(); 问题原因
namespace中的foo属于export元素,当通过NS.foo调用时被视为属性。由于未开启-enable-property-obfuscation选项,导致foo在使用时未被混淆。
解决方案
方案一:开启-enable-property-obfuscation选项。
方案二:使用-keep-global-name选项将namespace中导出的方法配置到白名单中。
-keep-global-name foo
场景二:动态导入某个类,类定义处被混淆,调用时未被混淆
问题现象
混淆规则配置如下所示:
-enable-toplevel-obfuscation -enable-export-obfuscation
示例代码如下:
// 混淆前
// ExportUtils.ts
export function add(a: number, b: number): number {
return a + b;
} // Index.ets
async function loadAndUseAdd() {
let result: number = 0;
try {
const mathUtils = await import('./ExportUtils');
result = mathUtils.add(2, 3);
console.info(`result = ${result}`);
} catch (error) {
console.error('Failure reason:', error);
}
}
loadAndUseAdd(); // 混淆后
// ExportUtils.ts
export function c1(d1: number, e1: number): number {
return d1 + e1;
}
// Index.ets
async function i() {
let b1: number = 0;
try {
const a1 = await import("@normalized:N&&&entry/src/main/ets/pages/ExportUtils&");
b1 = a1.add(2, 3);
console.info(`result = ${b1}`);
}
catch (z) {
console.error('Failure reason:', z);
}
}
i(); 问题原因
函数add在定义时位于顶层作用域,但通过.add访问时被视为属性。由于未开启-enable-property-obfuscation选项,导致add被使用时未进行混淆。
解决方案
方案一:开启-enable-property-obfuscation选项。
方案二:使用-keep-global-name选项将add配置到白名单中。
-keep-global-name add
场景三:调用so库的方法后导致crash
问题现象
混淆规则配置如下所示:
-enable-property-obfuscation -enable-export-obfuscation
示例代码如下:
// src/main/cpp/types/libentry/Index.d.ts export const addNum: (a: number, b: number) => number;
// example.ets // 混淆前 import testNapi from 'libentry.so'; // ... let sun = testNapi.addNum(1, 2);
// example.ets // 混淆后 import testNapi from "@normalized:Y&&&libentry.so&"; testNapi.m();
问题原因
混淆工具仅支持js/ts/ets代码的混淆。so库中的方法定义在C++侧,因此这些方法在定义处不会被混淆,但在调用处会被混淆。
解决方案
将so库导出的方法配置到属性白名单中。
-keep-property-name addNum
问题现象
主模块和HSP模块的混淆规则配置如下所示:
-enable-toplevel-obfuscation -enable-export-obfuscation
示例代码如下:
// 混淆前
// hsp模块
export function addNum(a: number, b: number) {
return a + b;
} // entry模块
import { addNum } from 'sharedlibrary';
addNum(1, 2); // 混淆后
// hsp模块
export function b(c: number, d: number): number {
return c + d;
}
// entry模块
import { n } from '@normalized:N&sharedlibrary&&sharedlibrary/Index&';
n(1, 2); 问题原因
当同时开启-enable-toplevel-obfuscation和-enable-export-obfuscation选项时,主模块与被调用模块的混淆情况如下:
| 主模块 | 依赖模块 | 导入与导出的名称混淆情况 |
|---|---|---|
| HAP/HSP | HSP | HSP和主模块是独立编译的,混淆后名称会不一致,因此都需要配置白名单。 |
| HAP/HSP | 本地HAR | 本地HAR与主模块一起编译,混淆后名称一致。 |
| HAP/HSP | 三方库 | 三方库中导出的名称及其属性会被收集到白名单,因此导入和导出时都不会被混淆。 |
由于HAP和HSP模块是独立编译,因此混淆后导入和导出名称不一致,从而导致HAP引用HSP的方法时报错。
解决方案
将HSP模块导出的方法配置到-keep-global-name下,并且需要在HSP的consumer-rules.txt和obfuscation-rules.txt文件中都进行对应配置。
// consumer-rules.txt -keep-global-name addNum // obfuscation-rules.txt -keep-global-name addNum
问题现象
parameters的类型为Record<string, Object>。开启属性混淆后,parameters对象中的linkSource属性被混淆,导致功能异常。
示例代码如下:
// 混淆前
import { Want } from '@kit.AbilityKit';
// ...
let petalMapWant: Want = {
bundleName: 'com.example.myapplication',
uri: 'maps://',
parameters: {
linkSource: 'com.other.app'
}
} // 混淆后
import type Want from "@ohos:app.ability.Want";
let petalMapWant: Want = {
bundleName: 'com.example.myapplication',
uri: 'maps://',
parameters: {
i: 'com.other.app'
}
}; 问题原因
示例中parameters的类型为Record<string, Object>,这仅表示以字符串为键的对象的泛型定义,未详细描述其内部属性。因此,混淆工具无法识别对象内部哪些属性不应被混淆,导致linkSource被混淆后,引发功能异常。
解决方案
将混淆后会出现问题的属性名配置到属性白名单中。
-keep-property-name linkSource
问题现象
混淆规则配置如下所示:
-enable-property-obfuscation -keep ./FileInside.ts
在Index.ets中导入FileInside.ts的接口。该接口包含一个对象类型的属性。此对象属性在FileInside.ts中被保留,但在Index.ets中被混淆,导致调用时出现功能异常。
示例代码如下:
// 混淆前
// FileInside.ts
export interface MyInfo {
age: number;
address: {
city1: string;
}
} // Index.ets
import { MyInfo } from './FileInside';
// ...
const person: MyInfo = {
age: 20,
address: {
city1: 'shanghai'
}
} // 混淆后
// FileInside.ts
export interface MyInfo {
age: number;
address: {
city1: string;
}
}
// Index.ets
import { MyInfo } from './FileInside';
const person: MyInfo = {
age: 20,
address: {
i: "shanghai"
}
} 问题原因
使用-keep选项保留FileInside.ts文件时,该文件中的代码不会被混淆。导出属性(如address)所属类型内的属性不会自动加入白名单,因此在其他文件中使用时会被混淆。
解决方案
方案一:使用interface定义该属性的类型,并使用export进行导出,这样该属性将被自动加入到属性白名单中。
// FileOutside.ts
export interface AddressType {
city1: string
}
export interface MyInfo2 {
age: number;
address: AddressType;
} 方案二:使用-keep-property-name选项,将未直接导出的类型内的属性配置到属性白名单中。
-keep-property-name city1
问题现象
// 混淆前
const person = {
myAge: 18
}
person["myAge"] = 20; // 混淆后
const person = {
myAge: 18
}
person["m"] = 20; 问题原因
主模块所依赖的其他模块中的consumer-rules.txt文件配置了-enable-string-property-obfuscation选项,主模块会合并该选项,导致字符串字面量属性名被混淆。
解决方案
从API version 18开始,主模块默认不会被三方库的混淆规则所影响,因此不会有这种情况。但如果API version低于18,可参考以下两种解决方案。
方案一:确认依赖的远程HAR包的obfuscation.txt文件中是否配置了-enable-string-property-obfuscation选项。若配置了则会影响主模块,需将其关闭。参考排查非预期的混淆能力。
方案二:若工程复杂无法找到配置了该混淆选项的远程HAR包,可以将属性名直接配置到白名单中。
问题现象
HiLog日志中报错信息为:table Account has no column named a1 in 'INSERT INTO Account(a1)'。
import { ValuesBucket } from '@kit.ArkData';
// ...
const valueBucket: ValuesBucket = {
ID1: 'ID1', // ID1应该被保留
NAME1: 'jack', // NAME1应该被保留
AGE1: 20, // AGE1应该被保留
SALARY1: 100 // SALARY1应该被保留
} // 混淆后
import { ValuesBucket } from '@kit.ArkData';
// ...
const valueBucket: ValuesBucket = {
a1: 'ID1',
b1: 'jack',
c1: 20,
d1: 100
}; 问题原因
混淆时代码中的SQL语句字段名称被混淆,但数据库中字段为原始名称,从而导致报错。
解决方案
使用-keep-property-name选项将使用到的数据库字段配置到白名单。
-keep-property-name ID1 NAME1 AGE1 SALARY1