# 如何解决Web加载H5页面时出现的白屏问题

#### 问题现象

使用Web组件加载H5页面时出现页面白屏无法显示内容的问题。

#### 背景知识

1.  页面加载是Web组件的基本功能。根据页面加载数据来源可以分为三种常用场景，包括加载网络页面、加载本地页面、加载HTML格式的文本数据。
2.  在页面加载过程中，若涉及网络资源的获取，需要在module.json5中配置网络访问的权限，添加方法可参考在配置文件中声明权限。
3.  Web组件本地资源跨域问题：为了提高安全性，ArkWeb内核禁止file协议和resource协议访问跨域请求。
4.  User-Agent（简称UA）是一个特殊的字符串，包含设备类型、操作系统及版本等关键信息。在Web开发中，这个字符串使服务器能够识别请求的来源设备及其特性，从而根据这些信息提供定制化的内容和服务。如果页面无法正确识别UA，可能会导致多种异常情况。
5.  通过WebviewController可以控制Web组件各种行为。Web支持一系列属性和事件：
    *   常用属性：
        *   mixedMode：设置是否允许加载超文本传输协议（HTTP）和超文本传输安全协议（HTTPS）混合内容，默认不允许加载HTTP和HTTPS混合内容；
        *   onlineImageAccess：设置是否允许从网络加载图片资源（通过HTTP和HTTPS访问的资源），默认允许访问；
        *   domStorageAccess：设置是否开启文档对象模型存储接口（DOM Storage API）权限，默认未开启；
        *   fileAccess：设置是否开启应用中对于文件系统的访问，涉及文件上传下载操作时需要开启，API12版本及以后默认未开启；
        *   javaScriptAccess：设置是否允许执行JavaScript脚本，默认允许执行。
    *   常用事件：
        
        | 阶段 | 事件/状态 | 触发时机 | 可执行操作 | 注意事项 / 限制 |
        | --- | --- | --- | --- | --- |
        | 1.初始化准备 | aboutToAppear | 自定义组件实例创建后，build执行前 | 设置WebDebug调试模式、自定义协议URL的权限、Cookie等 | / |
        | 2.控制器绑定 | onControllerAttached | Controller成功绑定到Web组件时 | 注入JS对象、设置自定义 User-Agent、使用操作网页不相关的接口 | 禁止在该事件回调前调用Web组件相关的接口，否则会抛出js-error异常 |
        | 3.加载前拦截（URL） | onLoadIntercept | LoadUrl和iframe加载时 | 获取并校验URL字段值是否在业务预置的白名单内，返回true表示取消此次导航，false表示允许此次导航 | 默认允许加载，返回undefined或null时为false；与onOverrideUrlLoading触发时机不同 |
        | 4.加载前拦截（请求） | onInterceptRequest | 加载URL前 | 用于拦截URL并返回响应数据 | / |
        | 5.页面开始加载 | onPageBegin | 页面开始加载时触发 | / | 仅在主frame触发；iframe或frameset的内容加载时不触发 |
        | 6.加载进度更新 | onProgressChange | 页面加载过程中的进度通知 | / | 与onPageEnd无直接先后关系；主frame结束时子frame或多frame页面仍可能加载中 |
        | 7.页面加载完成 | onPageEnd | 页面加载完成时 | 执行JS脚本 | 仅在主frame触发；收到该回调不能保证下一帧反映DOM状态 |
        | 8.页面可见（早期） | onPageVisible | 渲染流程中HTTP响应主体开始加载，新页面即将可见时 | / | 此时文档加载还处于早期，因此链接的资源比如在线CSS、在线图片等可能尚不可用 |
        | 9.组件卸载 | onDisAppear | 组件卸载消失时 | / | / |
        | 10.异常处理路径（一） | onOverrideUrlLoading | URL即将加载时 | 返回true：中止加载；返回false：继续加载 | 与onLoadIntercept不同，在LoadUrl和iframe加载时不会触发 |
        | 11.异常处理路径（二） | onRenderExited | 应用渲染进程异常退出时 | 释放系统资源、保存关键数据等 | 若应用希望异常恢复，需要调用loadUrl接口重新加载页面 |
        | 12.异常处理路径（三） | onErrorReceive | 网页收到Web资源加载错误或无网络时 | 通知异常事件，打印错误信息等 | / |
        | 13.异常处理路径（四） | onSslErrorEvent | 加载资源发生SSL错误时 | 通知用户加载资源（主资源+子资源）时发生SSL错误 | / |
        

#### 问题定位

Web加载H5页面出现异常问题时，可按如下步骤进行定位排查：

1.  使用Web组件加载在线页面的场景下，首先排查网络状态与网络权限的声明，若为Web组件加载本地资源，则不涉及该步骤。
    *   检查网络状况是否正常可用，可通过系统日志中的WifiFrameWork: SignalPoll字段查看wifi状态，主要查看以下关键字的值：
        
        | 关键字 | 描述 |
        | --- | --- |
        | rtRate | 重传率，重传率rtRate>=0.2时报文重传率高，卡顿明显无法上网。 |
        | chload | 通道占用比，可用于表征WiFi信道的繁忙度。chload越高代表网络状态越差，chload 500以上为中网，会卡顿，800以上不可上网。 |
        | rssi | -30表示信号很强，-80表示信号很弱。 |
        | noise | -80为干扰环境，到-60以上就是强干扰。 |
        | isSpeedOk | 网速质量，rx_speed上传速度，tx_speed下载速度，单位b/s，isSpeedOk false是指上传小于24KB，或者下载小于32KB。 |
        
        其中rtRate、rssi、isSpeedOk只要有1项较差就说明网络质量不好。
        
    *   检查项目是否在module.json5中配置声明了网络权限ohos.permission.INTERNET。
        
        ```
        "requestPermissions":[
            {
              "name" : "ohos.permission.INTERNET",
              "reason": xxx,
              "usedScene": xxx
            }
          ]
        ```
        
2.  排查H5页面使用到哪些功能，查看Web组件的属性配置，确认H5页面使用的功能涉及的权限是否正确配置；还需注意排查Web组件宽高设置是否正常，如果宽高属性设置异常（比如特别小或者直接为0）也可能造成显示异常。
3.  若因项目需要，页面使用了复杂布局或渲染模式，需注意其应用场景和约束条件，不当使用可能导致布局混乱或白屏，例如使用Web组件大小自适应页面内容布局模式layoutMode(WebLayoutMode.FIT\_CONTENT)时，异步渲染模式下Web组件的宽高不能超过7680px（物理像素），超过会导致白屏。详情可参考复杂的布局与渲染模式导致白屏。
4.  排查页面是否正确识别用户代理（User-Agent），通常在onControllerAttached回调事件中通过setCustomUserAgent接口设置自定义用户代理，若出现异常，可查询日志是否抛出如下错误，修改UserAgent后再观察页面是否恢复正常。
    
    | 错误码ID | 错误信息 |
    | --- | --- |
    | 17100001 | Init error. The WebviewController must be associated with a Web component. |
    | 401 | Parameter error. Possible causes: 1.Mandatory parameters are left unspecified. 2.Incorrect parameter types. |
    
5.  若以上配置项与属性设置均不存在问题，但仍出现白屏现象，可利用DevTools工具调试前端页面以及监听Web相关错误上报接口，来定位具体报错类型。常见场景有资源加载失败、拦截本地资源跨域等，详情可参考使用DevTools工具进行页面内容验证。
6.  兼容性问题处理不当也会导致页面白屏。若H5页面调用tel:、mailto:等协议导致白屏，需通过onInterceptRequest回调事件拦截并调用系统拨号能力。
    
    ```
    .onInterceptRequest((event) => {
        if (event.request.url.startsWith('tel:')) {
            // 调用系统拨号能力
            call.makeCall({ phoneNumber: '123456' });
            return { responseCode: 404 }; // 阻止默认行为
        }
        return null;
    })
    ```
    
7.  若仍无法定位到问题，需要查看Web相关回调事件中是否有相应拦截或异常处理逻辑，如在onLoadIntercept事件中对指定页面进行拦截，若为相应页面则返回true阻止加载（默认情况下显示为白屏），同时可以根据实际场景加载特定页面等（如加载默认页面或其他错误提示页面）。
    
    ```
    Web({ src: $rawfile('local.html'), controller: this.controller })
      .onLoadIntercept((event) => {
    
        const url = event.data.getRequestUrl();
        console.info('拦截到 URL:', url);
    
        // 判断是否是加载local.html的请求
        if (url.includes('local.html')) {
          console.info('正在拦截 local.html，将替换为 local1.html');
    
          // 替换为加载local1.html
          try {
            this.controller.loadUrl($rawfile('local1.html'));
          } catch (error) {
            console.error('加载 local1.html 失败:', error);
          }
          return true; // 拦截成功，阻止默认加载
        }
        // 其他URL不拦截，允许正常加载
        return false;
      })
    ```
    

#### 分析结论

Web组件加载H5页面白屏问题可分为以下几类场景：

*   加载在线页面网络权限设置问题或Web组件未正确设置对应属性导致的问题：
    *   加载在线页面未配置网络权限；
    *   Web组件未设置对应权限相关属性开启导致页面加载白屏，需要确认Web组件需要的权限是否设置为true，例如H5中如涉及到localStorage、sessionStorage前端存储，需要设置domStorageAccess为true；
    *   Web组件未正确设置宽高属性，如宽高设置过小或在异步渲染模式下超过7680px等。
*   User-Agent（简称UA）未正确设置导致的页面展示异常，包括不限于白屏：UA是一个特殊的字符串，包含设备类型、操作系统及版本等关键信息，Web中通过这个字符串能够针对特定设备提供定制化的内容和服务，在H5页面中如果针对UA进行了定制处理，但未针对HarmonyOS系统或设备进行处理，可能会引发页面渲染异常、布局错乱等问题。
*   加载H5本地离线包时，由于ArkWeb拦截了file和resource协议的跨域访问，导致H5页面因跨域限制出现加载异常。
*   H5页面本身或者H5与ArkTS交互时发生报错导致页面白屏。
*   兼容性问题处理不当以及应用自定义拦截或异常处理逻辑不当等。

#### 修改建议

*   因网络设置问题或Web组件未设置对应权限，这些问题可以按照以下步骤去排查解决：
    1.  确保真机正常联网，并在工程中的module.json5配置文件中添加网络权限：ohos.permission.INTERNET，具体申请方式请参考声明权限。如果使用的是模拟器，需要检查模拟器是否无法连接网络，通常是由于网络代理的原因，按照指引配置即可。
    2.  网站使用了浏览器存储功能或文件系统时，需要开启文档对象模型存储接口和应用中文件系统访问，示例代码如下：
        
        ```
        import { webview } from '@kit.ArkWeb';
        
        @Entry
        @Component
        struct DomFIle {
          controller: webview.WebviewController = new webview.WebviewController();
        
          build() {
            Column() {
              Web({ src: 'www.example.com', controller: this.controller })
                .domStorageAccess(true)
                .fileAccess(true)
                .geolocationAccess(false);
            };
          }
        }
        ```
        
    3.  若是页面依赖于第三方cookie，通过putAcceptThirdPartyCookieEnabled设置发送和接收第三方cookie的权限，示例代码如下：
        
        ```
        import { webview } from '@kit.ArkWeb';
        
        @Entry
        @Component
        struct CookieDemo {
          controller: webview.WebviewController = new webview.WebviewController();
        
          aboutToAppear(): void {
            webview.WebCookieManager.putAcceptThirdPartyCookieEnabled(true);
          }
        
        
        
          build() {
            Column() {
              Web({ src: 'www.example.com', controller: this.controller })
                .domStorageAccess(true)
                .fileAccess(false)
                .geolocationAccess(false);
            };
          }
        }
        ```
        
    4.  Web组件常用的属性设置如下：
        
        ```
        import { webview } from '@kit.ArkWeb';
        
        @Entry
        @Component
        struct Common {
          controller: webview.WebviewController = new webview.WebviewController();
        
          build() {
            Column() {
              Web({ src: 'www.example.com', controller: this.controller })
                .javaScriptAccess(true) // 允许执行JavaScript脚本
                .onlineImageAccess(true) // 允许加载网络图片
                .domStorageAccess(true) // 开启文档对象模型存储接口
                .fileAccess(true) // 设置是否开启应用中文件系统的访问
                .geolocationAccess(false);
            };
          }
        }
        ```
        
*   因UA未正确设置导致的Web页面展示异常，通常有两种解决方案：
    *   方案一（推荐）：联合H5的提供方，在H5代码中支持对于ArkWeb的UA的适配，ArkWeb的UA结构可参考默认User-Agent结构，可以通过OSName字段中的"OpenHarmony"关键字识别是否是HarmonyOS设备，H5中可添加如下的判断代码：
        
        ```
        const isHarmonyOS = () => /OpenHarmony/i.test(navigator.userAgent);
        ```
        
    *   方案二：HarmonyOS中提供了setCustomUserAgent接口，允许设置自定义UA，可通过该接口来兼容原来H5中相关的UA设置。由于该接口会覆盖系统的UA，因此推荐先通过getUserAgent接口获取到默认UA，然后将兼容H5的扩展字段追加到默认UA的末尾，既能保留原有的UA信息，又能增加自定义的UA识别信息。示例代码如下：
        
        ```
        import { webview } from '@kit.ArkWeb';
        import { BusinessError } from '@kit.BasicServicesKit';
        
        @Entry
        @Component
        struct SolutionOne {
          controller: webview.WebviewController = new webview.WebviewController();
          // 自定义UA标识，可更改为兼容原来H5中的UA设置
          customUserAgent: string = 'customUADemo';
        
          build() {
            Column() {
              Web({ src: 'www.example.com', controller: this.controller })
                .fileAccess(false)
                .geolocationAccess(false)
                .expandSafeArea([SafeAreaType.SYSTEM])
                .onControllerAttached(() => {
                  try {
                    let userAgent = this.controller.getUserAgent() + this.customUserAgent;
                    this.controller.setCustomUserAgent(userAgent);
                  } catch (error) {
                    console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
                  }
                });
            };
          }
        }
        ```
        

*   加载H5本地离线包因跨域限制导致的页面加载异常，解决方案有两种：
    *   方案一：使用setPathAllowingUniversalAccess接口设置一个允许访问的路径列表，当使用file协议访问该列表中的资源时，允许进行跨域访问本地文件。
    *   方案二：采用HTTP或HTTPS等协议，替代原先使用的file或resource协议进行加载，同时利用Web组件的onInterceptRequest方法，对本地资源进行拦截和相应的替换。
    *   详细实现可参考本地资源跨域问题解决方法。
*   H5页面本身或者H5与应用侧交互时发生报错导致页面异常，常见的问题有以下几种：
    *   H5本身页面逻辑导致报错；
    *   H5和应用侧进行交互时，未正确建立交互通道或交互逻辑存在问题，导致异常。
*   兼容性问题处理不当以及应用自定义拦截或异常处理逻辑导致的白屏问题，需要根据具体情况在对应事件中进行代码逻辑的优化。

上述问题可以使用DevTools调试工具，在devtool控制台观察是否有报错日志，或者通过断点调试H5页面的方式来排查和解决问题。从DevEco Studio 5.0.13.200版本开始，支持自动映射WebView端口进行调试，无须手动执行端口转发等命令，可参考自动映射WebView调试链接。

#### 总结

排除网络连接或服务端的问题后，其他H5页面加载异常问题和解决方案参见下表：

| 问题分类 | 解决方案 |
| --- | --- |
| Web未设置对应权限导致的页面白屏 | 设置网络权限ohos.permission.INTERNET，同时排查H5页面使用到哪些功能，确认配置了这些功能涉及的权限 |
| 因UA未正确设置导致的Web页面展示异常 | 在H5代码中支持对于ArkWeb的UA的适配或者在工程中自定义UA兼容H5页面 |
| 加载H5本地离线包因跨域限制导致的页面加载白屏 | 使用setPathAllowingUniversalAccess接口允许进行跨域访问本地文件；或者采用HTTP或HTTPS替代原先使用的file或resource协议进行资源加载 |
| H5页面本身或者H5与应用侧交互时发生报错导致页面白屏 | 使用DevTools工具观察控制台日志输出或者调试H5页面排查问题 |
| Web加载事件中的特定拦截或异常处理逻辑不当导致的页面白屏 | 根据具体情况进行逻辑优化 |

#### 常见FAQ

Q：什么场景会触发onReceivedError接口的回调？

A：onReceivedError接口会在Web加载页面遇到无法恢复的错误时会被调用，通常包括找不到目标网页或者连接超时等，可在该回调中自定义错误处理效果，相关错误码可参考@ohos.web.netErrorList (ArkWeb网络协议栈错误列表)。

Q：onReceivedError回调中如何对主frame进行判断？

A：通过isMainFrame方法进行判断：

```
import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct FaqTwo {
  controller: webview.WebviewController = new webview.WebviewController();

  build() {
    Column() {
      Web({ src: 'www.example.com', controller: this.controller })
        .fileAccess(false)
        .geolocationAccess(false)
        .onErrorReceive((event) => {
          if (event) {
            console.info(`isMainFrame:${event.request.isMainFrame()}`);
          }
        });
    };
  }
}
```

Q：Web组件在配置大小自适应页面内容布局后，为什么页面白屏或页面消失不显示？如何解决？

A：H5页面中核心内容DOM节点高度为0或者未设置。本地H5页面可以通过设置核心内容DOM节点高度；如果是网页则只能删除自适应页面内容布局属性，详情参考：设置FIT\_CONTENT后页面白屏或页面消失不显示。

Q：Web和HarmonyOS桥接部分接口未通，引发白屏？

A：通过Web桥接调试，参考Web组件加载某个页面，出现白屏、页面显示不出来，如何解决和定位，找到问题代码点，可通过修改相关问题代码解决。