1# ArkGuard Principles and Capabilities for Source Code Obfuscation 2 3## Glossary 4 5| Term| Definition| 6| --- | --- | 7| [HAP](../quick-start/hap-package.md) | The Harmony Ability Package (HAP) is the basic unit for installing and running applications. It is a module package generated by packaging code, resources, third-party libraries, and configuration files.| 8| [HAR](../quick-start/har-package.md) | A Harmony Archive (HAR) is a static shared package that enables multiple modules or projects to share code such as ArkUI components and resources. It is created by using a static library.| 9| [HSP](../quick-start/in-app-hsp.md) | A Harmony Shared Package (HSP) is a dynamic shared package for sharing code and resources. It is created by using a shared library.| 10| Local HAR| HAR module in source code form.| 11| Remote HAR| HAR generated after the build.| 12| Local HSP| HSP module in source code form.| 13| Remote HSP| HSP generated after the build.| 14| Third-party library| Libraries developed by third parties and published to the OpenHarmony Third-Party Library Repository.| 15| Name obfuscation| Changing class names, method names, variable names, property names, exported variable names and other identifiers to simple, meaningless names.| 16 17## Scope of Obfuscation Capabilities 18 19### Supported Languages 20ArkGuard supports ArkTS, TS, and JS, but not C/C++, JSON, or resource files. 21 22### Obfuscation Capabilities 23ArkGuard provides name obfuscation, code compression, and comment removal, but does not support advanced features like control stream obfuscation or data obfuscation. 24 25It primarily offers name renaming and trustlist configuration for retention. 26 27### Limitations of Obfuscation Capabilities 28 29**Language Limitations** 30 31Source code obfuscation tools vary in type analysis mechanisms, obfuscation strategies, and execution efficiency based on the target language. For example, ProGuard targets strongly-typed languages like Java, where each type has a clear definition source. This feature makes the type relationship tracing and processing in the obfuscation process more accurate, greatly reducing the need for retention rules. 32 33In contrast, ArkGuard targets JS, TS, and ArkTS. Suppose ArkGuard supports configuring a trustlist for specific types. JS supports dynamic modification of objects and functions at runtime, but obfuscation is a static process in the compilation phase. This difference may cause a failure in parsing obfuscated named at runtime, resulting in runtime exceptions. TS and ArkTS use a structural type system, where different named types with the same structure are considered as equivalent types. Therefore, it is difficult to trace the exact source of types. As such, when using ArkGuard, you need to configure trustlists for more syntax scenarios. Moreover, ArkGuard uses a global property retention mechanism that retains all properties with the same name according to the trustlist. It does not support precise retention settings for specific types. 34 35To illustrate, consider this example: 36 37Assume that ArkGuard allows the configuration of a trustlist for specific types. If class A1 is configured in a trustlist with its property prop1, but prop1 in class A2 is not in the trustlist, then passing an instance of A2 as a parameter to the **test** function and accessing its properties within the function could lead to issues. Before obfuscation, accessing the prop1 property works as expected. However, after obfuscation, since prop1 in A1 remains unchanged while prop1 in A2 is obfuscated, accessing prop1 in the **test** function will result in functionality anomalies. 38 39ArkGuard does not support precise retention configurations for specific types. 40 41```typescript 42// Before obfuscation: 43class A1 { 44 prop1: string = ''; 45} 46 47class A2 { 48 prop1: string = ''; 49} 50 51function test(input: A1) { 52 console.log(input.prop1); 53} 54 55let a2 = new A2(); 56a2.prop1 = 'prop a2'; 57test(a2); 58``` 59 60```typescript 61// After obfuscation: 62class A1 { 63 prop1: string = ''; 64} 65 66class A2 { 67 a: string = ''; 68} 69 70function test(input: A1) { 71 console.log(input.prop1); 72} 73 74let a2 = new A2(); 75a2.a = 'prop a2'; 76test(a2); 77``` 78 79You should be aware of these differences and use unique names to achieve better obfuscation results. 80 81**Limited security assurance** 82 83Similar to other source code obfuscation tools, ArkGuard increases reverse engineering difficulty but cannot prevent it entirely. 84 85You should not rely solely on ArkGuard for security. For higher security requirements, consider [application encryption](https://developer.huawei.com/consumer/en/doc/harmonyos-guides/code-protect) and hardening measures. 86 87## Obfuscation Mechanism and Process 88 89The following figure shows a simplified compilation process. 90 91 92 93You can enable the obfuscation feature in the **build-profile.json5** file of the module so that the source code can be automatically obfuscated during compilation and packaging. For details, see [Using ArkGuard for Source Code Obfuscation](source-obfuscation-guide.md). 94 95During obfuscation, the tool reads the obfuscation switch. If the switch is enabled, it parses the obfuscation configuration file, merges rules according to the [merging strategies](#obfuscation-rule-merging-strategies), applies obfuscation to intermediate files (generated after syntax conversion), and writes the obfuscated files to the **build** directory. You can verify the obfuscation effect by examining the output in the **build** directory. 96 97Before using obfuscation, you are advised to learn about the capabilities of [obfuscation options](source-obfuscation.md#obfuscation-options) and [retention options](source-obfuscation.md#retention-options), and select the appropriate capabilities for your needs. 98 99 100## Obfuscation Options 101 102### Summary of Existing Obfuscation Options 103 104| Function| Option| 105| --- | --- | 106| Default obfuscation| Enabled after obfuscation is enabled| 107| Disabling obfuscation| [`-disable-obfuscation`](#-disable-obfuscation) | 108| Enabling obfuscation for property names| [`-enable-property-obfuscation`](#-enable-property-obfuscation) | 109| Enabling obfuscation for string literal property names| [`-enable-string-property-obfuscation`](#-enable-string-property-obfuscation) | 110| Enabling obfuscation for top-level scope name obfuscation.| [`-enable-toplevel-obfuscation`](#-enable-toplevel-obfuscation) | 111| Enabling obfuscation for imported/exported names| [`-enable-export-obfuscation`](#-enable-export-obfuscation) | 112| Enabling obfuscation for file names| [`-enable-filename-obfuscation`](#-enable-filename-obfuscation) | 113| Compressing code| [`-compact`](#-compact) | 114| Removing declaration file comments| [`-remove-comments`](#-remove-comments) | 115| Removing console.* statement.| [`-remove-log`](#-remove-log) | 116| Printing name caches| [`-print-namecache`](#-print-namecache) | 117| Reusing name caches| [`-apply-namecache`](#-apply-namecache) | 118| Printing unobfuscated names| [`-print-kept-names`](#-print-kept-names) | 119| Reducing the default language trustlist| [`-extra-options strip-language-default`](#-extra-options-strip-language-default) | 120| Reducing the default system API trustlist| [`-extra-options strip-system-api-args`](#-extra-options-strip-system-api-args) | 121| Retaining declaration file parameters| [`-keep-parameter-names`](#-keep-parameter-names) | 122| Merging dependent module options| [`-enable-lib-obfuscation-options`](#-enable-lib-obfuscation-options) | 123| Marking trustlists in source code by comments| [`-use-keep-in-source`](#-use-keep-in-source) | 124 125### Default Obfuscation 126 127Default obfuscation takes effect automatically when obfuscation is enabled, and it only obfuscates local variable names and parameter names. 128 129### -disable-obfuscation 130 131Disables code obfuscation. 132 133If this option is configured, the default obfuscation capabilities (obfuscating only local variables and parameter names) and all configured obfuscation and retention options become invalid. 134 135### -enable-property-obfuscation 136 137Enables property name obfuscation. The effect is as follows: 138 139 ``` 140 // Before obfuscation: 141 class TestA { 142 static prop1: number = 0; 143 } 144 TestA.prop1; 145 ``` 146 147 ``` 148 // After obfuscation: 149 class TestA { 150 static i: number = 0; 151 } 152 TestA.i; 153 ``` 154 155If this option is configured, all property names except the following are obfuscated: 156 157* Property names of classes and objects that are directly imported or exported by using **import** or **export** in case that the **-enable-export-obfuscation** option is not configured. For example, the property name **data** in the following example is not obfuscated. 158 159 ``` 160 export class MyClass { 161 data: string; 162 } 163 ``` 164 165* Property names in ArkUI components. For example, **message** and **data** in the following example are not obfuscated. 166 167 ``` 168 @Component struct MyExample { 169 @State message: string = "hello"; 170 data: number[] = []; 171 // ... 172 } 173 ``` 174 175* Property names specified in [retention options](#-keep-property-name). 176* Property names in the SDK API list. The SDK API list is a set of names automatically extracted from the SDK during build. Its cache file is **systemApiCache.json**, which is stored in **build/default/cache/{...}/release/obfuscation** in the project directory. 177* String literal property names. For example, **exampleName** and **exampleAge** in the following example are not obfuscated. 178 179 ``` 180 let person = {"exampleName": "abc"}; 181 person["exampleAge"] = 22; 182 ``` 183 184* Annotation member names. For example, **authorName** and **revision** in the following example are not obfuscated. 185 186 ``` 187 @interface MyAnnotation { 188 authorName: string; 189 revision: number = 1; 190 } 191 ``` 192 193### -enable-string-property-obfuscation 194 195To obfuscate string literal property names, you must use this option together with **-enable-property-obfuscation**. Example: 196 197 ``` 198 -enable-property-obfuscation 199 -enable-string-property-obfuscation 200 ``` 201 202According to the preceding configuration, the obfuscation effect of **exampleName** and **exampleAge** is as follows: 203 204 ``` 205 // Before obfuscation: 206 let person = {"exampleName": "abc"}; 207 person["exampleAge"] = 22; 208 ``` 209 210 ``` 211 // After obfuscation: 212 let person = {"a": "abc"}; 213 person["b"] = 22; 214 ``` 215 216 217 218**NOTE** 219 220**1.** If a string literal property name in the code contains special characters, for example, **let obj = {"\n": 123, "": 4, " ": 5}**, you are advised not to use the **-enable-string-property-obfuscation** option because these names may fail to be retained using [retention options](#-keep-property-name). Special characters refer to characters other than lowercase letters a-z, uppercase letters A-Z, digits 0-9, and underscores (_). 221 222**2.** The property trustlist of the SDK API list does not contain string constants used in the declaration file. For example, the string **'ohos.want.action.home'** in the example is not included in the property trustlist. 223``` 224// Part of the SDK API file @ohos.app.ability.wantConstant: 225export enum Params { 226 ACTION_HOME = 'ohos.want.action.home' 227} 228// Source code example: 229let params = obj['ohos.want.action.home']; 230``` 231 232When the **-enable-string-property-obfuscation** option is used, use the [-keep-property-name](#-keep-property-name) option if you want to retain the property names in the SDK API string constants in the source code, for example, **obj['ohos.want.action.home']**. 233 234### -enable-toplevel-obfuscation 235 236Enables obfuscation of top-level scope names. The effect is as follows: 237 238 ``` 239 // Before obfuscation: 240 let count = 0; 241 ``` 242 243 ``` 244 // After obfuscation: 245 let s = 0; 246 ``` 247 248If this option is configured, the names of all top-level scopes except the following are obfuscated: 249 250* Names that are directly imported or exported by using **import** or **export** in case that the **-enable-export-obfuscation** option is not configured. 251* Top-level scope names that are not declared in the current file. 252* Top-level scope names specified by [retention options](#-keep-global-name). 253* Top-level scope names in the SDK API list. 254 255### -enable-export-obfuscation 256 257Enables obfuscation for imported/exported names. The effect is as follows: 258 259 ``` 260 // Before obfuscation: 261 namespace ns { 262 export type customT = string; 263 } 264 ``` 265 266 ``` 267 // After obfuscation: 268 namespace ns { 269 export type h = string; 270 } 271 ``` 272 273If this option is configured, only names imported/exported in non-top-level scopes will be obfuscated. To obfuscate names imported/exported in the top-level scope, use this option with **-enable-toplevel-obfuscation**. To obfuscate imported or exported property names, use this option **-enable-property-obfuscation**. Note the following special scenarios: 274 275* Names exported from remote HARs (packages whose real paths are in **oh_modules**) and their property names are not obfuscated. 276* Names and property names specified by [retention options](#retention-options) are not obfuscated. 277* Names in the SDK API list are not obfuscated. 278 279### -enable-filename-obfuscation 280 281Enables obfuscation of file/folder names. The effect is as follows: 282 283 ``` 284 // Before obfuscation: 285 import * as m from '../test1/test2'; 286 import { foo } from '../test1/test2'; 287 const module = import('../test1/test2'); 288 ``` 289 290 291 ``` 292 // After obfuscation: 293 import * as m from '../a/b'; 294 import { foo } from '../a/b'; 295 const module = import('../a/b'); 296 ``` 297 298If this option is configured, all file names and folder names except the following are obfuscated: 299 300* File or folder names specified by the **main** and **types** fields in the **oh-package.json5** file. 301* File or folder names specified by the **srcEntry** field in the **module.json5** file of the module. 302* File or folder names specified by [-keep-file-name](#-keep-file-name). 303* File or folder names in non-ECMAScript module reference mode (for example, const module = require('./module')). 304* File or folder names in non-path reference mode. For example, **json5** in the example **import module from 'json5'** is not obfuscated. 305 306>**NOTE** 307> 308>For files that the system needs to load files during application running, manually configure them into a trustlist using the [-keep-file-name](#-keep-file-name) option. Otherwise, the application may fail to run. 309> 310>The names of the compilation entry file, ability component file, and Worker multithreaded file cannot be obfuscated and have been automatically added to the trustlist in DevEco Studio 5.0.3.500 or later. No manual configuration is required. For other files that cannot be obfuscated, you need to manually configure their names in the trustlist. 311 312### -compact 313 314Removes spaces and all newline characters that do not participate in the syntax structure and do not affect program execution. 315 316If this option is configured, all code is compressed to one line. The effect is as follows: 317 318 ``` 319 // Before obfuscation: 320 class TestA { 321 static prop1: number = 0; 322 } 323 TestA.prop1; 324 ``` 325 326 ``` 327 // After obfuscation: 328 class TestA { static prop1: number = 0; } TestA.prop1; 329 ``` 330 331>**NOTE** 332> 333>The stack information built in release mode contains the line number of code, but not the column number. Therefore, when the **compact** option is used, the source code cannot be located based on the line number in the stack information. 334 335### -remove-comments 336 337Removes JsDoc comments from the declaration file generated after compilation. The effect is as follows: 338 339Before obfuscation: 340 ``` 341 /** 342 * @todo 343 */ 344 declare let count: number; 345 ``` 346 347After obfuscation: 348 ``` 349 declare let count: number; 350 ``` 351 352You can configure [-keep-comments](#-keep-comments) to retain the JsDoc comments in the declaration file. 353 354>**NOTE** 355> 356> By default, all comments in the source code file generated after the compilation are removed and cannot be retained. 357 358### -remove-log 359 360Removes calls to console.* statements, provided the return value is not used. The effect is as follows: 361 362 ``` 363 // Before obfuscation: 364 if (flag) { 365 console.log("hello"); 366 } 367 ``` 368 369 ``` 370 // After obfuscation: 371 if (flag) { 372 } 373 ``` 374 375If this option is configured, the console.* statements in the following scenarios are removed: 376 3771. Calls at the top layer of a file. 378 Example: 379 ```js 380 console.log("in tolevel"); 381 ``` 3822. Calls within a code block. 383 Example: 384 ``` 385 function foo() { 386 console.log('in block'); 387 } 388 ``` 3893. Calls with a module or namespace. 390 Example: 391 ``` 392 namespace ns { 393 console.log('in ns'); 394 } 395 ``` 3964. Calls within a **switch** statement. 397 Example: 398 ```js 399 switch (value) { 400 case 1: 401 console.log("in switch case"); 402 break; 403 default: 404 console.warn("default"); 405 } 406 ``` 407 408### -print-namecache 409 410Saves the name cache to the specified file path. The name cache contains the mappings of names before and after obfuscation. The **filepath** parameter is mandatory. It supports relative and absolute paths. For a relative path, the start point is the current directory of the obfuscation configuration file. The file name extension in **filepath** must be .json. 411 412Example: 413``` 414-print-namecache 415./customCache/nameCache.json 416``` 417 418>**NOTE** 419> 420>A new **namecache.json** file is generated each time the module if fully built. Therefore, save a copy of the file each time you publish a new version. 421 422### -apply-namecache 423 424Reuses a name cache file in the specified file path. The **filepath** parameter is mandatory. It supports relative and absolute paths. For a relative path, the start point is the current directory of the obfuscation configuration file. The file name extension in **filepath** must be .json. 425 426This option applies to incremental build scenarios. After this option is enabled, the names will be obfuscated according to the cache mappings. If there is no corresponding name, new random names are used. 427 428Example: 429``` 430-apply-namecache 431./customCache/nameCache.json 432``` 433 434By default, DevEco Studio saves cache files in a temporary cache directory and automatically applies the cache files during incremental build. 435Default cache directory: **build/default/cache/{...}/release/obfuscation** 436 437### -print-kept-names 438 439Prints the unobfuscated list and full trustlist to the specified file path. The **filepath** parameter is optional. It supports relative paths, with the start point being the current directory of the obfuscation configuration file. The file name extension in **filepath** must be .json. 440 441If the **filepath** parameter is not specified, the unobfuscated list (**keptNames.json**) and full trustlist (**whitelist.json**) are output to the cache directory **build/default/cache/{...}/release/obfuscation** by default. 442 443If the **filepath** parameter is specified, the unobfuscated list is also exported to the path specified by this parameter. 444 445The full trustlist collected during a full build is classified into the following types: 446 447(1) 'sdk': system APIs. 448 449(2) 'lang': keywords in the language. 450 451(3) 'conf': trustlist in the user-defined retention options. 452 453(4) 'struct': properties in ArkUI structs. 454 455(5) 'exported': names and properties exported. 456 457(6) 'strProp': string properties. 458 459(7) 'enum': enum members. 460 461The 'sdk' trustlist is exported to the **systemApiCache.json** file in the **build/default/cache/{...}/release/obfuscation/** directory, and other trustlists are exported to the **whitelist.json** file. 462 463The **keptNames.json** file contains the names that are not obfuscated and the reasons why they are not obfuscated. There are seven reasons: The name is the same as that in the SDK trustlist, language trustlist, user-defined trustlist, struct trustlist, exported name trustlist, or string property trustlist (when [string literal property name obfuscation](#-enable-string-property-obfuscation) is disabled), or enum trustlist. 464 465**NOTE** 466 467**1.** During HAR module compilation with property name obfuscation enabled, enum member names are collected into the 'enum' trustlist. 468Example: 469``` 470enum Test { 471 member1, 472 member2 473} 474``` 475The 'enum' trustlist includes names such as ['member1', 'member2']. This requirement stems from the fact that, in earlier HAR module versions, the compilation process produced JS files. In these JS files, enums are represented as immediately invoked functions, with enum members expressed as string properties and constants. To maintain proper functionality during property name obfuscation, these enum member names must be added to the trustlist. This practice continues to be applied when compiling the latest bytecode HAR modules. 476 477**2.** During HAP/HSP/bytecode HAR module compilation with property name obfuscation enabled, variable names in initialization expressions of enum members are collected into the 'enum' trustlist. 478Example: 479``` 480let outdoor = 1; 481enum Test { 482 member1, 483 member2 = outdoor + member1 + 2 484} 485``` 486In the case of HAP/HSP module compilation, the content of the 'enum' trustlist is ['outdoor', 'member1']. In the case of bytecode HAR module compilation, the content is ['outdoor', 'member1', 'member2']. 487 488### -extra-options strip-language-default 489 490By default, the default language trustlist contains the names of APIs related to DOM, WebWorker, and ScriptHost in the TS system interfaces, as well as the names of Web APIs. If property names in the source code match these names, they will be retained. 491 492To obfuscate these parts of the code, configure the **-extra-options strip-language-default** option. 493 494You can determine the specific reduction range of APIs retained by default as follows: 495 496Enable the **-print-kept-names** option and compare the differences in the **lang** field of the **whitelist.json** file when the **-extra-options strip-language-default** option is enabled and disabled. The difference represents the specific reduction range of the default language trustlist. 497 498### -extra-options strip-system-api-args 499 500By default, the system API trustlist contains local variable names in system APIs and is effective for local variables in your source code by default. If property names in the source code match local variables in system APIs or if local variables in the source code match the system API trustlist, these property names and local variables will be retained. 501 502To obfuscate these parts of the code, configure the **-extra-options strip-system-api-args** option. 503 504The specific content of the system API trustlist can be viewed in the **systemApiCache.json** file through the **ReservedLocalNames**, **ReservedPropertyNames**, and **ReservedGlobalNames** fields. This file, located in the directory **build/default/cache/{...}/release/obfuscation**, records the interface and property names in the SDK, and source code with matching names will not be obfuscated. 505 506You can determine the specific reduction range of the system API trustlist as follows: 507 508Compare the differences in the **ReservedLocalNames** and **ReservedPropertyNames** fields of the **systemApiCache.json** file when the **-extra-options strip-system-api-args** option is enabled and disabled. The difference represents the specific reduction range of the system API trustlist. However, the content of the **ReservedGlobalNames** field will not change. 509 510**How to use -extra-options** 511 512Add the **-extra-options** prefix and options in the obfuscation configuration file, with no additional content in between. You can enable either one option or both options, like shown in the following examples: 513 514One option enabled: 515 516``` 517-extra-options 518strip-language-default 519 520-extra-options strip-language-default 521``` 522 523Both options enabled: 524 525``` 526-extra-options strip-language-default, strip-system-api-args 527 528-extra-options strip-language-default strip-system-api-args 529 530-extra-options strip-language-default 531-extra-options strip-system-api-args 532``` 533 534### -keep-parameter-names 535Retains parameter names in declaration files for exported interfaces. The effect is as follows: 536- For functions and class member methods, if the function or method name is not confused, their parameter names are retained. 537- For class constructors, if the class name is not obfuscated, their parameter names in the constructors are retained. 538 539**NOTE** 540 541**1.** Parameter names that are not in the preceding scenarios (such as anonymous functions) will still be obfuscated. 542 543**2.** Parameter names in source code files will be obfuscated regardless of this option. 544 545### -enable-lib-obfuscation-options 546Merges obfuscation options of dependent modules into the obfuscation configuration of the current module. 547 548Obfuscation configuration includes [obfuscation options](#obfuscation-options) and [retention options](#retention-options). 549- By default, the effective obfuscation configuration is the merged result of the current module's obfuscation configuration and the dependent modules' retention options. 550- When this option is configured, the effective obfuscation configuration is the merged result of the current module's obfuscation configuration and the dependent modules' obfuscation configuration. 551 552For details about the merging logic, see [Obfuscation Rule Merging Strategies](#obfuscation-rule-merging-strategies). 553 554### -use-keep-in-source 555 556Marks trustlists in .ts or .ets source code using the following two comment annotations (declaration files are not supported): 557 558// @KeepSymbol: This annotation is used to mark names that should be retained. It is usually placed on the line above the relevant code to ensure that the name is not obfuscated when the code is compiled. 559 560// @KeepAsConsumer: This annotation is used to mark names that should be retained. It is usually placed on the line above the relevant code to ensure that the name is not obfuscated when the code is compiled. In HAR/HSP modules, names marked with @KeepAsConsumer are also listed in the **obfuscation.txt** file. In HAP modules, @KeepAsConsumer works exactly like @KeepSymbol. 561 562> **NOTE** 563> 564> Both types of markings are comments and the slashes (//) should not be removed. 565 566 567 568The examples below use // @KeepSymbol, but // @KeepAsConsumer can be used in the same way for the same purposes. 569 570#### Classes 571 572You can mark the following elements in a class: 573 574- Class declarations 575- Constructors 576- Fields and methods 577 578**Example** 579 580```typescript 581// Retain the class name and all member names. 582// @KeepSymbol 583class MyClass01 { 584 prop01: string = "prop"; // MyClass01 and prop01 are not obfuscated. 585} 586 587// Use the constructor to retain the class name. 588class MyClass02 { 589 prop02: string = "prop"; 590 // @KeepSymbol 591 constructor() {}; // MyClass02 is not obfuscated. 592} 593 594// Retain the class name and specified field and method names. MyClass03, prop03_1, and method03_2 in the class are not obfuscated. 595class MyClass03 { 596 // @KeepSymbol 597 prop03_1: string = "prop"; 598 prop03_2: number = 1; 599 constructor() {}; 600 601 method03_1(): void {}; 602 // @KeepSymbol 603 method03_2(): void {}; 604} 605``` 606 607#### Interfaces 608 609You can mark the following elements in an interface: 610 611- Interface declarations 612- Fields and methods 613 614**Example** 615 616```typescript 617// Retain the interface name and all member names. MyInterface01, name01, and foo01 are not obfuscated. 618// @KeepSymbol 619interface MyInterface01 { 620 name01: string; 621 foo01(): void; 622} 623 624// Retain the interface name and specified field and method names. MyInterface02 and name02 are not obfuscated. 625interface MyInterface02 { 626 // @KeepSymbol 627 name02: string; 628 foo02(): void; 629} 630``` 631 632#### Enums 633 634You can mark the following elements in an enum: 635 636- Enum declarations 637- Enum members 638 639**Example** 640 641```typescript 642// Retain the enum name and all member names. Color01, RED01, and BLUE01 are not obfuscated. 643// @KeepSymbol 644enum Color01 { 645 RED01, 646 BLUE01 647} 648 649// Retain the specified enum member name. 650enum Color02 { 651 RED02, 652 // @KeepSymbol 653 BLUE02 // Color02 and BLUE02 are not obfuscated. 654} 655``` 656 657#### Functions 658 659Currently, function names can be marked. 660 661**Example** 662 663```typescript 664// Retain the function name. MyAdd is not obfuscated. 665// @KeepSymbol 666function MyAdd(a: number, b:number): number { 667 return a + b; 668} 669``` 670 671#### Namespaces 672 673Currently, namespace names can be marked. 674 675**Example** 676 677```typescript 678// Retain the namespace name and the member names directly exported internally. MyNameSpace and foo are not obfuscated. 679// @KeepSymbol 680namespace MyNameSpace { 681 export function foo(){}; 682 function bar(){}; 683} 684``` 685 686#### Global Variables 687 688Currently, only global variables can be marked. Local variables cannot be marked. 689 690**Example** 691 692```typescript 693// Retain the marked variable name. myVal is not obfuscated. 694// @KeepSymbol 695const myVal = 1; 696``` 697 698#### Annotations 699 700Currently, only the marking and retention of annotation declarations are supported. Marking annotation members is invalid, and the annotation members themselves are not obfuscated. 701 702Starting from API version 20, marking annotation declarations is supported. 703 704**Example** 705 706```typescript 707// Retain the marked annotation declaration. MyAnnotation will not be obfuscated. 708// @KeepSymbol 709@interface MyAnnotation { 710 // Marking annotation members is invalid; authorName will not be added to the trustlist. 711 // @KeepSymbol 712 authorName: string; 713 revision: number = 1; 714} 715``` 716 717#### Trustlist Addition Rules 718 719Marked names are added to the obfuscation trustlist based on the following rules. Names kept by **KeepAsConsumer** are also recorded in the **obfuscation.txt** file. 720 721* If a name is at the top level or directly exported, it goes into -keep-global-name. 722 723* If a name is directly exported, it also goes into -keep-property-name. 724 725* If a name is a property, it goes into -keep-property-name. 726 727* Local variable names are not added to the trustlist (they are not kept). 728 729**Example** 730 731```typescript 732// @KeepAsConsumer 733export class MyClass { 734 prop01: string = "prop"; 735} 736``` 737In this example, MyClass is added to -keep-global-name and -keep-property-name, and prop01 is added to -keep-property-name. They are also written into the **obfuscation.txt** file. 738 739#### -Scenarios Not Supported by -use-keep-in-source 740 741String properties, numeric properties, and computed properties are not supported. 742 743**Example** 744 745```typescript 746const myMethodName = "myMethod"; 747 748// 11, aa, and myMethod are not added to the trustlist. 749class MyClass01 { 750 // @KeepSymbol 751 11:11; 752 // @KeepSymbol 753 'aa':'aa'; 754 // @KeepSymbol 755 [myMethodName](){} 756} 757 758// RED is not added to the trustlist. 759enum MyEnum { 760 // @KeepSymbol 761 'RED', 762 BLUE 763} 764``` 765 766## Retention Options 767 768### Summary of Existing Retention Options 769 770| Function| Option| 771| --- | --- | 772| Retaining specified property names| [`-keep-property-name`](#-keep-property-name) | 773| Retaining specified top-level scope names or imported/exported element names| [`-keep-global-name`](#-keep-global-name) | 774| Retaining specified file/folder names| [`-keep-file-name`](#-keep-file-name) | 775| Retaining specified comments| [`-keep-comments`](#-keep-comments) | 776| Retaining all names in specified declaration files| [`-keep-dts`](#-keep-dts) | 777| Retaining all names in specified source code files| [`-keep`](#-keep) | 778 779### -keep-property-name 780 781Retains the specified property names. [Name wildcards](#name-wildcards) are supported. The following configuration is used to retain properties named **age**, **firstName**, and **lastName**: 782 783``` 784-keep-property-name 785age 786firstName 787lastName 788``` 789 790**NOTE** 791 792**1.** This option takes effect when **-enable-property-obfuscation** is used. 793 794**2.** The property trustlist applies globally. That is, if multiple properties with the same name exist in the code, they will not be confused as long as they match the names in the trustlist configured in **-keep-property-name**. 795 796**Which property names should be retained?** 797 7981. If object properties are defined via string concatenation, variable access, or the **defineProperty** method within the code, these property names should be retained. Example: 799 800 ``` 801 var obj = {x0: 0, x1: 0, x2: 0}; 802 for (var i = 0; i <= 2; i++) { 803 console.info(obj['x' + i]); // x0, x1, and x2 should be retained. 804 } 805 806 Object.defineProperty(obj, 'y', {}); // y should be retained. 807 Object.getOwnPropertyDescriptor(obj, 'y'); // y should be retained. 808 console.info(obj.y); 809 810 obj.s = 0; 811 let key = 's'; 812 console.info(obj[key]); // The variable value s corresponding to key should be retained. 813 814 obj.t1 = 0; 815 console.info(obj['t' + '1']); // t1 should be retained. 816 ``` 817 818 For the following string literal property calls, you can choose to retain them. 819 820 ``` 821 // Obfuscation configuration: 822 // -enable-property-obfuscation 823 // -enable-string-property-obfuscation 824 825 obj.t = 0; 826 console.info(obj['t']); // 't' will be correctly confused, and t can be retained. 827 828 obj.['v'] = 0; 829 console.info(obj['v']); // 'v' will be correctly confused, and v can be retained. 830 ``` 831 8322. In the case of indirect exports, for example, **export MyClass** and **let a = MyClass; export {a}**, if you do not want to obfuscate property names, use [retention options](#retention-options) to retain them. For property names of directly exported classes or objects, such as **name** and **age** in the following example, if you do not want to obfuscate them, use [retention options](#retention-options) to retain them. 833 834 ``` 835 export class MyClass { 836 person = {name: "123", age: 100}; 837 } 838 ``` 839 8403. If you want to use an API (for example, **foo** in the example) of the .so library in the ArkTS/TS/JS file, manually retain the API name. 841 842 ``` 843 import testNapi from 'library.so' 844 testNapi.foo() // foo should be retained Example: -keep-property-name foo 845 ``` 846 8474. Fields used in JSON parsing and object serialization should be retained. 848 849 ``` 850 // Example JSON file structure (test.json): 851 /* 852 { 853 "jsonProperty": "value", 854 "otherProperty": "value2" 855 } 856 */ 857 858 const jsonData = fs.readFileSync('./test.json', 'utf8'); 859 let jsonObj = JSON.parse(jsonData); 860 let jsonProp = jsonObj.jsonProperty; // jsonProperty should be retained. 861 862 class jsonTest { 863 prop1: string = ''; 864 prop2: number = 0 865 } 866 867 let obj = new jsonTest(); 868 const jsonStr = JSON.stringify(obj); // prop1 and prop2 will be obfuscated and should be retained. 869 ``` 870 8715. Database-related fields should be manually retained. For example, properties in the database key-value pair type (ValuesBucket): 872 873 ``` 874 const valueBucket: ValuesBucket = { 875 'ID1': ID1, // ID1 should be retained. 876 'NAME1': name, // NAME1 should be retained. 877 'AGE1': age, // AGE1 should be retained. 878 'SALARY1': salary // SALARY1 should be retained. 879 } 880 ``` 881 8826. When custom decorators are used on member variables, member methods, or parameters in the source code, and the intermediate product of source code compilation is a JS file (for example, compiling release-mode source code HAR or source code containing @ts-ignore or @ts-nocheck), the names of these member variables or member methods should be retained. This is because the names of these member variables/methods are hardcoded as string literals during conversion from TS syntax to standard JS syntax. 883 884 Example: 885 886 ``` 887 class A { 888 // 1. Member variable decorator 889 @CustomDecoarter 890 propertyName: string = "" // propertyName should be retained. 891 // 2. Member method decorator 892 @MethodDecoarter 893 methodName1(){} // methodName1 should be retained. 894 // 3. Method parameter decorator 895 methodName2(@ParamDecorator param: string): void { // methodName2 should be retained. 896 } 897 } 898 ``` 899 900### -keep-global-name 901 902Retains the specified top-level scope names or imported/exported element names. [Name wildcards](#name-wildcards) are supported. You can perform the configuration as follows: 903 904``` 905-keep-global-name 906Person 907printPersonName 908``` 909 910Names exported from the namespace can also be retained using the **-keep-global-name** option. The following is an example: 911 912``` 913export namespace Ns { 914 export const age = 18; // -keep-global-name age: retains variable age. 915 export function myFunc () {}; // -keep-global-name myFunc: retains function myFunc. 916} 917``` 918 919> **NOTE** 920> 921> The trustlist specified by `-keep-global-name` applies globally. That is, if multiple top-level scope names or exported names exist in the code, they will not be confused as long as they match the names in the trustlist configured in **-keep-global-name**. 922 923**Which top-level scope names should be retained?** 924 9251. In JS, variables in the top-level scope are properties of **globalThis**. If **globalThis** is used to access a global variable in the code, the variable name should be retained. 926 927 Example: 928 929 ``` 930 var a = 0; 931 console.info(globalThis.a); // a should be retained. 932 933 function foo(){} 934 globalThis.foo(); // foo should be retained. 935 936 var c = 0; 937 console.info(c); // c can be correctly obfuscated. 938 939 function bar(){} 940 bar(); // bar can be correctly obfuscated. 941 942 class MyClass {} 943 let d = new MyClass(); // MyClass can be correctly obfuscated. 944 ``` 945 9462. When importing API names from .so libraries using named imports, if both **-enable-toplevel-obfuscation** and **-enable-export-obfuscation** are configured, the API names should be manually retained. 947 948 ``` 949 import { testNapi, testNapi1 as myNapi } from 'library.so' // testNapi and testNapi1 should be retained. 950 ``` 951 952### -keep-file-name 953 954Retains the file/folder names. You do not need to specify the file name extension. [Name wildcards](#name-wildcards) are supported. Example: 955 956``` 957-keep-file-name 958index 959entry 960``` 961 962**Which file names should be retained?** 963 9641. When **require** is used to import file paths, the path should be retained. This is because ArkTS does not support [CommonJS](../arkts-utils/module-principle.md#commonjs-module) syntax. 965 966 ``` 967 const module1 = require('./file1') // file1 should be retained. 968 ``` 969 9702. For dynamically imported paths, since it is impossible to determine whether the parameter in the **import** function is a path, the path should be retained. 971 972 ``` 973 const moduleName = './file2' // The path name file2 corresponding to moduleName should be retained. 974 const module2 = import(moduleName) 975 ``` 976 9773. When [dynamic routing](../ui/arkts-navigation-navigation.md#cross-package-dynamic-routing) is used for navigation, the path passed to the dynamic routing should be retained. Dynamic routing provides two modes: system routing table and custom routing table. If a custom routing table is used for redirection, the way to configure a trustlist is consistent with the second dynamic reference scenario. However, if the system routing table is used for redirection, the path corresponding to the **pageSourceFile** field in the **resources/base/profile/route_map.json** file of the module should be added to the trustlist. 978 979 ``` 980 { 981 "routerMap": [ 982 { 983 "name": "PageOne", 984 "pageSourceFile": "src/main/ets/pages/directory/PageOne.ets", // The path should be retained. 985 "buildFunction": "PageOneBuilder", 986 "data": { 987 "description" : "this is PageOne" 988 } 989 } 990 ] 991 } 992 ``` 993 994### -keep-comments 995 996Retains the classes, functions, namespaces, enums, structs, interfaces, modules, types, and JsDoc comments above properties in the declaration files generated after compilation. [Name wildcards](#name-wildcards) are supported. For example, to retain the JSDoc comments above the **Human** class in the declaration file, use the following configuration: 997 998``` 999-keep-comments 1000Human 1001``` 1002 1003**NOTE** 1004 1005**1.** This option takes effect when **-remove-comments** is used. 1006 1007**2.** If the classes, functions, namespaces, enums, structs, interfaces, modules, types, and property names in the declaration file generated after compilation are confused, the JsDoc comments above the element cannot be retained using **-keep-comments**. For example, when **exportClass** is configured in **-keep-comments**, if the class name is **exportClass** obfuscated, its JSDoc comments cannot be retained: 1008 1009``` 1010/* 1011 * @class exportClass 1012 */ 1013export class exportClass {} 1014``` 1015 1016### -keep-dts 1017 1018Adds names (such as variable names, class names, and property names) in the .d.ts file of the specified file path into the trustlist of **-keep-global-name** and **-keep-property-name**. Note that **filepath** supports only absolute paths and can be specified as a directory. In this case, the names in all .d.ts files in the directory are retained. 1019 1020### -keep 1021 1022Retains all names (such as variable names, class names, and property names) in the specified relative file path. **filepath** can be a file or directory. If it is a directory, the files in the directory and subdirectories are not obfuscated. 1023 1024**filepath** must be a relative path. **./** and **../** are relative to the directory where the obfuscation configuration file is located. [Path wildcards](#path-wildcards) are supported. 1025 1026``` 1027-keep 1028./src/main/ets/fileName.ts // Names in the fileName.ts file are not obfuscated. 1029../folder // Names in all the files under the folder directory and its subdirectories are not obfuscated. 1030../oh_modules/json5 // Names in all the files in the imported third-party library json5 are not obfuscated. 1031``` 1032 1033**How to retain remote HAR packages in modules?** 1034 1035**Method 1**: Specify the exact path of the remote HAR package in the module-level oh_modules. This path is a symbolic link to the real path in the project-level oh_modules. When configuring the path in the module-level oh_modules as a trustlist, you should specify the bundle name or a directory following the bundle name to correctly link to the real directory path. Therefore, configuring only the parent directory name of the HAR package is not supported. 1036 1037``` 1038// Positive example: 1039-keep 1040./oh_modules/harName1 // Names in all the files under the harName1 directory and its subdirectories are not obfuscated. 1041./oh_modules/harName1/src // Names in all the files under the src directory and its subdirectories are not obfuscated. 1042./oh_modules/folder/harName2 // Names in all the files under the harName2 directory and its subdirectories are not obfuscated. 1043 1044// Negative example: 1045-keep 1046./oh_modules // To retain the HAR package in the module-level oh_modules, configuring the parent directory name of the HAR package is not supported. 1047``` 1048 1049**Method 2**: Specify the exact path of the remote HAR package in the project-level oh_modules. The file paths in the project-level oh_modules are actual paths and can be directly configured. Since the file paths in the project-level oh_modules are all real paths, any path can be configured. 1050 1051``` 1052-keep 1053../oh_modules // Names in all the files under the project-level oh_modules and its subdirectories are not obfuscated. 1054../oh_modules/harName3 // Names in all the files under the harName3 directory and its subdirectories are not obfuscated. 1055``` 1056 1057The following figure shows the directory structure of module-level oh_modules and project-level oh_modules in DevEco Studio. 1058 1059 1060 1061**NOTE** 1062 1063**1.** For files retained by **-keep filepath**, all exported names and their properties in the dependency chain of these files are also retained. 1064 1065**2.** This option does not affect the capability provided by the **-enable-filename-obfuscation** option. 1066 1067### Wildcards Supported by Retention Options 1068 1069#### Name Wildcards 1070 1071The table below lists the name wildcards supported. 1072 1073| Wildcard| Description | Example | 1074| ------ | ---------------------- | ------------------------------------------ | 1075| ? | Matches any single character. | "AB?" matches "ABC", but not "AB". | 1076| \* | Matches any number of characters.| "\*AB\*" matches "AB", "aABb", "cAB", and "ABc".| 1077 1078**Use Example** 1079 1080Retain all property names that start with **a**. 1081 1082``` 1083-keep-property-name 1084a* 1085``` 1086 1087Retain all single-character property names. 1088 1089``` 1090-keep-property-name 1091? 1092``` 1093 1094Retain all property names. 1095 1096``` 1097-keep-property-name 1098* 1099``` 1100 1101#### Path Wildcards 1102 1103The table below lists the path wildcards supported. 1104 1105| Wildcard| Description | Example | 1106| ------ | ------------------------------------------------------------------------ | ------------------------------------------------- | 1107| ? | Matches any single character except the path separator (/). | "../a?" matches "../ab", but not "../a/". | 1108| \* | Matches any number of characters except the path separator (/). | "../a*/c" matches "../ab/c", but not "../ab/d/s/c".| 1109| \*\* | Matches any number of characters. | "../a**/c" matches "../ab/c" and "../ab/d/s/c". | 1110| ! | Negation. It can only be placed at the beginning of a path to exclude a certain case configured in the trustlist.| "!../a/b/c.ets" indicates all paths other than "../a/b/c.ets". | 1111 1112**Use Example** 1113 1114Retain the **c.ets** file in the **../a/b/** directory (excluding subdirectories). 1115 1116``` 1117-keep 1118../a/b/*/c.ets 1119``` 1120 1121Retain the **c.ets** file in the **../a/b/** directory and its subdirectories. 1122 1123``` 1124-keep 1125../a/b/**/c.ets 1126``` 1127 1128Retain all files except the **c.ets** file in the **../a/b/** directory. The exclamation mark (!) cannot be used alone. It can only be used to exclude existing cases in the trustlist. 1129 1130``` 1131-keep 1132../a/b/ 1133!../a/b/c.ets 1134``` 1135 1136Retain all the files in the **../a/** directory (excluding subdirectories). 1137 1138``` 1139-keep 1140../a/* 1141``` 1142 1143Retain all the files in the **../a/** directory and its subdirectories. 1144 1145``` 1146-keep 1147../a/** 1148``` 1149 1150Retain all the files in the module. 1151 1152``` 1153-keep 1154./** 1155``` 1156 1157**NOTE** 1158 1159**1.** In these options, the wildcards *, ?, and ! cannot be used for other meanings. 1160Example: 1161 1162``` 1163class A { 1164 '*'= 1 1165} 1166 1167-keep-property-name 1168* 1169``` 1170 1171In this example, * indicates any number of characters, and all property names are retained (not obfuscated). It does not mean that only the * property is retained. 1172 1173**2.** In the **-keep** option, only the path format / is allowed. The path format \ or \\ is not. 1174 1175## Obfuscation Rule Merging Strategies 1176 1177During module compilation, the effective obfuscation rules are the merged result of the current module's obfuscation rules and the dependent modules' obfuscation rules. The specific rules are as follows: 1178 1179**Obfuscation rules of the current module** 1180Content of the obfuscation configuration file specified by the **arkOptions.obfuscation.ruleOptions.files** field in the current module's configuration file **build-profile.json5**. 1181 1182**Obfuscation rules of dependent modules** 1183Depending on the type of dependent module, the obfuscation rules come from the following two sources: 1184 1185- **Local HAR/HSP modules** 1186 Content of the obfuscation configuration file specified by the **arkOptions.obfuscation.consumerFiles** field in the module's configuration file **build-profile.json5**. 1187 1188- **Remote HAR/HSP packages** 1189 Content of the **obfuscation.txt** file in the remote HAR/HSP package. 1190 1191If an HAP, HSP, or HAR is built, the final obfuscation rules are the merge of the following files: 1192* **ruleOptions.files** attribute of the current module 1193* **consumerFiles** attribute of the dependent local HSP 1194* **consumerFiles** attribute of the dependent local HAR 1195* **obfuscation.txt** files in the dependent remote HAR and remote HSP 1196 1197If an HAR is built, the **obfuscation.txt** file in the generated remote HAR is the merge of the following files: 1198* Its own **consumerFiles** attribute 1199* **consumerFiles** attribute of the dependent local HSP 1200* **consumerFiles** attribute of the dependent local HAR 1201* **obfuscation.txt** files in the dependent remote HAR and remote HSP 1202 1203If an HSP is built, the **obfuscation.txt** file in the generated remote HSP only contains its own **consumerFiles** attribute. 1204If a HAP is built, no **obfuscation.txt** will be generated. 1205 1206#### Obfuscation Rule Merging Logic 1207 1208Obfuscation options: The OR operation is used for merging. If a switch option exists in any of the rule files being merged, it will be included in the final merged result. 1209Retention options: When merging, for trustlist options, their content is the union of all. 1210 1211- If the current module's obfuscation configuration does not include the **-enable-lib-obfuscation-options** option, the merged result is the current module's obfuscation rules and the [retention options](#retention-options) in the dependent modules' obfuscation rules. 1212 1213- If the current module's obfuscation configuration includes the **-enable-lib-obfuscation-options** option, the merged result is the current module's obfuscation rules and the dependent modules' obfuscation rules. 1214 1215When the obfuscation configuration file specified by **consumerFiles** contains the following obfuscation rules, these rules will be merged into the **obfuscation.txt** file of a remote HAR or remote HSP, whereas other obfuscation rules will not. 1216``` 1217// Obfuscation options 1218-enable-property-obfuscation 1219-enable-string-property-obfuscation 1220-enable-toplevel-obfuscation 1221-compact 1222-remove-log 1223 1224// Retention options 1225-keep-property-name 1226-keep-global-name 1227``` 1228 1229**Precautions for Obfuscation in HSP and HAR** 1230 12311. If the obfuscation configuration file specified by **consumerFiles** contains the above obfuscation options, when other modules depend on this HAR, these obfuscation options will be merged with the main module's obfuscation rules, thereby affecting the main module. Therefore, you are not advised to configure obfuscation options in the **consumer-rules.txt** file. Instead, configure only retention options in the file. 1232 12332. If the **-keep-dts** option is added to the obfuscation configuration file specified by **consumerFiles**, it will be converted into **-keep-global-name** and **-keep-property-name**. 1234 1235## Mappings Between Obfuscation Options and Minimum SDK Versions 1236 1237| Obfuscation Option| Description | Minimum SDK Version| 1238| ------- | --------- | ------ | 1239| -disable-obfuscation | Disables obfuscation.| 4.0.9.2 | 1240| -enable-property-obfuscation | Enables property name obfuscation.| 4.0.9.2 | 1241| -enable-string-property-obfuscation | Enables obfuscation for string literal property names.| 4.0.9.2 | 1242| -enable-toplevel-obfuscation | Enables top-level scope name obfuscation.| 4.0.9.2 | 1243| -enable-filename-obfuscation | Enables file or folder name obfuscation for the HAR.<br> Enables file or folder name obfuscation for the HAP/HSP.| 4.1.5.3 <br> 5.0.0.19 | 1244| -enable-export-obfuscation | Enables obfuscation for imported/exported names.| 4.1.5.3 | 1245| -compact | Removes unnecessary spaces and all line feeds.| 4.0.9.2 | 1246| -remove-log | Removes the expressions involving direct calls to the console. statement in specific scenarios.| 4.0.9.2 | 1247| -print-namecache | Saves the name cache to the specified file path.| 4.0.9.2 | 1248| -apply-namecache | Reuses the specified name cache file.| 4.0.9.2 | 1249| -remove-comments | Removes all comments in the file.| 4.1.5.3 | 1250| -keep-property-name | Retains property names.| 4.0.9.2 | 1251| -keep-global-name | Retains top-level scope names.| 4.0.9.2 | 1252| -keep-file-name | Retains file or folder names in the HAR.<br> Retains file or folder names in the HAP/HSP.| 4.1.5.3 <br> 5.0.0.19 | 1253| -keep-dts | Retains the names in the .d.ts file in the specified path.| 4.0.9.2 | 1254| -keep-comments | Retains the classes, functions, namespaces, enums, structs, interfaces, modules, types, and JsDoc comments above properties in the declaration file generated after compilation.| 4.1.5.3 | 1255| -keep | Retains all names in the specified path.| 5.0.0.18 | 1256| Wildcard | The retention options of the name classes and path classes support wildcards.| 5.0.0.24 | 1257| -use-keep-in-source | Marks trustlists in source code by comments.| 5.1.0.57 | 1258