• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Lifecycle of the Web Component
2
3## Overview
4
5You can use **Web** components to load local or online web pages.
6
7The **Web** component provides lifecycle callbacks for detecting status changes and processing services.
8
9The statuses of a **Web** component include binding a controller to it, the start, progress, and end of page loading, and the state when the page is about to be displayed.
10
11For details about how to keep web pages alive, see [Using Offline Web Components](../web/web-offline-mode.md).
12
13If the [aboutToDisAppear](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#abouttodisappear) function is executed when a custom component is destructed, the **Web** component is destroyed and unbound from the WebviewController, and the JS running environment is also destroyed.
14
15**Figure 1** Callback events during the normal web page loading of the **Web** component
16
17![web-event-sequence](figures/web-event-sequence.png)
18
19## Statuses of the Normal Web Page Loading
20
21- [aboutToAppear](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#abouttoappear): executed before its build function when a new instance of a custom component is created. You are advised to set the web debug mode and customize protocol URL permissions and cookies at this status.
22
23- [onControllerAttached](../reference/apis-arkweb/arkts-basic-components-web-events.md#oncontrollerattached10): triggered when the controller is successfully bound to the **Web** component. Do not call APIs related to the **Web** component before this callback. Otherwise, a js-error exception will be thrown. You are advised to inject a JS object, set a custom user agent, and use APIs irrelevant to web page operations in this event. However, the web page is not loaded when this callback is called. Therefore, APIs for web page operation, such as [zoomIn](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#zoomin) and [zoomOut](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#zoomout), cannot be used in this callback.
24
25- [onLoadIntercept](../reference/apis-arkweb/arkts-basic-components-web-events.md#onloadintercept10): triggered before the **Web** component loads a URL, which is used to determine whether to block the access. By default, the loading is allowed.
26
27- [onInterceptRequest](../reference/apis-arkweb/arkts-basic-components-web-events.md#oninterceptrequest9): triggered before the **Web** component loads a URL, which is used to intercept the URL and return response data.
28
29- [onPageBegin](../reference/apis-arkweb/arkts-basic-components-web-events.md#onpagebegin): triggered when a web page starts loading and only in the main frame (an HTML element used to display the HTML page). This callback is not triggered when the content of an **iframe** or **frameset** (an HTML tag used to include frames) is loaded. Multiple-frame pages may be loaded at the same time. When the main frame is loaded, subframes may still be loaded. This callback will not be triggered for navigations to the same page or failed navigations.
30
31- [onProgressChange](../reference/apis-arkweb/arkts-basic-components-web-events.md#onprogresschange): triggered to notify the page loading progress. The multi-frame page or subframes may continue to be loaded while the main frame has been loaded. Therefore, this event may be received after the [onPageEnd](../reference/apis-arkweb/arkts-basic-components-web-events.md#onpageend) event.
32
33- [onPageEnd](../reference/apis-arkweb/arkts-basic-components-web-events.md#onpageend): triggered only in the main frame when a web page is already loaded. Multi-frame pages may start to be loaded at the same time. Even if the main frame is already loaded, the sub-frames may start to be loaded or continue to be loaded. This callback will not be triggered for navigations to the same page or failed navigations. You are advised to execute the JavaScript script in this callback. Note that even if this callback function is received, the next frame may not reflect the DOM status.
34
35## Statuses of the Abnormal Web Page Loading
36- [onOverrideUrlLoading](../reference/apis-arkweb/arkts-basic-components-web-events.md#onoverrideurlloading12): triggered for the host application to obtain control when a URL is about to be loaded to the current web page. The value **true** means to stop loading the URL, and the value **false** means to continue loading the URL. The behavior of **onLoadIntercept()** is different from that of the **onOverrideUrlLoading()** and they are triggered in different timing. Therefore, the two APIs are used in different scenarios. The **onLoadIntercept** event is triggered when **loadUrl** and iframe are loaded, but the **onOverrideUrlLoading** event is not triggered when **loadUrl** and specific iframe are loaded. For details, see the document.
37
38- [onPageVisible](../reference/apis-arkweb/arkts-basic-components-web-events.md#onpagevisible9): web callback event, which is triggered when the body of an HTTP response starts to be loaded and a new page is about to be displayed in the rendering process. In this case, the document loading is still in the early stage, so the linked resources such as online CSS and images may not be available.
39
40- [onRenderExited](../reference/apis-arkweb/arkts-basic-components-web-events.md#onrenderexited9): triggered when an application rendering process exits abnormally. You can release system resources and save data in this callback. If you want to recover the application, call the [loadUrl](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md#loadurl) API to reload the page. For details, see [How can I prevent page suspension when the Web component's rendering child process exits unexpectedly](#how-can-i-prevent-page-suspension-when-the-web-components-rendering-child-process-exits-unexpectedly).
41
42- [onDisAppear](../reference/apis-arkui/arkui-ts/ts-universal-events-show-hide.md#ondisappear): triggered when a component is uninstalled from the component tree, This event is triggered when a component is uninstalled.
43
44Codes on the application side:
45
46  ```ts
47  // xxx.ets
48  import { webview } from '@kit.ArkWeb';
49  import { BusinessError } from '@kit.BasicServicesKit';
50
51  @Entry
52  @Component
53  struct WebComponent {
54    controller: webview.WebviewController = new webview.WebviewController();
55    responseWeb: WebResourceResponse = new WebResourceResponse();
56    heads: Header[] = new Array();
57    @State webData: string = "<!DOCTYPE html>\n" +
58      "<html>\n" +
59      "<head>\n" +
60      "<title>intercept test</title>\n" +
61      "</head>\n" +
62      "<body>\n" +
63      "<h1>intercept test</h1>\n" +
64      "</body>\n" +
65      "</html>";
66
67    aboutToAppear(): void {
68      try {
69        webview.WebviewController.setWebDebuggingAccess(true);
70      } catch (error) {
71        console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
72      }
73    }
74
75    build() {
76      Column() {
77        Web({ src: $rawfile('index.html'), controller: this.controller })
78          .onControllerAttached(() => {
79            // You are advised to use **loadUrl**, set a custom user agent, and inject a JS object.
80            console.log('onControllerAttached execute')
81          })
82          .onLoadIntercept((event) => {
83            if (event) {
84              console.log('onLoadIntercept url:' + event.data.getRequestUrl())
85              console.log('url:' + event.data.getRequestUrl())
86              console.log('isMainFrame:' + event.data.isMainFrame())
87              console.log('isRedirect:' + event.data.isRedirect())
88              console.log('isRequestGesture:' + event.data.isRequestGesture())
89            }
90            // If true is returned, the loading is blocked. Otherwise, the loading is allowed.
91            return false;
92          })
93          .onOverrideUrlLoading((webResourceRequest: WebResourceRequest) => {
94            if (webResourceRequest && webResourceRequest.getRequestUrl() == "about:blank") {
95              return true;
96            }
97            return false;
98          })
99          .onInterceptRequest((event) => {
100            if (event) {
101              console.log('url:' + event.request.getRequestUrl());
102            }
103            let head1: Header = {
104              headerKey: "Connection",
105              headerValue: "keep-alive"
106            }
107            let head2: Header = {
108              headerKey: "Cache-Control",
109              headerValue: "no-cache"
110            }
111            // Add a new element to the end of the array and return the length of the new array.
112            let length = this.heads.push(head1);
113            length = this.heads.push(head2);
114            console.log('The response header result length is :' + length);
115            this.responseWeb.setResponseHeader(this.heads);
116            this.responseWeb.setResponseData(this.webData);
117            this.responseWeb.setResponseEncoding('utf-8');
118            this.responseWeb.setResponseMimeType('text/html');
119            this.responseWeb.setResponseCode(200);
120            this.responseWeb.setReasonMessage('OK');
121            // If response data is returned, the data is loaded based on the response data. If no response data is returned, null is returned, indicating that the data is loaded in the original mode.
122            return this.responseWeb;
123          })
124          .onPageBegin((event) => {
125            if (event) {
126              console.log('onPageBegin url:' + event.url);
127            }
128          })
129          .onFirstContentfulPaint(event => {
130            if (event) {
131              console.log("onFirstContentfulPaint:" + "[navigationStartTick]:" +
132              event.navigationStartTick + ", [firstContentfulPaintMs]:" +
133              event.firstContentfulPaintMs);
134            }
135          })
136          .onProgressChange((event) => {
137            if (event) {
138              console.log('newProgress:' + event.newProgress);
139            }
140          })
141          .onPageEnd((event) => {
142            // You are advised to execute the JavaScript script in this event.
143            if (event) {
144              console.log('onPageEnd url:' + event.url);
145            }
146          })
147          .onPageVisible((event) => {
148            console.log('onPageVisible url:' + event.url);
149          })
150          .onRenderExited((event) => {
151            if (event) {
152              console.log('onRenderExited reason:' + event.renderExitReason);
153            }
154          })
155          .onDisAppear(() => {
156            this.getUIContext().getPromptAction().showToast({
157              message: 'The web is hidden',
158              duration: 2000
159            })
160          })
161      }
162    }
163  }
164  ```
165
166Frontend index.html:
167
168  ```html
169  <!-- index.html -->
170  <!DOCTYPE html>
171  <html>
172  <head>
173    <meta charset="UTF-8">
174  </head>
175  <body>
176  <h1>Hello, ArkWeb</h1>
177  </body>
178  </html>
179  ```
180
181## Performance Indicators of Web Component Page Loading
182
183Pay attention to some important performance indicators during web page loading. Such as First Contentful Paint (FCP), First Meaningful Paint (FMP), and Largest Contentful Paint (LCP). The **Web** component provides the following APIs for notifying you these indicators of online non-PDF web pages. Local web pages and PDF web pages are not supported.
184
185- [onFirstContentfulPaint](../reference/apis-arkweb/arkts-basic-components-web-events.md#onfirstcontentfulpaint10): triggered when the web page content such as a text, image, non-blank Canvas, or SVG is drawn for the first time.
186
187- [onFirstMeaningfulPaint](../reference/apis-arkweb/arkts-basic-components-web-events.md#onfirstmeaningfulpaint12): triggered when the first meaningful paint is drawn.
188
189- [onLargestContentfulPaint](../reference/apis-arkweb/arkts-basic-components-web-events.md#onlargestcontentfulpaint12): triggered when the largest content, such as the image, text block, or video, is drawn in the visible area.
190
191## How can I prevent page suspension when the Web component's rendering child process exits unexpectedly?
192
193ArkWeb is a **Web** component platform designed to display web page content for applications and provide capabilities such as page loading, interaction, and debugging. When an ArkWeb application is used, the page may be suspended due to various reasons. For example, the ArkWeb child rendering process crashes due to front-end exceptions, or the background ArkWeb child rendering process is terminated due to insufficient system resources. In this case, you need to open the page again or restart the application.
194
195If the web page is suspended when the ArkWeb child process exits abnormally, the application can listen for the [onRenderExited](../reference/apis-arkweb/arkts-basic-components-web-events.md#onrenderexited9) event to obtain the specific exit cause [RenderExitReason](../reference/apis-arkweb/arkts-basic-components-web-e.md#renderexitreason9) and handle the exception in the callback correspondingly.
196
197**Development in Practice**
198```ts
199import { webview } from '@kit.ArkWeb';
200
201@Entry
202@Component
203struct WebComponent {
204  needReloadWhenVisible: boolean = false ;  // When the Web component is invisible, the page reloading is blocked after the render process exits. When the Web component is visible, the page is reloaded.
205  webIsVisible: boolean = false;            // Check whether the Web component is visible.
206
207  // The child process crash is distinguished from other exceptions. You can refine the exception handling policy based on the actual service.
208  renderReloadMaxForCrashed: number = 5;    // Set the maximum number of retries for reloading after a crash. The application can set this parameter based on service characteristics.
209  renderReloadCountForCrashed: number = 0;  // Number of reload times after a crash.
210  renderReloadMaxForOthers: number = 10;    // Set the maximum number of retry times for exiting due to other exceptions. The application can set this parameter based on service characteristics.
211  renderReloadCountForOthers: number = 0;   // Number of reload times after exit due to other exceptions.
212
213  // Create a Web component.
214  controller: webview.WebviewController = new webview.WebviewController();
215
216  // Specify the page to be loaded.
217  url: string = "www.example.com";
218  build() {
219    Column() {
220      Web({ src: this.url, controller: this.controller })
221        .onVisibleAreaChange([0, 1.0], (isVisible) => {
222          this.webIsVisible = isVisible;
223          if (isVisible && this.needReloadWhenVisible) { // Reload the page when the Web component is visible.
224            this.needReloadWhenVisible = false;
225            this.controller.loadUrl(this.url);
226          }
227        })
228        // The application listens for the callback triggered when the child rendering process exits abnormally and handles the exception.
229        .onRenderExited((event) => {
230          if (!event) {
231            return;
232          }
233          if (event.renderExitReason == RenderExitReason.ProcessCrashed) {
234            if (this.renderReloadCountForCrashed >= this.renderReloadMaxForCrashed) {
235              // Set the maximum number of reload times to prevent the page from being cyclically loaded.
236              return;
237            }
238            console.log('renderReloadCountForCrashed: ' + this.renderReloadCountForCrashed);
239            this.renderReloadCountForCrashed++;
240          } else {
241            if (this.renderReloadCountForOthers >= this.renderReloadMaxForOthers) {
242              // Set the maximum number of reload times to prevent the page from being cyclically loaded.
243              return;
244            }
245            console.log('renderReloadCountForOthers: ' + this.renderReloadCountForOthers);
246            this.renderReloadCountForOthers++;
247          }
248          if (this.webIsVisible) {
249            // Reload the page immediately when the Web component is visible.
250            this.controller.loadUrl(this.url);
251            return;
252          }
253          // Do not reload the page immediately when the Web component is invisible.
254          this.needReloadWhenVisible = true;
255        })
256    }
257  }
258}
259```
260