• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![bytecode-compilation-code-build](figures/bytecode-compilation-code-build.png)
21
22 ![bytecode-compilation-build](figures/bytecode-compilation-build.png)
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![bytecode-build-product](figures/bytecode-build-product.png)
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![bytecode-buildoptionset](figures/bytecode-buildoptionset.png)
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![bytecode-directory](figures/bytecode-directory.png)
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