# 如何排查代码混淆导致功能异常问题以及常见报错案例

#### 问题现象

本地调试debug包安装正常，但是使用release模式打包报错或使用release包安装测试有问题，具体表现包括但不限于以下几种场景：

*   问题1：release模式下，开启代码混淆导致接口请求数据异常。
    *   The obfuscation file declared in configuration does not exist。
    *   TypeError: Cannot read properties of undefined (reading 'OBFUSCATION\_INITIALIZATION')。
    *   Record<K,T>修饰的数据类型，打点访问属性结果为undefined，通过动态属性取值结果正常。
    *   json转对象后再取字段值的时候，debug是正常的，release变成undefined。
    *   APP打开时闪退：Generated by HiviewDFX@OpenHarmony\_\_\_#15 pc 00000000004b6f74 /system/lib64/platformsdk/libark\_jsruntime.so(1eb5ac6fbd5fa210e5a78c30cc151a54)。
    *   APP打开后界面空白。
*   问题2：release模式下，开启代码混淆导致路由跳转异常：TypeError:Cannot read property route of undefined。
*   问题3：代码中配置了-remove-log规则以后，理论上编译后日志会被阻断无法读取，但发现设备上仍在正常打印日志。
*   问题4：开启混淆后，目录中无混淆规则配置文件：The obfuscation file declared in configuration does not exist。
*   问题5：使用"use shared"修饰的类，在编译成HAR后引用，运行时报错：Error message:Cannot add property in prevent extensions。
*   问题6：HAR包A依赖HAR包B，release模式下，开启代码混淆后报错：the requested module @B does not provide an export name 'u11' which imported by @A
*   问题7：开启混淆编译过程中报错：INTERNAL ERROR: Failed to obfuscate file xxx/xxx/Index.ets with arkguard. Error: app license invalid COMPILE RESULT:FAIL。
*   问题8：运行APP后报错：Error name:ReferenceError Error message:cannot find record '&basic/src/main/ets/xxx/xxxx&', please check the request path.'/data/storage/el1/xxx。
*   问题9：应用开启混淆后，@hzw/zrouter三方库进行页面路由失败，报错：ZRouter -> error: 100005 Builder function not registered。
*   问题10：没有主动配置混淆参数名，但是输出har包的d.ts文件接口参数名会被混淆，如何避免这种混淆？

#### 背景知识

*   混淆规则分为两种类型，一种是混淆选项（通常以-enable开头），一种是保留选项（通常以-keep开头）；前者是提供顶层作用域名称、属性名称、文件名称等多种混淆功能配置开关，后者是提供各种混淆功能的白名单配置能力。
*   混淆规则配置文件obfuscation-rules.txt默认开启了四项推荐的混淆选项：-enable-property-obfuscation、-enable-toplevel-obfuscation、-enable-filename-obfuscation和-enable-export-obfuscation，开发者可以根据需要进一步修改混淆配置。需要注意的是，开启这四项规则可能会导致应用在运行时崩溃，因此建议开发者参考开启指导来修正应用功能。
*   不同包类型的源码混淆建议：由于不同包类型的用途及构建流程的差异，不同包类型使用混淆有不同的注意事项。参考：HAP包混淆建议、HSP包源码混淆。

#### 问题定位

排查功能异常步骤：

1.  基于以下方式快速确定是否为混淆引起的异常：
    *   如果是以debug模式进行编译推包，说明该运行时异常不是由混淆引起的；
    *   如果是以release模式进行编译推包，可以在推包模块的build-profile.json5中，将enable设置为false则关闭混淆，执行clean，再次编译推包，如果运行时没问题，可以确定该异常是由混淆引起。
2.  若确认是开启混淆后功能出现异常：
    *   混淆报错位置，通过混淆常见问题和报错栈还原进行排查具体报错位置。
    *   将报错位置配置白名单，配置白名单的主要场景为网络数据访问、json字段访问、动态属性访问、调用so库接口等不能混淆场景，需要使用-keep-property-name来保留指定的属性名称，可按照官方文档排查功能异常步骤来进行排查。
    *   根据ArkGuard混淆原理及功能修改混淆文件中配置，当存在多个混淆规则文件时，规则合并以及合并后的作用范围可参考混淆规则合并策略。
    *   若上述未排查出问题，怀疑文件损坏。排查如下路径内arkguard相关文件是否被更改：DevEco Studio > SDK > default > OpenHarmony > ets > build-tools > ets-loader > node\_modules。

#### 分析结论

*   问题1：网络接口数据访问需配置白名单，请求接口的入参名以及接口返回的数据的属性名需要使用-keep-property-name来保留指定的属性名称。
*   问题2：在使用动态路由进行路由跳转时，传递给动态路由的路径应该被保留。若采用系统路由表进行跳转，则需要将模块下resources/base/profile/route\_map.json文件中pageSourceFile字段对应的路径添加到白名单中。需要使用-keep-file-name来保留这些文件路径。
*   问题3：排查后，虽配置混淆规则-remove-log，但未开启源码混淆，导致混淆规则未生效，所以能正常打印日志。
*   问题4：未在对应路径下创建obfuscation-rules.txt文件，并配置混淆规则。
*   问题5：HAR包主要分为开源HAR、闭源HAR，闭源HAR里面确实会把ts文件转换成js，debug模式没问题，是因为直接源码打包了，这时候HAR中的ets源码直接参与hap的编译。但是release模式会涉及①代码转换+②文件格式变化+③混淆，这时候就①②就导致报错。
*   问题6：HAR包会影响使用它的主模块的混淆流程，无论HAR包是否开启混淆，都需配置consumer-rules.txt，以确保主模块在开启混淆时，HAR包的功能保持正常。HAR包B未配置consumer-rules.txt，开启混淆后导致HAR包A引用HAR包B中方法时报错。
*   问题7：arkguard混淆能力相关文件被替换或更改，导致编译器无法正常使用能力。
*   问题8：引用文件为HSP包提供接口，但调用方使用相关接口时，未通过引用包名调用，而是通过相对路径，导致调用方引用相对路径配置被混淆，无法获取接口。
*   问题9：应用开启文件名混淆后，导致@hzw/zrouter三方库生成的路由文件route\_map.json中pageSourceFile字段指向的ets文件名被混淆，导致找不到目标页面。
*   问题10：只要开启混淆开关，就会默认混淆局部变量名和参数名。

#### 修改建议

*   问题1：网络接口数据请求异常需要在obfuscation-rules.txt使用-keep-property-name指定需要保留的属性名，如果保留属性太多，不想一个个的添加，可以使用-keep指定保留整个文件夹。
    
    代码示例如下：
    
    ```
    #-keep-property-name 保留属性名
    -keep-property-name
    age
    firstName
    lastName
    
    #保留属性太多，不想一个个的添加，可以使用 -keep  保留整个文件夹
    -keep
    src/main/ets/network
    ```
    
*   问题2：路由跳转异常问题需要在obfuscation-rules.txt使用-keep-file-name来保留resources/base/profile/route\_map.json文件中pageSourceFile字段对应的路由文件。
    
    代码示例如下：
    
    ```
    #-keep-file-name 保留文件路径
    -keep-file-name
    SuggestionPage
    WebContentPage
    ```
    
*   问题3：在本模块build-profile.json5配置文件中的arkOptions.obfuscation.ruleOptions字段中，通过enable字段配置true开启混淆。
    
    ```
    "arkOptions": {
      "obfuscation": {
        "ruleOptions": {
          "enable": true,
          "files": [
            "./obfuscation-rules.txt"
          ]
        }
      }
    },
    ```
    
*   问题4：在下方路径创建obfuscation-rules.txt文件，并在此配置混淆规则，配置混淆可以参考通过混淆助手配置保留选项。
    
*   问题5：在HAR模块下的module.json5文件中将"metadata"字段下的"name"设置为“UseTsHar”，修改产物为ts文件。
*   问题6：HAR包B参考ArkGuard混淆开启指南配置consumer-rules.txt。
*   问题7：重新下载DevEco Studio。
*   问题8：引用其他包体的接口，须使用包名的形式。

*   问题9：在每个模块的obfuscation-rules.txt文件添加混淆配置：
    
    ```
    -keep-file-name
    Index
    _generated
    ZR*
    ```
    
*   问题10：开启-keep-parameter-names混淆规则，保留声明文件中对外接口的参数名称。

#### 常见FAQ

Q：引入google-libphonenumber库导致crash怎么处理？

A：混淆会改变类名、方法名、变量名等，如果三方库依赖于某些特定的名字来工作，那么混淆后可能会导致这些依赖失效。关闭混淆，应用不再崩溃。

Q：打印日志如何设置阻断？

A：对于不同日志可使用以下方式：

*   针对console日志，在obfuscation-rules.txt中配置-remove-log规则，并且开启混淆实现日志阻断，参考：-remove-log。
*   针对hilog日志，开发者可以根据商用或者调试场景来调整日志级别，调整方式：调用setMinLogLevel接口并设置相应参数。参考：hilog.setMinLogLevel。

Q：如何简化混淆配置过程？

A：HarmonyOS应用开发过程中，避免对特定类或方法进行混淆，开发者需要手动配置白名单规则。为了简化这一配置过程，建议开发者优先借助IDE的混淆助手来自动化处理部分配置工作，参考链接如下：通过混淆助手配置保留选项。

Q：debug包如何混淆？编译出来的hap包怎么查看是否混淆成功？

A：debug包不支持混淆，debug包以便于调试。只有release模式才能混淆。

在混淆结束后会生成中间产物，因此可以在编译产物build目录中找到混淆后的中间产物以查看混淆效果，同时可以找到混淆生成的名称映射表及系统API白名单文件。

*   混淆后的文件目录：build/default/\[...\]/release/模块名。
*   混淆名称映射表及系统API白名单目录：build/default/\[...\]/release/obfuscation。
    *   名称映射表文件：nameCache.json，该文件记录了源码名称混淆的映射关系。
    *   系统API白名单文件：systemApiCache.json，该文件记录了SDK中的接口与属性名称，工程源码中与其重名的元素不会被混淆。
        

Q：在不同源文件中，同样的写法new Object({\[属性名\]: 123})，查看编译后对应的文件，有的文件中的属性名会被混淆，有的属性名不会被混淆，这是什么原因呢？

属性userOftenAppData被混淆效果如下：

属性isFromChat未被混淆效果如下：

A：

1.  首先在systemApiCache.json文件中排查未被混淆的属性是否与系统API重名，若与系统API重名，则不会被混淆。
2.  其次确认未被混淆的属性名在项目中是否存在字符串字面量属性名，只要有一个字符串字面量属性名，那么所有的同名属性都不会被混淆。

Q：在main\_pages.json文件里增加页面时会提示“A page configured in 'main\_pages.json or build-profile.json5' must have one and only one '@Entry' decorator. ”。

A：main\_pages.json文件中包含的页面都需要使用@Entry装饰器。对于未使用@Entry装饰器的页面，检查main\_pages.json和工程级build-profile.json5文件中是否配置对应页面信息，有的话需要删除。

Q：新增一个模块提交代码到仓库，新建文件夹重新克隆仓库代码，编译报错，如图：

A：请排查其他模块级和项目级的build-profile.json5中是否存在混淆配置项，若不存在，建议新增模块的build-profile.json5中也删除obfuscation节点。

Q：应用打包时，APP包与HAP包的区别？

A：一个HarmonyOS工程的构建产物为APP包，APP包用于应用/服务发布上架应用市场，APP里编译的HAP包一般会比正常编HAP包小，编译APP包默认是非debug的，APP包里的HAP包是混淆过的，不包含调试信息；HAP是应用/服务可以独立运行在设备中的形态，也是应用安装的基本单位，在DevEco Studio工程目录中，一个HAP对应一个Module。应用打包时，每个Module生成一个.hap文件，一般编译HAP是debug模式，不会开启混淆，便于安装与调试。

Q：多模块引入中，需要保留HAR包中的选项，是否只需要在入口模块的obfuscation-rules.txt中配置保留选项？

A：是。

Q：多模块引入中，需要保留HAR包中的文件或者文件夹，此时相对路径filepath应该怎么填写？

A：filepath可以是文件或文件夹，若是文件夹，则文件夹下的文件及子文件夹中文件都不混淆。具体方式如下：

*   方式一：指定远程HAR包在模块级oh\_modules中的具体路径（该路径为软链接路径，真实路径为工程级oh\_modules中的文件路径）。代码示例如下：
    
    ```
    -keep
    ./oh_modules/harName1         // harName1目录下所有文件及子文件夹中的名称都不混淆
    ./oh_modules/harName1/src     // src目录下所有文件及子文件夹中的名称都不混淆
    ./oh_modules/folder/harName2  // harName2目录下所有文件及子文件夹中的名称都不混淆
    ```
    

*   方式二：指定远程HAR包在工程级oh\_modules中的具体路径。代码示例如下：
    
    ```
    -keep
    ../oh_modules                  // 工程级oh_modules目录下所有文件及子文件夹中的名称都不混淆
    ../oh_modules/harName3          // harName3目录下所有文件及子文件夹中的名称都不混淆
    ```
    

Q：开启混淆模式下，如何定位错误代码的具体行数？

A：在Release模式下，经过代码混淆的堆栈信息无法定位到源码的具体文件和行位置，不易于快速解决问题。针对该场景，DevEco Studio提供了Release模式下堆栈解析功能，利用Release模式下堆栈中的bundle路径，通过映射规则转换为具体的源码路径，从而提升解决问题的效率。

Release模式下堆栈解析功能操作方法如下：

1.  单击菜单栏Code> Analyze Stack Trace。
2.  在弹出的Analyze Stack Trace对话框中，粘贴应用的异常堆栈信息，单击OK。
3.  DevEco Studio将解析后的堆栈信息显示在底部的Stacktrace页签中，点击路径链接可快速定位到源码具体位置。