1# Common Issues with ArkGuard Bytecode Obfuscation 2 3## Differences Between Bytecode Obfuscation and Source Code Obfuscation 4 5### Differences in Obfuscation Scope 6 7**JSON Files** 8 9When the **-enable-filename-obfuscation** option is enabled in bytecode obfuscation, JSON file names are obfuscated. 10 11### Differences in Obfuscation Options 12 131. Bytecode obfuscation is disabled by default. After [enabling obfuscation](bytecode-obfuscation-guide.md#how-to-use), you need to additionally configure **-enable-bytecode-obfuscation** and **-enable-bytecode-obfuscation-debugging** in the **obfuscation-rules.txt** file in the module directory. 142. Bytecode obfuscation does not support the **-remove-comments** option. 15 16### Differences in File Structure After Obfuscation 17 18#### Directory Differences 19 20 21 22  23 24After bytecode obfuscation, the **obf** and **origin** folders and the **config.json** file are added to the **obfuscation** directory. For details, see [Viewing Obfuscation Effects](bytecode-obfuscation-guide.md#viewing-obfuscation-effects). 25 26#### File Content Differences 27 28**nameCache.json** file: 29 30After source code obfuscation: 31 32```txt 33{ 34 "entry/src/main/ets/entryability/EntryAbility.ets": { 35 "IdentifierCache": { 36 "#UIAbility": "UIAbility", 37 ...... 38 "#testObject": "i", 39 "#EntryAbility": "j" 40 }, 41 "MemberMethodCache": { 42 .... 43 }, 44 "obfName": "entry/src/main/ets/entryability/EntryAbility.ets" 45 }, 46 ...... 47 }, 48 "compileSdkVersion": "5.0.0.70", 49 "entryPackageInfo": "entry|1.0.0", 50 "PropertyCache": { 51 ...... 52 }, 53 "FileNameCache": { 54 ...... 55 } 56} 57``` 58 59After bytecode obfuscation: 60 61```json 62{ 63 "entry/src/main/ets/entryability/EntryAbility.ets": { 64 "IdentifierCache": { 65 "#EntryAbility": "a", 66 "#testObject": "c" 67 }, 68 "MemberMethodCache": { 69 "EntryAbility:0:0": "a", 70 ...... 71 }, 72 "obfName": "entry/src/main/ets/entryability/EntryAbility.ets", 73 "OriSourceFile": "entry|entry|1.0.0|src/main/ets/entryability/EntryAbility.ts", 74 "ObfSourceFile": "entry|entry|1.0.0|src/main/ets/entryability/EntryAbility.ts" 75 }, 76 ...... 77 "entryPackageInfo": "entry|1.0.0", 78 "compileSdkVersion": "5.0.0.70", 79 "PropertyCache": { 80 ...... 81 }, 82 "FileNameCache": { 83 ...... 84 } 85} 86``` 87 881. Difference in bytecode obfuscation in **IdentifierCache**: 89 1. Function parameter names are not obfuscated. 90 2. There are no obfuscation name mappings for anonymous functions. 912. When the -enable-filename-obfuscation option is enabled, the **OriSourceFile** (source file path before obfuscation) and **ObfSourceFile** (source file path after obfuscation) fields are generated for bytecode obfuscation, but not for source code obfuscation. 92 93### Precautions for Switching 94 95#### Differences in UI Obfuscation 96 97Bytecode obfuscation does not provide UI obfuscation. 98 99Since UI components in bytecode have many string bindings for properties, methods, classes, and variables, bytecode obfuscation uses a system trustlist scanning mechanism to ensure normal functionality. 100 101#### Binding Properties with Strings as Function Parameters 102 103Source code: 104 105```ts 106@Component 107export struct MainPage { 108 @State messageStr: string = 'Hello World'; 109 ... 110} 111``` 112 113Intermediate file: 114 115```abc 116this.__messageStr = new ObservedPropertySimplePU('Hello World', this, "messageStr"); 117``` 118 119During the intermediate file conversion process, **message** is bound as a literal; however, if **messageStr** is obfuscated but the string parameter of this method is not, it can cause UI failure. 120 121**Solution**: Collect all members in the struct and add them to the trustlist to prevent obfuscation. Currently, since bytecode obfuscation does not provide UI obfuscation, the system automatically identifies and adds them to the trustlist, eliminating the need for your configuration. 122 123#### Binding Properties in Bytecode with Strings 124 125Source code: 126 127```ts 128class Info { 129 @Trace sample: Sample = new Sample(); 130} 131``` 132 133Bytecode file: 134 135```abc 136tryldglobalbyname 0x136, Trace 137sta v2 138lda v0 139ldobjbyname 0x137, prototype 140sta v3 141lda.str sample 142sta v4 143lda v2 144callargs2 0x2c, v3, v4 145lda v0 146ldobjbyname 0x139, prototype 147sta v2 148lda.str sample 149sta v3 150lda v1 151callargs2 0x2e, v2, v3 152``` 153 154The bytecode contains a global **Trace** object that links properties using the string **sample**. 155 156**Solution**: During bytecode obfuscation, the system scans for decorators and automatically add any parameters decorated with @Trace to the trustlist. Therefore, you do not need to set this up manually. 157 158## Troubleshooting Functional Issues 159 160**Procedure** 161 1621. Configure the **-disable-obfuscation** option in the **obfuscation-rules.txt** file to disable obfuscation, and check whether the issue is caused by obfuscation. 163 1642. If the issue is related to obfuscation, review the documentation to understand the capabilities of [obfuscation rules](bytecode-obfuscation.md#obfuscation-options) and understand when to [configure trustlists](bytecode-obfuscation.md#summary-of-existing-retention-options) to avoid issues. 165 1663. If your issue matches any cases listed below, apply the suggested solutions. 167 1684. If the issue is not covered, use a positive approach to identify the problem (remove specific configuration items if the corresponding functionality is not needed). 169 1705. Analyze runtime crashes as follows: 171 172 a. Open the application runtime logs or the **Crash** dialog box in DevEco Studio to find the crash stack. 173 174 b. The line number in the crash stack is the line number of the build product, and the method name may also be the obfuscated name. Therefore, you are advised to check the build product based on the crash stack, analyze the names that cannot be obfuscated, and add them to the trustlist. 175 1766. Analyze functional exceptions (for example, white screens) as follows: 177 178 a. Opening the application runtime logs: Select HiLog and search for logs directly related to the exceptions. 179 180 b. Locating the problematic code segment: Identify the specific code block causing the exceptions through log analysis. 181 182 c. Enhancing log output: Add log records for data fields in the suspected code segment. 183 184 d. Analyzing and identifying critical fields: Determine if the data exception is caused by obfuscation through the enhanced log output. 185 186 e. Configuring a trustlist for critical fields: Add fields that directly affect application functionality after obfuscation to the trustlist. 187 188## Handling Common Configuration Issues 189 190### No .pa File Generated When enable-bytecode-obfuscation-debugging Is Configured 191 192Ensure that **Build Mode** is set to **release**. Check that **"compatibleSdkVersionStage": "beta3"** is configured in the **build-profile.json5** file in the root directory. Then enable bytecode obfuscation in the **obfuscation-rules.txt** file of each module. 193 194### Viewing Obfuscation Effects 195 196After obfuscation is complete, intermediate products are generated. You can find the obfuscated intermediate products in the **build** directory of the compilation output, as well as the name mapping file and system API trustlist files. 197 198Obfuscated file directory: build/default/[...]/release/obfuscation/obf 199 200Directory of the name mapping file and system API trustlist file: build/default/[...]/release/obfuscation 201 202 203 204· The name mapping file, named **nameCache.json**, records the mappings between source code names and names after obfuscation. 205· The system API trustlist file, named **systemApiCache.json**, records the APIs and property names that will be kept. 206 207 208## Handling Compilation Errors 209 210### Case 1: The error message "ERROR: [Class]get different name for method." is displayed. 211 212**Symptom**: @CustomDialog is used to customize a dialog box, and another dialog box is displayed inside. After bytecode obfuscation is enabled, the build fails, and the following error information is displayed: 213 214Error message: ArkTSCompilerError: ArkTS:ERROR Failed to execute ByteCode Obfuscate. 215Error message: [Class]get different name for method:&entry/src/main/ets/pages/XXXX&.#~@0>#setController^1. 216 217```ts 218// Code 1 219@CustomDialog 220export default struct TmsDialog { 221 controller?: CustomDialogController 222 dialogController:CustomDialogController; 223} 224// Code 2 225@CustomDialog 226struct Index{ 227 controller?: CustomDialogController 228 dialogController?:CustomDialogController 229} 230``` 231 232**Possible Causes** 233 234In this example, when a custom dialog box pops up another dialog box, or when two **CustomDialogController** objects are defined in a UI, the ETS code is converted to TS, resulting in two identical **setController** functions, causing the bytecode obfuscation to fail. 235 236**Solution** 237 238```ts 239dialogController:CustomDialogController|null = null; 240``` 241 242In code 1, the dialogController cannot be properly displayed up at runtime. You only need to change the code to the code in the solution. The dialogController will be displayed normally, and the bytecode obfuscation feature will work as expected. 243 244In code 2, since only CustomDialogController is used, the @CustomDialog is not needed and can be directly removed. After removal, the function works normally, and the bytecode obfuscation feature works as expected. 245 246## Handling Runtime Exceptions 247 248### Errors That May Occur When -enable-property-obfuscation Is Configured 249 250#### Case 1: The error message "Cannot read property 'xxx' of undefined" is reported. 251 252```ts 253// Before obfuscation: 254const jsonData = ('./1.json') 255let jsonStr = JSON.parse(jsonData) 256let jsonObj = jsonStr.jsonProperty 257// After obfuscation: 258const jsonData = ('./1.json') 259let jsonStr = JSON.parse(jsonData) 260let jsonObj = jsonStr.i 261``` 262 263After property name obfuscation is enabled, **jsonProperty** is obfuscated as a random character **i**. However, the original name is used in the JSON file, causing the error. 264 265**Solution**: Use the **-keep-property-name** option to add the fields used in JSON files to the trustlist. 266 267#### Case 2: An error message is reported when database-related fields are used and property obfuscation is enabled. 268 269The error message is "table Account has no column named a23 in 'INSET INTO Account(a23)'." 270 271The SQL statement uses database field names that are obfuscated, whereas the database expects the original names. 272 273**Solution**: Use the **-keep-property-name** option to add the database fields to the trustlist. 274 275#### Case 3: Properties are obfuscated when Record<string, Object> is used as an object type. 276 277**Symptom** 278 279When **Record<string, Object>** is used as an object type, properties like **linkSource** are obfuscated, causing the error. Example: 280 281```ts 282// Before obfuscation: 283import { Want } from '@kit.AbilityKit'; 284let petalMapWant: Want = { 285 bundleName: 'com.example.myapplication', 286 uri: 'maps://', 287 parameters: { 288 linkSource: 'com.other.app' 289 } 290} 291// After obfuscation: 292import type Want from "@ohos:app.ability.Want"; 293let petalMapWant: Want = { 294 bundleName: 'com.example.myapplication', 295 uri: 'maps://', 296 parameters: { 297 i: 'com.other.app' 298 } 299}; 300``` 301 302**Possible Causes** 303 304In this example, the object's properties need to be passed to the system to load a specific page, so the property names should not be obfuscated. The type **Record<string, Object>** is a generic definition for an object with string keys and does not describe the internal structure or property types in detail. Therefore, the obfuscation tool cannot identify which properties should not be obfuscated, leading to the obfuscation of internal property names like **linkSource**. 305 306**Solution** 307 308Add the problematic property names to the property trustlist. The following is an example: 309 310```txt 311-keep-property-name 312linkSource 313``` 314 315#### Case 4: Properties of decorators marked with @Type and @Trace do not work properly after obfuscation. 316 317**Symptom** 318 319The properties of decorators marked with @Type and @Trace can be obfuscated properly, but the functionality becomes abnormal. 320 321```ts 322@ObservedV2 323class SampleChild { 324 @Trace p123: number = 0; 325 p2: number = 10; 326} 327@ObservedV2 328export class Sample { 329 // For complex objects, use the @Type decorator to ensure successful serialization. 330 @Type(SampleChild) 331 @Trace f123: SampleChild = new SampleChild(); 332} 333 334// Call the API. 335this.prop = PersistenceV2.connect(Sample, () => new Sample())!; 336Text.create(`Page1 add 1 to prop.p1: ${this.prop.f123.p123}`); 337``` 338 339After obfuscation, **p123** and **f123** are correctly replaced, but when processing the **Trace** and **Type** decorator properties, **p123** and **f123** are identified as strings and not obfuscated, leading to failed calls. 340 341**Possible Causes** 342 343Decorator-marked property names should be retained, and properties decorated with the combination of @Type and @Trace decorators should also be retained. 344 345**Solution** 346 347Use the **-keep-property-name** option to add properties within types that are not directly exported to the trustlist. Example: 348 349```txt 350-keep-property-name 351f123 352p123 353``` 354 355#### Case 5: Problems that may occur when **both -enable-property-obfuscation** and **-keep** are enabled. 356 357**Symptom** 358 359The following obfuscation configuration is used: 360 361```txt 362-enable-property-obfuscation 363-keep 364./file1.ts 365``` 366 367**file2.ts** imports an interface from **file1.ts**, and the interface contains object-type properties. As a result, these properties are retained in **file1.ts** but obfuscated in **file2.ts**, leading to function exceptions. Example: 368 369```ts 370// Before obfuscation: 371// file1.ts 372export interface MyInfo { 373 age: number; 374 address: { 375 city1: string; 376 } 377} 378// file2.ts 379import { MyInfo } from './file1'; 380const person: MyInfo = { 381 age: 20, 382 address: { 383 city1: "shanghai" 384 } 385} 386// After obfuscation, the code of file1.ts is retained. 387// file2.ts 388import { MyInfo } from './file1'; 389const person: MyInfo = { 390 age: 20, 391 address: { 392 i: "shanghai" 393 } 394} 395``` 396 397**Possible Causes** 398 399-The **-keep** option retains the code in the **file1.ts** file, but properties within exported types (for example, **address**) are not automatically added to the property trustlist. Therefore, these properties are obfuscated when being used in other files. 400 401**Solution** 402 403Solution 1: Define the property type using **interface** and export it. This will automatically add the property to the trustlist. Example: 404 405```ts 406// file1.ts 407export interface AddressType { 408 city1: string 409} 410export interface MyInfo { 411 age: number; 412 address: AddressType; 413} 414``` 415 416Solution 2: Use the **-keep-property-name** option to add properties within types that are not directly exported to the trustlist. Example: 417 418```ts 419-keep-property-name 420city1 421``` 422 423#### Errors That May Occur When -enable-export-obfuscation and -enable-toplevel-obfuscation Are Configured 424 425When the two options are configured, method name confusion in the following scenarios is involved when the main module calls the methods of other modules: 426|Main Module|Dependent Module|Imported/Exported Name Obfuscation| 427|-------|--------|---------| 428|HAP/HSP| HSP |The HSP and main module are built independently, and different names are generated after obfuscation. Therefore, a trustlist must be configured for both the HSP and main module.| 429|HAP/HSP| Local HAR|The local HAR is built together with the main module. After obfuscation, the names are the same.| 430|HAP/HSP| Third-party library| The names and properties exported from a third-party library are collected to the trustlist. They are not confused during import and export.| 431 432For the HSP, you must add the methods used by other modules to the trustlist. You must add the same trustlist for the main module. Therefore, you are advised to add the obfuscation file configured with the trustlist (for example, **hsp-white-list.txt**) to the obfuscation configuration item of the module that depends on the obfuscation file, that is, the **files** field shown in the following figure. 433 434 435 436##### Case 1: When a class is dynamically imported, the class definition is confused, but the class name is not, causing an error. 437 438```ts 439// Before obfuscation: 440export class Test1 {} 441let mytest = (await import('./file')).Test1 442// After obfuscation: 443export class w1 {} 444let mytest = (await import('./file')).Test1 445``` 446 447The exported class **Test1** is a top-level domain name. When being dynamically used, it is a property. Because the **-enable-property-obfuscation** option is not configured, the class name is confused, but the property name is not. 448 449**Solution** 450 451Use **-keep-global-name** to add **Test1** to the trustlist. 452 453##### Case 2: For a method in a namespace, the method definition is confused, but the statement that uses the method is not, causing an error. 454 455```ts 456// Before obfuscation: 457export namespace ns1 { 458 export class person1 {} 459} 460import {ns1} from './file1' 461let person1 = new ns1.person1() 462// After obfuscation: 463export namespace a3 { 464 export class b2 {} 465} 466import {a3} from './file1' 467let person1 = new a3.person1() 468``` 469 470**person1** in the namespace is an exported element. When being called through **ns1.person1**, it is a property. Because the **-enable-property-obfuscation** option is not configured, the property name is not obfuscated during the call. 471 472**Solution** 473 4741. Configure the **-enable-property-obfuscation** option. 4752. Use the **-keep-global-name** option to add the methods exported from the namespace to the trustlist. 476 477#### Case 3: When declare global is used, a syntax error is reported after obfuscation. 478 479```ts 480// Before obfuscation: 481declare global { 482 var age : string 483} 484// After obfuscation: 485declare a2 { 486 var b2 : string 487} 488``` 489 490The error message "SyntaxError: Unexpected token" is reported. 491 492**Solution** 493 494Use **-keep-global-name** to add **global** to the trustlist. 495 496#### Case 4: When Reflect.defineMetadata() is displayed, a message is displayed indicating that the function cannot be found after obfuscation. 497 498**Symptom** 499 500When **-enable-toplevel-obfuscation** is configured, bytecode obfuscation works normally, but a runtime error is reported. The error log is as follows: 501 502```txt 503Error message:is not callable 504Stacktrace: Cannot get SourceMap info, dump raw stack: at anonymous (ads_service|@hw-ads/ohos-ads-model|1.0.1|src/main/ets/annotations/FieldType.ts:6:1. 505``` 506 507```js 508Implemented in Reflect 509function defineMetadata(metadataKey, metadataValue, target, propertyKey) { 510 if (!IsObject(target)) 511 throw new TypeError(); 512 if (!IsUndefined(propertyKey)) 513 propertyKey = ToPropertyKey(propertyKey); 514 return OrdinaryDefineOwnMetadata(metadataKey, metadataValue, target, propertyKey); 515} 516exporter("defineMetadata", defineMetadata); 517 518Call the code. 519Reflect.defineMetadata(FIELD_TYPE_KEY, types, target, key); 520 521After obfuscation: 522In Reflect 523function w9(metadataKey, metadataValue, target, propertyKey) { 524} 525``` 526 527**Possible cause** 528 529When **-enable-toplevel-obfuscation** is configured, the function name in the Reflect file is obfuscated, but the string "defineMetadata" in the exporter function is not obfuscated. As a result, when the **Reflect.defineMetadata** is used externally, the corresponding function cannot be found. 530 531**Solution** 532 533Use **-keep-global-name** to add **defineMetadata** to the trustlist. Since the Reflect file uses exporter multiple times, you are advised to use the **-keep** option directly. 534 535```txt 536-keep 537../xxx/xxx/xxx/Reflect.ts // Use the relative path of the file. 538``` 539 540### The **-enable-string-property-obfuscation** option is not configured, but the string literal property name is obfuscated. As a result, the value of the string literal property name is undefined. 541 542```ts 543person["personAge"] = 22; // Before obfuscation 544 545person["b"] = 22; // After obfuscation 546``` 547 548**Solution** 549 5501. Check whether **-enable-string-property-obfuscation** is configured for the dependent HAR. If it is configured, the main project will be affected, and you should disable it. 5512. If it must be configured, add the property name to the trustlist. 5523. If it is not configured and the SDK version is earlier than 4.1.5.3, update the SDK. 553 554### Errors That May Occur When -enable-filename-obfuscation Is Configured 555 556#### Case 1: The error message "Error Failed to get a resolved OhmUrl for 'D:code/MyApplication/f12/library1/pages/d.ets' imported by 'undefined'" is reported. 557 558As shown below, the outer layer of the **library1** module contains a directory named **directory**. When file name obfuscation is enabled, **directory** is obfuscated as **f12**, causing the error indicating that the path is not found. 559 560 561 562**Solution** 563 5641. If the project directory structure and error message are similar, update the SDK to 5.0.0.26 or later. 5652. Use the **-keep-file-name** option to add the directory name **directory** of the module to the trustlist. 566 567#### Case 2: The error message "Cannot find module 'ets/appability/AppAbility' which is application Entry Point" is reported. 568 569The system loads the ability file when the application is running. Therefore, you must manually configure the trustlist to prevent the specified file from being obfuscated. 570 571**Solution**: Use the **-keep-file-name** option to add the path corresponding to the **srcEntry** field in the **src/main/module.json5** file to the trustlist. 572 573```txt 574-keep-file-name 575appability 576AppAbility 577``` 578 579The HAP and HSP depend on the same local source code HAR module. 580 581* If file name obfuscation is enabled, the following issue may occur: 582 583 Singleton function exceptions: The reason is that the HAP and HSP modules execute independent build and obfuscation processes. The same file names in the shared local source code HAR may be obfuscated differently in the HAP and HSP packages. 584 585 Interface call failures: The reason is that the HAP and HSP modules execute independent build and obfuscation processes. Different file names in the shared local source code HAR may be obfuscated to the same name in the HAP and HSP packages. 586 587* If **-enable-export-obfuscation** and **-enable-toplevel-obfuscation** are configured, the interface loading failures may occur at runtime. 588 589 The HAP and HSP modules execute independent build and obfuscation processes, resulting in different obfuscated names for the interfaces exposed by the shared local source code HAR. 590 591**Solution** 592 5931. Convert the local source code HAR that both the HAP and HSP depend on into a bytecode HAR. In this way, this HAR will not be obfuscated again when it is depended on. 5942. Build and package the local source code HAR that is depended by both the HAP and HSP in release mode. In this way, when this HAR is depended on, its filenames and exposed interfaces will not be obfuscated. 595