文档管理中心

ArkGuard混淆保留选项

从API version 10开始,开启混淆后代码中的方法、属性或路径将被混淆。但在运行时,通过混淆前的原始名称访问已被混淆的方法、属性或路径,可能会导致功能失效。因此需要根据不同的场景配置相应的保留选项。

排查场景和配置字段时,推荐使用混淆助手配置保留选项,快速识别需要配置的保留选项和白名单字段。

保留选项汇总

展开
功能 选项 起始API版本
指定保留属性名称 -keep-property-name 10
指定保留顶层作用域或导入导出元素名称 -keep-global-name 10
指定保留文件/文件夹名称 -keep-file-name 10
指定保留注释 -keep-comments 12
指定保留声明文件中的所有名称 -keep-dts 12
指定保留源码文件中的所有名称 -keep 12
名称类和路径类的保留选项支持通配符 保留选项支持的通配符 12
在代码压缩时排除指定路径的文件 -keep-uncompact 26.0.0

-keep-property-name

指定想保留的属性名,支持使用名称类通配符。按如下方式进行配置,表示保留名称为firstName和lastName的属性:

收起
自动换行
深色代码主题
复制
  1. -keep-property-name
  2. firstName
  3. lastName

使用该选项时,需要注意以下事项:

  1. 该选项在开启-enable-property-obfuscation时生效。
  2. 属性白名单作用于全局。即代码中出现多个重名属性,只要与-keep-property-name配置白名单名称相同,均不会被混淆。

需要手动配置白名单的属性名:

  1. 如果代码中通过字符串拼接、变量访问或使用defineProperty方法定义对象属性,则这些属性名应被保留。

    收起
    自动换行
    深色代码主题
    复制
    1. // ArkGuardAbility.js
    2. var obj = {x0: '0', x1: '1', x2: '2'};
    3. for (var i = 0; i <= 2; i++) {
    4. console.info(obj['x' + i]); // x0, x1, x2应该被保留
    5. }
    6. Object.defineProperty(obj, 'y', {}); // y应该被保留
    7. Object.getOwnPropertyDescriptor(obj, 'y'); // y应该被保留
    8. console.info(obj.y);
    9. obj.s1 = 'a';
    10. let key = 's1';
    11. console.info(obj[key]); // key对应的变量值s1应该被保留
    12. obj.t1 = 'b';
    13. console.info(obj['t' + '1']); // t1应该被保留

    对于如下的字符串常量形式的属性调用,可以选择性保留:

    收起
    自动换行
    深色代码主题
    复制
    1. // 混淆配置:
    2. // -enable-property-obfuscation
    3. // -enable-string-property-obfuscation
    4. // ArkGuardAbility.ts
    5. var obj2 = {t:'1', m:'2'};
    6. obj2.t = 'a';
    7. console.info(obj2['t']); // 此时,'t'会被正确混淆,t可以选择性保留
    8. obj2['m'] = 'b';
    9. console.info(obj2['m']); // 此时,'m'会被正确混淆,m可以选择性保留
  2. 对于间接或直接导出的类或对象的属性名的场景,如果混淆后出现问题,可以使用-keep-property-name来保留这些属性名。

    收起
    自动换行
    深色代码主题
    复制
    1. // 间接导出MyClass07
    2. class MyClass07 {
    3. greet() {}
    4. }
    5. let alias = new MyClass07();
    6. export { alias };
    7. // 直接导出MyClass08
    8. export class MyClass08 {
    9. exampleName: 'jack'
    10. exampleAge: 100
    11. }
  3. 在ArkTS/TS/JS文件中使用so库的API(如示例中的addNum)时,需手动保留API名称。

    收起
    自动换行
    深色代码主题
    复制
    1. // src/main/cpp/types/libentry/Index.d.ts
    2. export const addNum: (a: number, b: number) => number;
    收起
    自动换行
    深色代码主题
    复制
    1. // ArkGuardAbility.ets
    2. import testNapi from 'libentry.so';
    3. // ...
    4. testNapi.addNum(2, 3); // addNum需要保留,示例如:-keep-property-name addNum
  4. JSON数据解析和对象序列化时,需要保留使用到的字段。

    收起
    自动换行
    深色代码主题
    复制
    1. {
    2. "jsonProperty": "value",
    3. "otherProperty": "value2"
    4. }
    收起
    自动换行
    深色代码主题
    复制
    1. import jsonData from './ImportJson.json';
    2. // ...
    3. let jsonProp = jsonData.jsonProperty; // jsonProperty应该被保留
    4. class JsonTest {
    5. prop1: string = '';
    6. prop2: number = 0
    7. }
    8. let obj = new JsonTest();
    9. const jsonStr = JSON.stringify(obj); // prop1 和 prop2 会被混淆,应该被保留
  5. 使用到的数据库相关的字段,需要手动保留。例如,数据库键值对类型(ValuesBucket)中的属性:

    收起
    自动换行
    深色代码主题
    复制
    1. import { ValuesBucket } from '@kit.ArkData';
    2. // ...
    3. const valueBucket: ValuesBucket = {
    4. ID1: 'ID1', // ID1应该被保留
    5. NAME1: 'jack', // NAME1应该被保留
    6. AGE1: 20, // AGE1应该被保留
    7. SALARY1: 100 // SALARY1应该被保留
    8. }
  6. 源码中自定义装饰器修饰了成员变量、成员方法、参数,同时其源码编译的中间产物为js文件时(如编译release源码HAR或者源码包含@ts-ignore、@ts-nocheck),这些装饰器所在的成员变量/成员方法名称需要被保留。这是由于ts高级语法特性转换为js标准语法时,将上述装饰器所在的成员变量/成员方法名称硬编码为字符串常量。

    收起
    自动换行
    深色代码主题
    复制
    1. function CustomDecorator(target: Object, propertyKey: string) {}
    2. function MethodDecorator(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {}
    3. function ParamDecorator(target: Object, propertyKey: string, parameterIndex: number) {}
    4. class A {
    5. // 1.成员变量装饰器
    6. @CustomDecorator
    7. propertyName1: string = "" // propertyName1 需要被保留
    8. // 2.成员方法装饰器
    9. @MethodDecorator
    10. methodName1() {} // methodName1 需要被保留
    11. // 3.方法参数装饰器
    12. methodName2(@ParamDecorator param: string): void {} // methodName2 需要被保留
    13. }
  7. 使用到的数据请求相关的字段需要手动保留,例如,传递给数据请求方的字段需要手动保留:

    收起
    自动换行
    深色代码主题
    复制
    1. // ArkGuardAbility.ets
    2. import { UIAbility } from '@kit.AbilityKit';
    3. import { http } from '@kit.NetworkKit';
    4. // ...
    5. export default class EntryAbility extends UIAbility {
    6. onForeground(): void {
    7. let httpRequest = http.createHttp();
    8. httpRequest.request('https://www.example/Login',
    9. {
    10. method: http.RequestMethod.POST,
    11. header: { 'Content-Type': 'application/json' },
    12. extraData: { usernameTest: 'test1', passwordTest: 'test2'}, // usernameTest 和 passwordTest 需要被保留
    13. })
    14. }
    15. }
  8. 使用到的数字字面量属性需要手动保留。

    收起
    自动换行
    深色代码主题
    复制
    1. class MyClass09 {
    2. 123 = 'numeric-prop'; // 数字字面量属性
    3. [456] = 'computed'; // 计算属性中的数字
    4. method() {
    5. console.info(this[123]); // 123和456需要被保留
    6. console.info(this[456]);
    7. }
    8. }

-keep-global-name

指定要保留的顶层作用域及导入和导出元素的名称,支持使用名称类通配符。配置方式如下:

收起
自动换行
深色代码主题
复制
  1. -keep-global-name
  2. Person
  3. printPersonName

namespace中导出的名称也可以通过-keep-global-name选项保留。

收起
自动换行
深色代码主题
复制
  1. // ArkGuardAbility.ts
  2. export namespace Ns {
  3. export const myAge = 18 // -keep-global-name myAge 保留变量myAge
  4. export function myFunc() {} // -keep-global-name myFunc 保留函数myFunc
  5. }

使用该选项时,需要注意以下事项:

  1. 该选项在开启-enable-toplevel-obfuscation或-enable-export-obfuscation时生效。
  2. -keep-global-name指定的白名单作用于全局。即代码中出现多个顶层作用域名称或者导出名称,只要与-keep-global-name配置的白名单名称相同,均不会被混淆。

需要手动配置白名单的顶层作用域名称:

当以命名导入的方式导入so库的API时,如果同时开启-enable-toplevel-obfuscation和-enable-export-obfuscation选项,需要手动保留API的名称。

收起
自动换行
深色代码主题
复制
  1. // src/main/cpp/types/libentry/Index.d.ts
  2. declare function testNapi2(): void;
  3. declare function testNapi3(): void;
收起
自动换行
深色代码主题
复制
  1. // ArkGuardAbility.ets
  2. import { testNapi2, testNapi3 as myNapi } from 'libentry.so'; // testNapi2 和 testNapi3 应该被保留
  3. // ...
  4. testNapi2();
  5. myNapi();

-keep-file-name

指定要保留的文件或文件夹名称(不需要写文件后缀),支持使用名称类通配符。

以文件路径"utils/file.ets"为例,配置白名单的方法如下:

收起
自动换行
深色代码主题
复制
  1. -keep-file-name
  2. utils
  3. file

使用该选项时,需要注意以下事项:

  1. 该选项在开启-enable-filename-obfuscation时生效。
  2. -keep-file-name指定的白名单作用于全局。即不同层级的文件或文件夹名称,只要与-keep-file-name配置的白名单名称相同,均不会被混淆。
  3. 不支持使用路径类通配符。
    收起
    自动换行
    深色代码主题
    复制
    1. # 这种写法仅保留该条路径,pages目录下的文件和文件夹名称依旧会被混淆
    2. -keep-file-name
    3. ./src/main/ets/components/pages/**

需要手动配置白名单的文件名:

  1. 在使用require引入文件路径时,由于ArkTS不支持CommonJS模块语法,因此这种情况下require引入的文件路径应该被保留。

    收起
    自动换行
    深色代码主题
    复制
    1. // ArkGuardAbility.js
    2. const module1 = require('./RequireFile'); // RequireFile 应该被保留
  2. 对于动态导入的路径名,由于无法识别import函数中的参数是否为路径,因此在这种情况下应保留动态导入的路径名。

    收起
    自动换行
    深色代码主题
    复制
    1. // DynamicImportFile.ts
    2. export function foo () {}
    收起
    自动换行
    深色代码主题
    复制
    1. // ArkGuardAbility.ts
    2. const moduleName = './DynamicImportFile'; // moduleName对应的路径名DynamicImportFile应该被保留
    3. async function func2() {
    4. const modules = await import(moduleName);
    5. const result = modules.foo();
    6. }
  3. 对于API version 19及之前版本,使用Navigation跨包路由进行路由跳转时,传递给动态路由的路径应被保留。动态路由提供系统路由表和自定义路由表两种方式:

    若采用自定义路由表进行跳转,配置白名单的方式与第二种动态引用场景一致。

    若采用系统路由表进行跳转,则需将模块下resources/base/profile/route_map.json文件中pageSourceFile字段对应的路径添加到白名单中。

    对于API version 20及之后版本,不再需要手动配置白名单。

    收起
    自动换行
    深色代码主题
    复制
    1. {
    2. "routerMap": [
    3. {
    4. "name": "PageOne",
    5. "pageSourceFile": "src/main/ets/pages/directory/PageOne.ets",
    6. "buildFunction": "PageOneBuilder",
    7. "data": {
    8. "description" : "this is PageOne"
    9. }
    10. }
    11. ]
    12. }
  4. 对于API version 19及之前版本,使用应用启动框架AppStartup时,启动参数配置文件和启动任务文件的路径应保留。这些路径配置在本模块的resources/base/profile/startup_config.json文件中,分别对应configEntry字段和startupTasks对象的srcEntry字段。

    对于API version 20及之后版本,不再需要手动配置白名单。

    startup_config.json文件示例如下:

    收起
    自动换行
    深色代码主题
    复制
    1. {
    2. "startupTasks": [
    3. {
    4. "name": "StartupTask_001",
    5. "srcEntry": "./ets/startup/StartupTask_001.ets",
    6. "dependencies": [
    7. "StartupTask_002"
    8. ],
    9. "runOnThread": "taskPool",
    10. "waitOnMainThread": false
    11. },
    12. {
    13. "name": "StartupTask_002",
    14. "srcEntry": "./ets/startup/StartupTask_002.ets",
    15. "runOnThread": "taskPool",
    16. "waitOnMainThread": false
    17. }
    18. ],
    19. "configEntry": "./ets/startup/StartupConfig.ets"
    20. }

    配置白名单方式如下:

    收起
    自动换行
    深色代码主题
    复制
    1. -keep-file-name
    2. # 启动任务文件路径为:"./ets/startup/StartupTask_001.ets" 和 "./ets/startup/StartupTask_002.ets"。
    3. startup
    4. StartupTask_001
    5. StartupTask_002
    6. # 启动参数配置文件路径为:"./ets/startup/StartupConfig.ets"。
    7. StartupConfig
  5. 使用三方库提供的路由跳转方法时开启文件名混淆规则,文件路径将被混淆,从而导致跳转失败。因此需要将路由跳转的路径都配置到-keep-file-name下,防止文件路径被混淆。

-keep-comments

保留编译生成的声明文件中class、function、namespace、enum、struct、interface、module、type及属性上方的JsDoc注释,支持使用名称类通配符。例如想保留声明文件中Human类上方的JsDoc注释,可进行以下配置:

收起
自动换行
深色代码主题
复制
  1. -keep-comments
  2. Human

使用该选项时,需要注意以下事项:

  1. 该选项在开启-remove-comments时生效。

  2. 当编译生成的声明文件中class、function、namespace、enum、struct、interface、module、type及属性的名称被混淆时,该元素上方的JsDoc注释无法通过-keep-comments保留。例如,当在-keep-comments中配置了exportClass时,如果exportClass类名被混淆,其JsDoc注释无法被保留。

    收起
    自动换行
    深色代码主题
    复制
    1. /**
    2. * @class exportClass
    3. */
    4. export class exportClass {}

-keep-dts

指定路径filepath的.d.ts文件中的名称(如变量名、类名、属性名等)将被添加到-keep-global-name和-keep-property-name白名单中。请确保filepath为绝对路径,也可以指定为一个目录。如果指定为目录,则该目录下所有.d.ts文件中的名称都将被保留。

-keep

保留指定相对路径filepath中的所有名称(例如变量名、类名、属性名等)不被混淆。filepath可以是文件或文件夹,若是文件夹,则文件夹下的文件及子文件夹中文件都不混淆。

filepath仅支持相对路径,./和../为相对于混淆配置文件所在目录,支持使用路径类通配符。

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ./src/main/ets/fileName.ts // fileName.ts中的名称不混淆
  3. ../folder // folder目录下文件及子文件夹中的名称都不混淆
  4. ../oh_modules/json5 // 引用的三方库json5里所有文件中的名称都不混淆

如何在模块中保留远程HAR包

方式一:指定远程HAR包在模块级oh_modules中的具体路径(该路径为软链接路径,真实路径为工程级oh_modules中的文件路径)。因为在配置模块级oh_modules中的路径作为白名单时,需要具体到包名或之后的目录才能正确地软链接到真实的目录路径,所以不能仅配置HAR包的上级目录名称。

收起
自动换行
深色代码主题
复制
  1. // 正例
  2. -keep
  3. ./oh_modules/harName1 // harName1目录下所有文件及子文件夹中的名称都不混淆
  4. ./oh_modules/harName1/src // src目录下所有文件及子文件夹中的名称都不混淆
  5. ./oh_modules/folder/harName2 // harName2目录下所有文件及子文件夹中的名称都不混淆
  6. // 反例
  7. -keep
  8. ./oh_modules // 保留模块级oh_modules里HAR包时,不支持配置HAR包的上级目录名称

方式二:指定远程HAR包在工程级oh_modules中的具体路径。工程级oh_modules中的文件路径均为真实路径,可直接配置。

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ../oh_modules // 工程级oh_modules目录下所有文件及子文件夹中的名称都不混淆
  3. ../oh_modules/harName3 // harName3目录下所有文件及子文件夹中的名称都不混淆

模块级oh_modules和工程级oh_modules在DevEco Studio中的目录结构如下图所示:

使用该选项时,需要注意以下事项:

  1. 使用-keep filepath保留的文件,其依赖链路上的文件中导出的名称及其属性也会被保留。
  2. 该功能不影响文件名混淆-enable-filename-obfuscation的功能。
  3. 使用-keep规则保留某个文件时,该文件中的代码不会被混淆,但是在其他文件中引用该文件中的属性名称时,仍然可能被混淆,此时可参考-keep规则常见案例来解决。

-keep-uncompact

从API版本26.0.0开始,可通过-keep-uncompact指定相对路径下的源码不参与代码压缩。

使用该选项时,需要注意以下事项:

  1. 该选项在开启-compact功能后才会生效;未开启-compact时,配置不生效。
  2. 配置的路径仅支持相对路径,./和../均为相对于混淆配置文件所在的目录。若配置路径为文件夹,则该文件夹下的文件及子文件夹中的文件都不被压缩。
  3. 当配置路径指向远程三方包(即oh_modules目录)时,需指定其在工程级oh_modules中的真实路径(与-keep中保留远程HAR包的方式二一致),以确保路径解析正确。
收起
自动换行
深色代码主题
复制
  1. -compact
  2. -keep-uncompact
  3. ./src/main/ets/example/FileA.ets
  4. ./src/main/ets/example/folder
  5. ../oh_modules/somePackage/src

保留选项支持的通配符

名称类通配符

名称类通配符使用方式如下:

展开
通配符 含义 示例
? 匹配任意单个字符 "AB?"能匹配"ABC"等,但不能匹配"AB"。
* 匹配任意数量的任意字符 "*AB*"能匹配"AB"、"aABb"、"cAB"、"ABc"等。

使用示例:

保留所有以a开头的属性名称:

收起
自动换行
深色代码主题
复制
  1. -keep-property-name
  2. a*

保留所有单个字符的属性名称:

收起
自动换行
深色代码主题
复制
  1. -keep-property-name
  2. ?

保留所有属性名称:

收起
自动换行
深色代码主题
复制
  1. -keep-property-name
  2. *

路径类通配符

路径类通配符使用方式如下:

展开
通配符 含义 示例
? 匹配任意单个字符,除了路径分隔符/。 "../a?"能匹配"../ab"等,但不能匹配"../a/"。
* 匹配任意数量的任意字符,但不包括路径分隔符/。 "../a*/c"能匹配"../ab/c",但不能匹配"../ab/d/s/c"。
** 匹配任意数量的任意字符。 "../a**/c"能匹配"../ab/c",也能匹配"../ab/d/s/c"。
! 表示非,只能写在某个路径最前端,用来排除用户配置的白名单中已有的某种情况。 "!../a/b/c.ets"表示匹配除了"../a/b/c.ets"以外的路径。

使用示例:

表示路径../a/b/中所有文件夹(不包含子文件夹)中的c.ets文件不会被混淆:

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ../a/b/*/c.ets

表示路径../a/b/中所有文件夹(包含子文件夹)中的c.ets文件不会被混淆:

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ../a/b/**/c.ets

表示路径../a/b/中,除了c.ets文件以外的其它文件都不会被混淆。其中,!不可单独使用,只能用来排除白名单中已有的情况:

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ../a/b/
  3. !../a/b/c.ets

表示路径../a/中的所有文件(不包含子文件夹)不会被混淆:

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ../a/*

表示路径../a/下的所有文件夹(包含子文件夹)中的所有文件不会被混淆:

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ../a/**

表示模块内的所有文件不会被混淆:

收起
自动换行
深色代码主题
复制
  1. -keep
  2. ./**

使用通配符时,需要注意以下事项:

  1. 以上选项不支持将通配符*、?、!用作其他含义。

    收起
    自动换行
    深色代码主题
    复制
    1. class A {
    2. '*'= 1
    3. }
    4. -keep-property-name
    5. *

    此时*表示匹配任意数量的任意字符,配置效果为所有属性名称都不会被混淆,而不是只有*属性不被混淆。

  2. -keep选项中只允许使用/路径格式,不支持\或\\。