1e41f4b71Sopenharmony_ci# Taking Over the Media Playback on Web Pages
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ciThe **Web** component provides the capability for applications to take over web media player, so that applications can better enhance web media playback capabilities (for example, image quality).
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci## When to Use
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciThere are unsatisfactory scenarios when media is played on a web page, such as unclear video quality, overly simplistic and feature-lacking web player interface, or even videos that cannot be played. 
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciIn this case, if you want to improve the web media playback experience by taking over web media playback with your own or third-party players, you can utilize this functionality.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci## Implementation Principle
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci### Framework for the ArkWeb Kernel to Play Media
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ciWhen this functionality is disabled, the playback architecture of the ArkWeb kernel is as follows:
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci  ![arkweb media pipeline](figures/arkweb_media_pipeline.png)
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci  > **NOTE**
20e41f4b71Sopenharmony_ci  > - In the preceding figure, step 1 indicates that the ArkWeb kernel creates a **WebMdiaPlayer** to play media resources on web pages.
21e41f4b71Sopenharmony_ci  > - Step 2 indicates that the **WebMdiaPlayer** uses the system decoder to render media data.
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ciWhen this functionality is enabled, the playback architecture of the ArkWeb kernel is as follows:
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci  ![arkweb native media player](figures/arkweb_native_media_player.png)
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci  > **NOTE**
28e41f4b71Sopenharmony_ci  > - In the preceding figure, step 1 indicates that the ArkWeb kernel creates a **WebMdiaPlayer** to play media resources on web pages.
29e41f4b71Sopenharmony_ci  > - Step 2 indicates that the **WebMdiaPlayer** uses the **NativeMediaPlayer** provided by the application to render media data.
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci### Interactions Between the ArkWeb Kernel and Application
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci  ![interactions between arkweb and native media player](figures/interactions_between_arkweb_and_native_media_player.png)
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci  > **NOTE**
37e41f4b71Sopenharmony_ci  > - For details about step 1 in the preceding figure, see [Enabling Web Media Playback Takeover](#enabling-web-media-playback-takeover).
38e41f4b71Sopenharmony_ci  > - For details about step 2, see [Creating a Native Media Player](#creating-a-native-media-player).
39e41f4b71Sopenharmony_ci  > - For details about step 3, see [Drawing Native Media Player Components](#drawing-native-media-player-components).
40e41f4b71Sopenharmony_ci  > - For details about step 4, see [Executing Playback Control Commands Sent by ArkWeb Kernel to the Native Media Player](#executing-playback-control-commands-sent-by-arkweb-kernel-to-the-native-media-player).
41e41f4b71Sopenharmony_ci  > - For details about step 5, see [Notifying the State Information of Native Media Player to the ArkWeb Kernel](#notifying-the-state-information-of-native-media-player-to-the-arkweb-kernel).
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci## How to Develop
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci### Enabling Web Media Playback Takeover
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ciTo take over web media playback, you need to enable this functionality 
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ciusing [enableNativeMediaPlayer](../reference/apis-arkweb/ts-basic-components-web.md#enablenativemediaplayer12).
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ci  ```ts
52e41f4b71Sopenharmony_ci  // xxx.ets
53e41f4b71Sopenharmony_ci  import { webview } from '@kit.ArkWeb';
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci  @Entry
56e41f4b71Sopenharmony_ci  @Component
57e41f4b71Sopenharmony_ci  struct WebComponent {
58e41f4b71Sopenharmony_ci    controller: webview.WebviewController = new webview.WebviewController();
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ci    build() {
61e41f4b71Sopenharmony_ci      Column() {
62e41f4b71Sopenharmony_ci        Web({ src: 'www.example.com', controller: this.controller })
63e41f4b71Sopenharmony_ci          .enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
64e41f4b71Sopenharmony_ci      }
65e41f4b71Sopenharmony_ci    }
66e41f4b71Sopenharmony_ci  }
67e41f4b71Sopenharmony_ci  ```
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ciFor details about the API and parameters, see [enableNativeMediaPlayer](../reference/apis-arkweb/ts-basic-components-web.md#enablenativemediaplayer12).
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci### Creating a Native Media Player
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ciOnce this functionality is enabled, the ArkWeb kernel triggers the callback function registered by [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12) each time a media file needs to be played on a web page.
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_ciYou need to register a callback function for creating a native media player by invoking **onCreateNativeMediaPlayer**.
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_ciThe callback function determines whether to create a native media player to take over the web page media resources based on the media information.
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci  * If the application does not take over the web page media resource, **null** is returned in the callback function.
80e41f4b71Sopenharmony_ci  * If the application takes over the web page media resource, a native media player instance is returned in the callback function.
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ciThe native media player needs to implement the [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12) API so that the ArkWeb kernel can control the playback on the native media player.
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci  ```ts
85e41f4b71Sopenharmony_ci  // xxx.ets
86e41f4b71Sopenharmony_ci  import { webview } from '@kit.ArkWeb';
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ci  // Implement the webview.NativeMediaPlayerBridge API.
89e41f4b71Sopenharmony_ci  // The ArkWeb kernel calls the APIs to control playback on NativeMediaPlayer.
90e41f4b71Sopenharmony_ci  class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge {
91e41f4b71Sopenharmony_ci    // ...Implement the APIs in NativeMediaPlayerBridge...
92e41f4b71Sopenharmony_ci    constructor(handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {}
93e41f4b71Sopenharmony_ci    updateRect(x: number, y: number, width: number, height: number) {}
94e41f4b71Sopenharmony_ci    play() {}
95e41f4b71Sopenharmony_ci    pause() {}
96e41f4b71Sopenharmony_ci    seek(targetTime: number) {}
97e41f4b71Sopenharmony_ci    release() {}
98e41f4b71Sopenharmony_ci    setVolume(volume: number) {}
99e41f4b71Sopenharmony_ci    setMuted(muted: boolean) {}
100e41f4b71Sopenharmony_ci    setPlaybackRate(playbackRate: number) {}
101e41f4b71Sopenharmony_ci    enterFullscreen() {}
102e41f4b71Sopenharmony_ci    exitFullscreen() {}
103e41f4b71Sopenharmony_ci  }
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ci  @Entry
106e41f4b71Sopenharmony_ci  @Component
107e41f4b71Sopenharmony_ci  struct WebComponent {
108e41f4b71Sopenharmony_ci    controller: webview.WebviewController = new webview.WebviewController();
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ci    build() {
111e41f4b71Sopenharmony_ci      Column() {
112e41f4b71Sopenharmony_ci        Web({ src: 'www.example.com', controller: this.controller })
113e41f4b71Sopenharmony_ci          .enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
114e41f4b71Sopenharmony_ci          .onPageBegin((event) => {
115e41f4b71Sopenharmony_ci            this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
116e41f4b71Sopenharmony_ci              // Determine whether to take over the media.
117e41f4b71Sopenharmony_ci              if (!shouldHandle(mediaInfo)) {
118e41f4b71Sopenharmony_ci                // The native media player does not take over the media.
119e41f4b71Sopenharmony_ci                // Return null. The ArkWeb kernel will play the media with the web media player.
120e41f4b71Sopenharmony_ci                return null;
121e41f4b71Sopenharmony_ci              }
122e41f4b71Sopenharmony_ci              // Take over the web media.
123e41f4b71Sopenharmony_ci              // Return a native media player instance to the ArkWeb kernel.
124e41f4b71Sopenharmony_ci              let nativePlayer: webview.NativeMediaPlayerBridge = new NativeMediaPlayerImpl(handler, mediaInfo);
125e41f4b71Sopenharmony_ci              return nativePlayer;
126e41f4b71Sopenharmony_ci            });
127e41f4b71Sopenharmony_ci          })
128e41f4b71Sopenharmony_ci      }
129e41f4b71Sopenharmony_ci    }
130e41f4b71Sopenharmony_ci  }
131e41f4b71Sopenharmony_ci
132e41f4b71Sopenharmony_ci  // stub
133e41f4b71Sopenharmony_ci  function shouldHandle(mediaInfo: webview.MediaInfo) {
134e41f4b71Sopenharmony_ci    return true;
135e41f4b71Sopenharmony_ci  }
136e41f4b71Sopenharmony_ci  ```
137e41f4b71Sopenharmony_ci
138e41f4b71Sopenharmony_ciFor details about the APIs and parameters, see [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12).
139e41f4b71Sopenharmony_ci
140e41f4b71Sopenharmony_ci### Drawing Native Media Player Components
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ciWhen the application takes over the media of the web page, you need to draw the native media player components and video images on the surface provided by the ArkWeb kernel.
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ciThen the ArkWeb kernel combines the surface with the web page and displays the web page on the screen.
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ciThis process is the same as that of [Rendering and Drawing XComponent+AVPlayer and Button Components at the Same Layer](web-same-layer.md#)
147e41f4b71Sopenharmony_ci
148e41f4b71Sopenharmony_ci
149e41f4b71Sopenharmony_ci1. Save the **UIContext** when the application is started, which will be used in the subsequent rendering and drawing at the same layer.
150e41f4b71Sopenharmony_ci
151e41f4b71Sopenharmony_ci   ```ts
152e41f4b71Sopenharmony_ci   // xxxAbility.ets
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ci   import { UIAbility } from '@kit.AbilityKit';
155e41f4b71Sopenharmony_ci   import { window } from '@kit.ArkUI';
156e41f4b71Sopenharmony_ci
157e41f4b71Sopenharmony_ci   export default class EntryAbility extends UIAbility {
158e41f4b71Sopenharmony_ci     onWindowStageCreate(windowStage: window.WindowStage): void {
159e41f4b71Sopenharmony_ci       windowStage.loadContent('pages/Index', (err, data) => {
160e41f4b71Sopenharmony_ci         if (err.code) {
161e41f4b71Sopenharmony_ci           return;
162e41f4b71Sopenharmony_ci         }
163e41f4b71Sopenharmony_ci         // Save the UIContext, which will be used in subsequent rendering and drawing at the same layer.
164e41f4b71Sopenharmony_ci         AppStorage.setOrCreate<UIContext>("UIContext", windowStage.getMainWindowSync().getUIContext());
165e41f4b71Sopenharmony_ci       });
166e41f4b71Sopenharmony_ci     }
167e41f4b71Sopenharmony_ci
168e41f4b71Sopenharmony_ci     // ...Other APIs that need to be overridden...
169e41f4b71Sopenharmony_ci   }
170e41f4b71Sopenharmony_ci   ```
171e41f4b71Sopenharmony_ci
172e41f4b71Sopenharmony_ci2. Use the surface created by the ArkWeb kernel is for rendering and drawing at the same layer.
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ci   ```ts
175e41f4b71Sopenharmony_ci   // xxx.ets
176e41f4b71Sopenharmony_ci   import { webview } from '@kit.ArkWeb';
177e41f4b71Sopenharmony_ci   import { BuilderNode, FrameNode, NodeController, NodeRenderType } from '@kit.ArkUI';
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ci   interface ComponentParams {}
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci   class MyNodeController extends NodeController {
182e41f4b71Sopenharmony_ci     private rootNode: BuilderNode<[ComponentParams]> | undefined;
183e41f4b71Sopenharmony_ci
184e41f4b71Sopenharmony_ci     constructor(surfaceId: string, renderType: NodeRenderType) {
185e41f4b71Sopenharmony_ci       super();
186e41f4b71Sopenharmony_ci
187e41f4b71Sopenharmony_ci       // Obtain the saved UIContext.
188e41f4b71Sopenharmony_ci       let uiContext = AppStorage.get<UIContext>("UIContext");
189e41f4b71Sopenharmony_ci       this.rootNode = new BuilderNode(uiContext as UIContext, { surfaceId: surfaceId, type: renderType });
190e41f4b71Sopenharmony_ci     }
191e41f4b71Sopenharmony_ci
192e41f4b71Sopenharmony_ci     makeNode(uiContext: UIContext): FrameNode | null {
193e41f4b71Sopenharmony_ci       if (this.rootNode) {
194e41f4b71Sopenharmony_ci         return this.rootNode.getFrameNode() as FrameNode;
195e41f4b71Sopenharmony_ci       }
196e41f4b71Sopenharmony_ci       return null;
197e41f4b71Sopenharmony_ci     }
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci     build() {
200e41f4b71Sopenharmony_ci       // Construct the native media player component.
201e41f4b71Sopenharmony_ci     }
202e41f4b71Sopenharmony_ci   }
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ci   @Entry
205e41f4b71Sopenharmony_ci   @Component
206e41f4b71Sopenharmony_ci   struct WebComponent {
207e41f4b71Sopenharmony_ci     node_controller?: MyNodeController;
208e41f4b71Sopenharmony_ci     controller: webview.WebviewController = new webview.WebviewController();
209e41f4b71Sopenharmony_ci     @State show_native_media_player: boolean = false;
210e41f4b71Sopenharmony_ci
211e41f4b71Sopenharmony_ci     build() {
212e41f4b71Sopenharmony_ci       Column() {
213e41f4b71Sopenharmony_ci         Stack({ alignContent: Alignment.TopStart }) {
214e41f4b71Sopenharmony_ci           if (this.show_native_media_player) {
215e41f4b71Sopenharmony_ci             NodeContainer(this.node_controller)
216e41f4b71Sopenharmony_ci               .width(300)
217e41f4b71Sopenharmony_ci               .height(150)
218e41f4b71Sopenharmony_ci               .backgroundColor(Color.Transparent)
219e41f4b71Sopenharmony_ci               .border({ width: 2, color: Color.Orange })
220e41f4b71Sopenharmony_ci           }
221e41f4b71Sopenharmony_ci           Web({ src: 'www.example.com', controller: this.controller })
222e41f4b71Sopenharmony_ci             .enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
223e41f4b71Sopenharmony_ci             .onPageBegin((event) => {
224e41f4b71Sopenharmony_ci               this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo:    webview.MediaInfo) => {
225e41f4b71Sopenharmony_ci                 // Take over the web media.
226e41f4b71Sopenharmony_ci
227e41f4b71Sopenharmony_ci                 // Use the surface provided by the rendering at the same layer to construct a native media player component.
228e41f4b71Sopenharmony_ci                 this.node_controller = new MyNodeController(mediaInfo..surfaceInfo.id, NodeRenderType.  RENDER_TYPE_TEXTURE);
229e41f4b71Sopenharmony_ci                 this.node_controller.build();
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_ci                 // Show the native media player component.
232e41f4b71Sopenharmony_ci                 this.show_native_media_player = true;
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci                 // Return a native media player instance to the ArkWeb kernel.
235e41f4b71Sopenharmony_ci                 return null;
236e41f4b71Sopenharmony_ci               });
237e41f4b71Sopenharmony_ci             })
238e41f4b71Sopenharmony_ci         }
239e41f4b71Sopenharmony_ci       }
240e41f4b71Sopenharmony_ci     }
241e41f4b71Sopenharmony_ci   }
242e41f4b71Sopenharmony_ci   ```
243e41f4b71Sopenharmony_ci
244e41f4b71Sopenharmony_ciFor details about how to dynamically create components and draw them on the surface, see [Rendering and Drawing XComponent+AVPlayer and Button Components at the Same Layer](web-same-layer.md#).
245e41f4b71Sopenharmony_ci
246e41f4b71Sopenharmony_ci### Executing Playback Control Commands Sent by ArkWeb Kernel to the Native Media Player
247e41f4b71Sopenharmony_ci
248e41f4b71Sopenharmony_ciTo facilitate the control over native media player by the ArkWeb kernel, you need to implement the [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12) API on the native media player and perform operations on the native media player based on the functionality of each API.
249e41f4b71Sopenharmony_ci
250e41f4b71Sopenharmony_ci  ```ts
251e41f4b71Sopenharmony_ci  // xxx.ets
252e41f4b71Sopenharmony_ci  import { webview } from '@kit.ArkWeb';
253e41f4b71Sopenharmony_ci
254e41f4b71Sopenharmony_ci  class ActualNativeMediaPlayerListener {
255e41f4b71Sopenharmony_ci    constructor(handler: webview.NativeMediaPlayerHandler) {}
256e41f4b71Sopenharmony_ci  }
257e41f4b71Sopenharmony_ci
258e41f4b71Sopenharmony_ci  class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge {
259e41f4b71Sopenharmony_ci    constructor(handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {
260e41f4b71Sopenharmony_ci      // 1. Create a listener for the native media player.
261e41f4b71Sopenharmony_ci      let listener: ActualNativeMediaPlayerListener = new ActualNativeMediaPlayerListener(handler);
262e41f4b71Sopenharmony_ci      // 2. Create a native media player.
263e41f4b71Sopenharmony_ci      // 3. Listen for the local player.
264e41f4b71Sopenharmony_ci      // ...
265e41f4b71Sopenharmony_ci    }
266e41f4b71Sopenharmony_ci
267e41f4b71Sopenharmony_ci    updateRect(x: number, y: number, width: number, height: number) {
268e41f4b71Sopenharmony_ci      // The position and size of the <video> tag are changed.
269e41f4b71Sopenharmony_ci      // Make changes based on the information change.
270e41f4b71Sopenharmony_ci    }
271e41f4b71Sopenharmony_ci
272e41f4b71Sopenharmony_ci    play() {
273e41f4b71Sopenharmony_ci      // Starts the native media player for playback.
274e41f4b71Sopenharmony_ci    }
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ci    pause() {
277e41f4b71Sopenharmony_ci      // Pause the playback.
278e41f4b71Sopenharmony_ci    }
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci    seek(targetTime: number) {
281e41f4b71Sopenharmony_ci      // The native media player seeks to the target playback time.
282e41f4b71Sopenharmony_ci    }
283e41f4b71Sopenharmony_ci
284e41f4b71Sopenharmony_ci    release() {
285e41f4b71Sopenharmony_ci      // Destroy the native media player.
286e41f4b71Sopenharmony_ci    }
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci    setVolume(volume: number) {
289e41f4b71Sopenharmony_ci      // The ArkWeb kernel adjusts the volume of the native media player.
290e41f4b71Sopenharmony_ci      // Set the volume of the native media player.
291e41f4b71Sopenharmony_ci    }
292e41f4b71Sopenharmony_ci
293e41f4b71Sopenharmony_ci    setMuted(muted: boolean) {
294e41f4b71Sopenharmony_ci      // Mute or unmute the native media player.
295e41f4b71Sopenharmony_ci    }
296e41f4b71Sopenharmony_ci
297e41f4b71Sopenharmony_ci    setPlaybackRate(playbackRate: number) {
298e41f4b71Sopenharmony_ci      // Set the playback rate of the native media player.
299e41f4b71Sopenharmony_ci    }
300e41f4b71Sopenharmony_ci
301e41f4b71Sopenharmony_ci    enterFullscreen() {
302e41f4b71Sopenharmony_ci      // Enter the full-screen mode.
303e41f4b71Sopenharmony_ci    }
304e41f4b71Sopenharmony_ci
305e41f4b71Sopenharmony_ci    exitFullscreen() {
306e41f4b71Sopenharmony_ci      // Exit the full-screen mode.
307e41f4b71Sopenharmony_ci    }
308e41f4b71Sopenharmony_ci  }
309e41f4b71Sopenharmony_ci  ```
310e41f4b71Sopenharmony_ci
311e41f4b71Sopenharmony_ciFor details about the APIs, see [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12).
312e41f4b71Sopenharmony_ci
313e41f4b71Sopenharmony_ci### Notifying the State Information of Native Media Player to the ArkWeb Kernel
314e41f4b71Sopenharmony_ci
315e41f4b71Sopenharmony_ciThe ArkWeb kernel requires the state information of the local player to update to the web page, such as the width and height of the video, playback time, and cache time. You need to notify the ArkWeb kernel of the state information of the native media player.
316e41f4b71Sopenharmony_ci
317e41f4b71Sopenharmony_ciThrough the [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12) API, the Ark Web kernel passes a [NativeMediaPlayerHandler](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerhandler12) object to the application.
318e41f4b71Sopenharmony_ci
319e41f4b71Sopenharmony_ciYou need to use this object to notify the ArkWeb kernel of the latest state information of the native media player.
320e41f4b71Sopenharmony_ci
321e41f4b71Sopenharmony_ci  ```ts
322e41f4b71Sopenharmony_ci  // xxx.ets
323e41f4b71Sopenharmony_ci  import { webview } from '@kit.ArkWeb';
324e41f4b71Sopenharmony_ci
325e41f4b71Sopenharmony_ci  class ActualNativeMediaPlayerListener {
326e41f4b71Sopenharmony_ci    handler: webview.NativeMediaPlayerHandler;
327e41f4b71Sopenharmony_ci
328e41f4b71Sopenharmony_ci    constructor(handler: webview.NativeMediaPlayerHandler) {
329e41f4b71Sopenharmony_ci      this.handler = handler;
330e41f4b71Sopenharmony_ci    }
331e41f4b71Sopenharmony_ci
332e41f4b71Sopenharmony_ci    onPlaying() {
333e41f4b71Sopenharmony_ci      // The native media player starts playback.
334e41f4b71Sopenharmony_ci      this.handler.handleStatusChanged(webview.PlaybackStatus.PLAYING);
335e41f4b71Sopenharmony_ci    }
336e41f4b71Sopenharmony_ci    onPaused() {
337e41f4b71Sopenharmony_ci      // The native media player pauses the playback.
338e41f4b71Sopenharmony_ci      this.handler.handleStatusChanged(webview.PlaybackStatus.PAUSED);
339e41f4b71Sopenharmony_ci    }
340e41f4b71Sopenharmony_ci    onSeeking() {
341e41f4b71Sopenharmony_ci      // The native media player starts to seek the target time point.
342e41f4b71Sopenharmony_ci      this.handler.handleSeeking();
343e41f4b71Sopenharmony_ci    }
344e41f4b71Sopenharmony_ci    onSeekDone() {
345e41f4b71Sopenharmony_ci      // The target time point is sought.
346e41f4b71Sopenharmony_ci      this.handler.handleSeekFinished();
347e41f4b71Sopenharmony_ci    }
348e41f4b71Sopenharmony_ci    onEnded() {
349e41f4b71Sopenharmony_ci      // The playback on the native media player is ended.
350e41f4b71Sopenharmony_ci      this.handler.handleEnded();
351e41f4b71Sopenharmony_ci    }
352e41f4b71Sopenharmony_ci    onVolumeChanged() {
353e41f4b71Sopenharmony_ci      // Obtain the volume of the native media player.
354e41f4b71Sopenharmony_ci      let volume: number = getVolume();
355e41f4b71Sopenharmony_ci      this.handler.handleVolumeChanged(volume);
356e41f4b71Sopenharmony_ci    }
357e41f4b71Sopenharmony_ci    onCurrentPlayingTimeUpdate() {
358e41f4b71Sopenharmony_ci      // Update the playback time.
359e41f4b71Sopenharmony_ci      let currentTime: number = getCurrentPlayingTime();
360e41f4b71Sopenharmony_ci      // Convert the time unit to second.
361e41f4b71Sopenharmony_ci      let currentTimeInSeconds = convertToSeconds(currentTime);
362e41f4b71Sopenharmony_ci      this.handler.handleTimeUpdate(currentTimeInSeconds);
363e41f4b71Sopenharmony_ci    }
364e41f4b71Sopenharmony_ci    onBufferedChanged() {
365e41f4b71Sopenharmony_ci      // The buffer is changed.
366e41f4b71Sopenharmony_ci      // Obtain the cache duration of the native media player.
367e41f4b71Sopenharmony_ci      let bufferedEndTime: number = getCurrentBufferedTime();
368e41f4b71Sopenharmony_ci      // Convert the time unit to second.
369e41f4b71Sopenharmony_ci      let bufferedEndTimeInSeconds = convertToSeconds(bufferedEndTime);
370e41f4b71Sopenharmony_ci      this.handler.handleBufferedEndTimeChanged(bufferedEndTimeInSeconds);
371e41f4b71Sopenharmony_ci
372e41f4b71Sopenharmony_ci      // Check the cache state.
373e41f4b71Sopenharmony_ci      // If the cache state changes, notify the ArkWeb kernel.
374e41f4b71Sopenharmony_ci      let lastReadyState: webview.ReadyState = getLastReadyState();
375e41f4b71Sopenharmony_ci      let currentReadyState: webview.ReadyState = getCurrentReadyState();
376e41f4b71Sopenharmony_ci      if (lastReadyState != currentReadyState) {
377e41f4b71Sopenharmony_ci        this.handler.handleReadyStateChanged(currentReadyState);
378e41f4b71Sopenharmony_ci      }
379e41f4b71Sopenharmony_ci    }
380e41f4b71Sopenharmony_ci    onEnterFullscreen() {
381e41f4b71Sopenharmony_ci      // The native media player enters the full-screen mode.
382e41f4b71Sopenharmony_ci      let isFullscreen: boolean = true;
383e41f4b71Sopenharmony_ci      this.handler.handleFullscreenChanged(isFullscreen);
384e41f4b71Sopenharmony_ci    }
385e41f4b71Sopenharmony_ci    onExitFullscreen() {
386e41f4b71Sopenharmony_ci      // The native media player exits the full-screen mode.
387e41f4b71Sopenharmony_ci      let isFullscreen: boolean = false;
388e41f4b71Sopenharmony_ci      this.handler.handleFullscreenChanged(isFullscreen);
389e41f4b71Sopenharmony_ci    }
390e41f4b71Sopenharmony_ci    onUpdateVideoSize(width: number, height: number) {
391e41f4b71Sopenharmony_ci      // Notify the ArkWeb kernel when the local player parses the video width and height.
392e41f4b71Sopenharmony_ci      this.handler.handleVideoSizeChanged(width, height);
393e41f4b71Sopenharmony_ci    }
394e41f4b71Sopenharmony_ci
395e41f4b71Sopenharmony_ci    // ...Listen for other state of the native media player.
396e41f4b71Sopenharmony_ci  }
397e41f4b71Sopenharmony_ci  @Entry
398e41f4b71Sopenharmony_ci  @Component
399e41f4b71Sopenharmony_ci  struct WebComponent {
400e41f4b71Sopenharmony_ci    controller: webview.WebviewController = new webview.WebviewController();
401e41f4b71Sopenharmony_ci    @State show_native_media_player: boolean = false;
402e41f4b71Sopenharmony_ci
403e41f4b71Sopenharmony_ci    build() {
404e41f4b71Sopenharmony_ci      Column() {
405e41f4b71Sopenharmony_ci        Web({ src: 'www.example.com', controller: this.controller })
406e41f4b71Sopenharmony_ci          .enableNativeMediaPlayer({enable: true, shouldOverlay: false})
407e41f4b71Sopenharmony_ci          .onPageBegin((event) => {
408e41f4b71Sopenharmony_ci            this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
409e41f4b71Sopenharmony_ci              // Take over the web media.
410e41f4b71Sopenharmony_ci
411e41f4b71Sopenharmony_ci              // Create a native media player instance.
412e41f4b71Sopenharmony_ci              // let nativePlayer: NativeMediaPlayerImpl = new NativeMediaPlayerImpl(handler, mediaInfo);
413e41f4b71Sopenharmony_ci
414e41f4b71Sopenharmony_ci              // Create a listener for the native media player state. 
415e41f4b71Sopenharmony_ci              let nativeMediaPlayerListener: ActualNativeMediaPlayerListener = new ActualNativeMediaPlayerListener(handler);
416e41f4b71Sopenharmony_ci              // Listen for the native media player state.
417e41f4b71Sopenharmony_ci              // nativePlayer.setListener(nativeMediaPlayerListener);
418e41f4b71Sopenharmony_ci
419e41f4b71Sopenharmony_ci              // Return the native media player instance to the ArkWeb kernel.
420e41f4b71Sopenharmony_ci              return null;
421e41f4b71Sopenharmony_ci            });
422e41f4b71Sopenharmony_ci          })
423e41f4b71Sopenharmony_ci      }
424e41f4b71Sopenharmony_ci    }
425e41f4b71Sopenharmony_ci  }
426e41f4b71Sopenharmony_ci
427e41f4b71Sopenharmony_ci  // stub
428e41f4b71Sopenharmony_ci  function getVolume() {
429e41f4b71Sopenharmony_ci    return 1;
430e41f4b71Sopenharmony_ci  }
431e41f4b71Sopenharmony_ci  function getCurrentPlayingTime() {
432e41f4b71Sopenharmony_ci    return 1;
433e41f4b71Sopenharmony_ci  }
434e41f4b71Sopenharmony_ci  function getCurrentBufferedTime() {
435e41f4b71Sopenharmony_ci    return 1;
436e41f4b71Sopenharmony_ci  }
437e41f4b71Sopenharmony_ci  function convertToSeconds(input: number) {
438e41f4b71Sopenharmony_ci    return input;
439e41f4b71Sopenharmony_ci  }
440e41f4b71Sopenharmony_ci  function getLastReadyState() {
441e41f4b71Sopenharmony_ci    return webview.ReadyState.HAVE_NOTHING;
442e41f4b71Sopenharmony_ci  }
443e41f4b71Sopenharmony_ci  function getCurrentReadyState() {
444e41f4b71Sopenharmony_ci    return webview.ReadyState.HAVE_NOTHING;
445e41f4b71Sopenharmony_ci  }
446e41f4b71Sopenharmony_ci  ```
447e41f4b71Sopenharmony_ci
448e41f4b71Sopenharmony_ci
449e41f4b71Sopenharmony_ciFor details about the APIs, see [NativeMediaPlayerHandler](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerhandler12).
450e41f4b71Sopenharmony_ci
451e41f4b71Sopenharmony_ci
452e41f4b71Sopenharmony_ci## Sample Code
453e41f4b71Sopenharmony_ci
454e41f4b71Sopenharmony_ci- Add the following permissions to **module.json5** before using it:
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ci  ```ts
457e41f4b71Sopenharmony_ci  "ohos.permission.INTERNET"
458e41f4b71Sopenharmony_ci  ```
459e41f4b71Sopenharmony_ci
460e41f4b71Sopenharmony_ci- Example of saving **UIContext** during application startup on the application side:
461e41f4b71Sopenharmony_ci
462e41f4b71Sopenharmony_ci  ```ts
463e41f4b71Sopenharmony_ci  // xxxAbility.ets
464e41f4b71Sopenharmony_ci
465e41f4b71Sopenharmony_ci  import { UIAbility } from '@kit.AbilityKit';
466e41f4b71Sopenharmony_ci  import { window } from '@kit.ArkUI';
467e41f4b71Sopenharmony_ci
468e41f4b71Sopenharmony_ci  export default class EntryAbility extends UIAbility {
469e41f4b71Sopenharmony_ci    onWindowStageCreate(windowStage: window.WindowStage): void {
470e41f4b71Sopenharmony_ci      windowStage.loadContent('pages/Index', (err, data) => {
471e41f4b71Sopenharmony_ci        if (err.code) {
472e41f4b71Sopenharmony_ci          return;
473e41f4b71Sopenharmony_ci        }
474e41f4b71Sopenharmony_ci        // Save the UIContext, which will be used in subsequent rendering and drawing at the same layer.
475e41f4b71Sopenharmony_ci        AppStorage.setOrCreate<UIContext>("UIContext", windowStage.getMainWindowSync().getUIContext());
476e41f4b71Sopenharmony_ci      });
477e41f4b71Sopenharmony_ci    }
478e41f4b71Sopenharmony_ci
479e41f4b71Sopenharmony_ci    // ...Other APIs that need to be overridden...
480e41f4b71Sopenharmony_ci  }
481e41f4b71Sopenharmony_ci  ```
482e41f4b71Sopenharmony_ci
483e41f4b71Sopenharmony_ci- Example of web media playback takeover:
484e41f4b71Sopenharmony_ci
485e41f4b71Sopenharmony_ci  ```ts
486e41f4b71Sopenharmony_ci  import { webview } from '@kit.ArkWeb';
487e41f4b71Sopenharmony_ci  import { BuilderNode, FrameNode, NodeController, NodeRenderType, UIContext } from '@kit.ArkUI';
488e41f4b71Sopenharmony_ci  import { AVPlayerDemo, AVPlayerListener } from './PlayerDemo';
489e41f4b71Sopenharmony_ci
490e41f4b71Sopenharmony_ci  // Implement the webview.NativeMediaPlayerBridge API.
491e41f4b71Sopenharmony_ci  // The ArkWeb kernel calls the APIs to control playback on NativeMediaPlayer.
492e41f4b71Sopenharmony_ci  class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge {
493e41f4b71Sopenharmony_ci    private surfaceId: string;
494e41f4b71Sopenharmony_ci    mediaSource: string;
495e41f4b71Sopenharmony_ci    private mediaHandler: webview.NativeMediaPlayerHandler;
496e41f4b71Sopenharmony_ci    web: WebComponent;
497e41f4b71Sopenharmony_ci    nativePlayer?: AVPlayerDemo;
498e41f4b71Sopenharmony_ci
499e41f4b71Sopenharmony_ci    constructor(web: WebComponent, handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {
500e41f4b71Sopenharmony_ci      console.log('NativeMediaPlayerImpl.constructor, surface_id[' + mediaInfo.surfaceInfo.id + ']');
501e41f4b71Sopenharmony_ci      this.web = web;
502e41f4b71Sopenharmony_ci      this.mediaHandler = handler;
503e41f4b71Sopenharmony_ci      this.surfaceId = mediaInfo.surfaceInfo.id;
504e41f4b71Sopenharmony_ci      this.mediaSource = mediaInfo.mediaSrcList[0].source;
505e41f4b71Sopenharmony_ci
506e41f4b71Sopenharmony_ci      // Use the rendering function at the same layer to draw the video and its playback control components to the web page.
507e41f4b71Sopenharmony_ci      this.web.node_controller = new MyNodeController(
508e41f4b71Sopenharmony_ci          this.web, this.surfaceId, this.mediaHandler, this, NodeRenderType.RENDER_TYPE_TEXTURE)
509e41f4b71Sopenharmony_ci      this.web.node_controller.build()
510e41f4b71Sopenharmony_ci      this.web.show_native_media_player = true;
511e41f4b71Sopenharmony_ci
512e41f4b71Sopenharmony_ci      console.log('NativeMediaPlayerImpl.mediaSource : ' + this.mediaSource);
513e41f4b71Sopenharmony_ci    }
514e41f4b71Sopenharmony_ci
515e41f4b71Sopenharmony_ci    setNativePlayer(nativePlayer: AVPlayerDemo) {
516e41f4b71Sopenharmony_ci      this.nativePlayer = nativePlayer;
517e41f4b71Sopenharmony_ci    }
518e41f4b71Sopenharmony_ci
519e41f4b71Sopenharmony_ci    updateRect(x: number, y: number, width: number, height: number): void {
520e41f4b71Sopenharmony_ci      this.web.node_width = width
521e41f4b71Sopenharmony_ci      this.web.node_height = height
522e41f4b71Sopenharmony_ci    }
523e41f4b71Sopenharmony_ci
524e41f4b71Sopenharmony_ci    play() {
525e41f4b71Sopenharmony_ci      this.nativePlayer?.play();
526e41f4b71Sopenharmony_ci    }
527e41f4b71Sopenharmony_ci    pause() {
528e41f4b71Sopenharmony_ci      this.nativePlayer?.pause();
529e41f4b71Sopenharmony_ci    }
530e41f4b71Sopenharmony_ci    seek(targetTime: number) {
531e41f4b71Sopenharmony_ci    }
532e41f4b71Sopenharmony_ci    setVolume(volume: number) {
533e41f4b71Sopenharmony_ci    }
534e41f4b71Sopenharmony_ci    setMuted(muted: boolean) {
535e41f4b71Sopenharmony_ci    }
536e41f4b71Sopenharmony_ci    setPlaybackRate(playbackRate: number) {
537e41f4b71Sopenharmony_ci    }
538e41f4b71Sopenharmony_ci    release() {
539e41f4b71Sopenharmony_ci      this.nativePlayer?.release();
540e41f4b71Sopenharmony_ci      this.web.show_native_media_player = false;
541e41f4b71Sopenharmony_ci    }
542e41f4b71Sopenharmony_ci    enterFullscreen() {
543e41f4b71Sopenharmony_ci    }
544e41f4b71Sopenharmony_ci    exitFullscreen() {
545e41f4b71Sopenharmony_ci    }
546e41f4b71Sopenharmony_ci  }
547e41f4b71Sopenharmony_ci
548e41f4b71Sopenharmony_ci  // Listen for the NativeMediaPlayer state and report the state to the ArkWeb kernel using webview.NativeMediaPlayerHandler.
549e41f4b71Sopenharmony_ci  class AVPlayerListenerImpl implements AVPlayerListener {
550e41f4b71Sopenharmony_ci    handler: webview.NativeMediaPlayerHandler;
551e41f4b71Sopenharmony_ci    component: NativePlayerComponent;
552e41f4b71Sopenharmony_ci
553e41f4b71Sopenharmony_ci    constructor(handler: webview.NativeMediaPlayerHandler, component: NativePlayerComponent) {
554e41f4b71Sopenharmony_ci      this.handler = handler;
555e41f4b71Sopenharmony_ci      this.component = component;
556e41f4b71Sopenharmony_ci    }
557e41f4b71Sopenharmony_ci    onPlaying() {
558e41f4b71Sopenharmony_ci      this.handler.handleStatusChanged(webview.PlaybackStatus.PLAYING);
559e41f4b71Sopenharmony_ci    }
560e41f4b71Sopenharmony_ci    onPaused() {
561e41f4b71Sopenharmony_ci      this.handler.handleStatusChanged(webview.PlaybackStatus.PAUSED);
562e41f4b71Sopenharmony_ci    }
563e41f4b71Sopenharmony_ci    onDurationChanged(duration: number) {
564e41f4b71Sopenharmony_ci      this.handler.handleDurationChanged(duration);
565e41f4b71Sopenharmony_ci    }
566e41f4b71Sopenharmony_ci    onBufferedTimeChanged(buffered: number) {
567e41f4b71Sopenharmony_ci      this.handler.handleBufferedEndTimeChanged(buffered);
568e41f4b71Sopenharmony_ci    }
569e41f4b71Sopenharmony_ci    onTimeUpdate(time: number) {
570e41f4b71Sopenharmony_ci      this.handler.handleTimeUpdate(time);
571e41f4b71Sopenharmony_ci    }
572e41f4b71Sopenharmony_ci    onEnded() {
573e41f4b71Sopenharmony_ci      this.handler.handleEnded();
574e41f4b71Sopenharmony_ci    }
575e41f4b71Sopenharmony_ci    onError() {
576e41f4b71Sopenharmony_ci      this.handler.handleError(1, "Oops!");
577e41f4b71Sopenharmony_ci    }
578e41f4b71Sopenharmony_ci    onVideoSizeChanged(width: number, height: number) {
579e41f4b71Sopenharmony_ci      this.handler.handleVideoSizeChanged(width, height);
580e41f4b71Sopenharmony_ci      this.component.onSizeChanged(width, height);
581e41f4b71Sopenharmony_ci    }
582e41f4b71Sopenharmony_ci  }
583e41f4b71Sopenharmony_ci
584e41f4b71Sopenharmony_ci  interface Params {
585e41f4b71Sopenharmony_ci    text: string
586e41f4b71Sopenharmony_ci    text2: string
587e41f4b71Sopenharmony_ci    web_tab: WebComponent
588e41f4b71Sopenharmony_ci    handler: webview.NativeMediaPlayerHandler
589e41f4b71Sopenharmony_ci    player: NativeMediaPlayerImpl
590e41f4b71Sopenharmony_ci  }
591e41f4b71Sopenharmony_ci
592e41f4b71Sopenharmony_ci  // Define the player components.
593e41f4b71Sopenharmony_ci  @Component
594e41f4b71Sopenharmony_ci  struct NativePlayerComponent {
595e41f4b71Sopenharmony_ci    params?: Params
596e41f4b71Sopenharmony_ci    @State bkColor: Color = Color.Red
597e41f4b71Sopenharmony_ci    mXComponentController: XComponentController = new XComponentController();
598e41f4b71Sopenharmony_ci    @State player_changed: boolean = false;
599e41f4b71Sopenharmony_ci
600e41f4b71Sopenharmony_ci    videoController: VideoController = new VideoController();
601e41f4b71Sopenharmony_ci    player?: AVPlayerDemo
602e41f4b71Sopenharmony_ci    offset_x: number = 0
603e41f4b71Sopenharmony_ci    offset_y: number = 0
604e41f4b71Sopenharmony_ci    @State video_width_percent: number = 100;
605e41f4b71Sopenharmony_ci    @State video_height_percent: number = 100;
606e41f4b71Sopenharmony_ci    view_width: number = 0;
607e41f4b71Sopenharmony_ci    view_height: number = 0;
608e41f4b71Sopenharmony_ci    video_width: number = 0;
609e41f4b71Sopenharmony_ci    video_height: number = 0;
610e41f4b71Sopenharmony_ci
611e41f4b71Sopenharmony_ci    fullscreen: boolean = false;
612e41f4b71Sopenharmony_ci
613e41f4b71Sopenharmony_ci    onSizeChanged(width: number, height: number) {
614e41f4b71Sopenharmony_ci      this.video_width = width;
615e41f4b71Sopenharmony_ci      this.video_height = height;
616e41f4b71Sopenharmony_ci      let scale: number = this.view_width / width;
617e41f4b71Sopenharmony_ci      let scaled_video_height: number = scale * height;
618e41f4b71Sopenharmony_ci      this.video_height_percent = scaled_video_height / this.view_height * 100;
619e41f4b71Sopenharmony_ci    }
620e41f4b71Sopenharmony_ci
621e41f4b71Sopenharmony_ci    build() {
622e41f4b71Sopenharmony_ci      Column() {
623e41f4b71Sopenharmony_ci        Stack() {
624e41f4b71Sopenharmony_ci          XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController })
625e41f4b71Sopenharmony_ci            .width(this.video_width_percent + '%')
626e41f4b71Sopenharmony_ci            .height(this.video_height_percent + '%')
627e41f4b71Sopenharmony_ci            .border({ width: 1, color: Color.Red })
628e41f4b71Sopenharmony_ci            .onLoad(()=>{
629e41f4b71Sopenharmony_ci              if (!this.params) {
630e41f4b71Sopenharmony_ci                console.log('this.params is null');
631e41f4b71Sopenharmony_ci                return;
632e41f4b71Sopenharmony_ci              }
633e41f4b71Sopenharmony_ci              this.player = new AVPlayerDemo();
634e41f4b71Sopenharmony_ci              this.params.player?.setNativePlayer(this.player);
635e41f4b71Sopenharmony_ci              this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId());
636e41f4b71Sopenharmony_ci              this.player_changed = !this.player_changed;
637e41f4b71Sopenharmony_ci
638e41f4b71Sopenharmony_ci              this.player.avPlayerLiveDemo(
639e41f4b71Sopenharmony_ci                this.params.player.mediaSource,
640e41f4b71Sopenharmony_ci                new AVPlayerListenerImpl(this.params.handler, this));
641e41f4b71Sopenharmony_ci            })
642e41f4b71Sopenharmony_ci          Column() {
643e41f4b71Sopenharmony_ci            Row() {
644e41f4b71Sopenharmony_ci              Button(this.params?.text)
645e41f4b71Sopenharmony_ci                .height(50)
646e41f4b71Sopenharmony_ci                .border({ width: 2, color: Color.Red })
647e41f4b71Sopenharmony_ci                .backgroundColor(this.bkColor)
648e41f4b71Sopenharmony_ci                .onClick(()=>{
649e41f4b71Sopenharmony_ci                  console.log('[BrowserShell] Button[' + this.params?.text + '] is clicked');
650e41f4b71Sopenharmony_ci                  this.player?.play();
651e41f4b71Sopenharmony_ci                })
652e41f4b71Sopenharmony_ci                .onTouch((event: TouchEvent) => {
653e41f4b71Sopenharmony_ci                  event.stopPropagation();
654e41f4b71Sopenharmony_ci                })
655e41f4b71Sopenharmony_ci              Button(this.params?.text2)
656e41f4b71Sopenharmony_ci                .height(50)
657e41f4b71Sopenharmony_ci                .border({ width: 2, color: Color.Red })
658e41f4b71Sopenharmony_ci                .onClick(()=>{
659e41f4b71Sopenharmony_ci                  console.log('[BrowserShell] Button[' + this.params?.text2 + '] is clicked');
660e41f4b71Sopenharmony_ci                  this.player?.pause();
661e41f4b71Sopenharmony_ci                })
662e41f4b71Sopenharmony_ci                .onTouch((event: TouchEvent) => {
663e41f4b71Sopenharmony_ci                  event.stopPropagation();
664e41f4b71Sopenharmony_ci                })
665e41f4b71Sopenharmony_ci            }
666e41f4b71Sopenharmony_ci            .width('100%')
667e41f4b71Sopenharmony_ci            .justifyContent(FlexAlign.SpaceEvenly)
668e41f4b71Sopenharmony_ci          }
669e41f4b71Sopenharmony_ci        }
670e41f4b71Sopenharmony_ci      }
671e41f4b71Sopenharmony_ci      .width('100%')
672e41f4b71Sopenharmony_ci      .height('100%')
673e41f4b71Sopenharmony_ci      .onTouchIntercept((event : TouchEvent) => {
674e41f4b71Sopenharmony_ci        return HitTestMode.None
675e41f4b71Sopenharmony_ci      })
676e41f4b71Sopenharmony_ci      .onAreaChange((oldValue: Area, newValue: Area) => {
677e41f4b71Sopenharmony_ci        this.view_width = new Number(newValue.width).valueOf()
678e41f4b71Sopenharmony_ci        this.view_height = new Number(newValue.height).valueOf()
679e41f4b71Sopenharmony_ci
680e41f4b71Sopenharmony_ci        this.onSizeChanged(this.video_width, this.video_height);
681e41f4b71Sopenharmony_ci      })
682e41f4b71Sopenharmony_ci    }
683e41f4b71Sopenharmony_ci  }
684e41f4b71Sopenharmony_ci
685e41f4b71Sopenharmony_ci  @Builder
686e41f4b71Sopenharmony_ci  function NativePlayerComponentBuilder(params: Params) {
687e41f4b71Sopenharmony_ci    NativePlayerComponent({ params: params })
688e41f4b71Sopenharmony_ci      .backgroundColor(Color.Green)
689e41f4b71Sopenharmony_ci      .border({ width: 1, color: Color.Brown })
690e41f4b71Sopenharmony_ci      .width('100%')
691e41f4b71Sopenharmony_ci      .height('100%')
692e41f4b71Sopenharmony_ci  }
693e41f4b71Sopenharmony_ci
694e41f4b71Sopenharmony_ci  // Use NodeController to dynamically create a player component and draw the component content on the surface specified by surfaceId.
695e41f4b71Sopenharmony_ci  class MyNodeController extends NodeController {
696e41f4b71Sopenharmony_ci    private rootNode: BuilderNode<[Params]> | undefined;
697e41f4b71Sopenharmony_ci    private isRemove = false;
698e41f4b71Sopenharmony_ci    web_tab: WebComponent
699e41f4b71Sopenharmony_ci    listener: webview.NativeMediaPlayerHandler
700e41f4b71Sopenharmony_ci    player: NativeMediaPlayerImpl
701e41f4b71Sopenharmony_ci
702e41f4b71Sopenharmony_ci    constructor(web_tab: WebComponent, surfaceId: string,  listener: webview.NativeMediaPlayerHandler, player: NativeMediaPlayerImpl, renderType: NodeRenderType) {
703e41f4b71Sopenharmony_ci      super()
704e41f4b71Sopenharmony_ci      this.web_tab = web_tab;
705e41f4b71Sopenharmony_ci      this.listener = listener;
706e41f4b71Sopenharmony_ci      this.player = player;
707e41f4b71Sopenharmony_ci      let uiContext = AppStorage.get<UIContext>("UIContext");
708e41f4b71Sopenharmony_ci      this.rootNode = new BuilderNode(uiContext as UIContext, { surfaceId: surfaceId, type: renderType });
709e41f4b71Sopenharmony_ci    }
710e41f4b71Sopenharmony_ci
711e41f4b71Sopenharmony_ci    makeNode(uiContext: UIContext): FrameNode | null {
712e41f4b71Sopenharmony_ci      if (this.rootNode) {
713e41f4b71Sopenharmony_ci        return this.rootNode.getFrameNode() as FrameNode;
714e41f4b71Sopenharmony_ci      }
715e41f4b71Sopenharmony_ci      return null;
716e41f4b71Sopenharmony_ci    }
717e41f4b71Sopenharmony_ci
718e41f4b71Sopenharmony_ci    build() {
719e41f4b71Sopenharmony_ci      if (this.rootNode) {
720e41f4b71Sopenharmony_ci        this.rootNode.build(wrapBuilder(NativePlayerComponentBuilder),
721e41f4b71Sopenharmony_ci          { "text": "play", "text2": "pause", web_tab: this.web_tab, handler: this.listener, player: this.player})
722e41f4b71Sopenharmony_ci      }
723e41f4b71Sopenharmony_ci    }
724e41f4b71Sopenharmony_ci  }
725e41f4b71Sopenharmony_ci
726e41f4b71Sopenharmony_ci  interface PageBeginParam {
727e41f4b71Sopenharmony_ci    url: string
728e41f4b71Sopenharmony_ci  }
729e41f4b71Sopenharmony_ci
730e41f4b71Sopenharmony_ci  @Entry
731e41f4b71Sopenharmony_ci  @Component
732e41f4b71Sopenharmony_ci  struct WebComponent {
733e41f4b71Sopenharmony_ci    controller: WebviewController = new webview.WebviewController()
734e41f4b71Sopenharmony_ci    nativePlayer? : webview.NativeMediaPlayerBridge
735e41f4b71Sopenharmony_ci    page_url: Resource = $rawfile('main.html')
736e41f4b71Sopenharmony_ci    node_controller?: MyNodeController
737e41f4b71Sopenharmony_ci    @State show_native_media_player: boolean = false;
738e41f4b71Sopenharmony_ci    @State node_width : number = 300;
739e41f4b71Sopenharmony_ci    @State node_height : number = 150;
740e41f4b71Sopenharmony_ci    area?: Area
741e41f4b71Sopenharmony_ci
742e41f4b71Sopenharmony_ci    build() {
743e41f4b71Sopenharmony_ci      Column() {
744e41f4b71Sopenharmony_ci        Stack({alignContent: Alignment.TopStart}) {
745e41f4b71Sopenharmony_ci          if (this.show_native_media_player) {
746e41f4b71Sopenharmony_ci            NodeContainer(this.node_controller)
747e41f4b71Sopenharmony_ci              .width(this.node_width + 'px')
748e41f4b71Sopenharmony_ci              .height(this.node_height + 'px')
749e41f4b71Sopenharmony_ci              .backgroundColor(Color.Transparent)
750e41f4b71Sopenharmony_ci              .border({ width: 2, color: Color.Orange })
751e41f4b71Sopenharmony_ci          }
752e41f4b71Sopenharmony_ci          Web({ src: this.page_url, controller: this.controller })
753e41f4b71Sopenharmony_ci            .enableNativeMediaPlayer({ enable: true, shouldOverlay: true })
754e41f4b71Sopenharmony_ci            .onPageBegin((event: PageBeginParam) => {
755e41f4b71Sopenharmony_ci              this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
756e41f4b71Sopenharmony_ci                console.error('onCreateNativeMediaPlayer(' + JSON.stringify(mediaInfo) + ')');
757e41f4b71Sopenharmony_ci                this.nativePlayer = new NativeMediaPlayerImpl(this, handler, mediaInfo);
758e41f4b71Sopenharmony_ci                return this.nativePlayer;
759e41f4b71Sopenharmony_ci              });
760e41f4b71Sopenharmony_ci            })
761e41f4b71Sopenharmony_ci            .width('100%')
762e41f4b71Sopenharmony_ci            .height('100%')
763e41f4b71Sopenharmony_ci            .onAreaChange((oldValue: Area, newValue: Area) => {
764e41f4b71Sopenharmony_ci              oldValue;
765e41f4b71Sopenharmony_ci              this.area = newValue;
766e41f4b71Sopenharmony_ci            })
767e41f4b71Sopenharmony_ci        }
768e41f4b71Sopenharmony_ci      }
769e41f4b71Sopenharmony_ci    }
770e41f4b71Sopenharmony_ci  }
771e41f4b71Sopenharmony_ci  ```
772e41f4b71Sopenharmony_ci
773e41f4b71Sopenharmony_ci- Example of using video playback on the application side:
774e41f4b71Sopenharmony_ci
775e41f4b71Sopenharmony_ci  ```ts
776e41f4b71Sopenharmony_ci  import { media } from '@kit.MediaKit';
777e41f4b71Sopenharmony_ci  import { common } from '@kit.AbilityKit';
778e41f4b71Sopenharmony_ci  import { BusinessError } from '@kit.BasicServicesKit';
779e41f4b71Sopenharmony_ci
780e41f4b71Sopenharmony_ci  export interface AVPlayerListener {
781e41f4b71Sopenharmony_ci    onPlaying() : void
782e41f4b71Sopenharmony_ci    onPaused() : void
783e41f4b71Sopenharmony_ci    onDurationChanged(duration: number) : void
784e41f4b71Sopenharmony_ci    onBufferedTimeChanged(buffered: number) : void
785e41f4b71Sopenharmony_ci    onTimeUpdate(time: number) : void
786e41f4b71Sopenharmony_ci    onEnded() : void
787e41f4b71Sopenharmony_ci    onError() : void
788e41f4b71Sopenharmony_ci    onVideoSizeChanged(width: number, height: number): void
789e41f4b71Sopenharmony_ci  }
790e41f4b71Sopenharmony_ci
791e41f4b71Sopenharmony_ci  export class AVPlayerDemo {
792e41f4b71Sopenharmony_ci    private surfaceID: string = ''; // The surfaceID parameter specifies the window used to display the video. Its value is obtained through the XComponent.
793e41f4b71Sopenharmony_ci    private isSeek: boolean = true; // Specify whether the seek operation is supported.
794e41f4b71Sopenharmony_ci    private fileSize: number = -1;
795e41f4b71Sopenharmony_ci    private fd: number = 0;
796e41f4b71Sopenharmony_ci
797e41f4b71Sopenharmony_ci    avPlayer?: media.AVPlayer;
798e41f4b71Sopenharmony_ci
799e41f4b71Sopenharmony_ci    setSurfaceID(surface_id: string) {
800e41f4b71Sopenharmony_ci      console.log('setSurfaceID : ' + surface_id)
801e41f4b71Sopenharmony_ci      this.surfaceID = surface_id;
802e41f4b71Sopenharmony_ci    }
803e41f4b71Sopenharmony_ci    // Set AVPlayer callback functions.
804e41f4b71Sopenharmony_ci    setAVPlayerCallback(avPlayer: media.AVPlayer, listener?: AVPlayerListener) {
805e41f4b71Sopenharmony_ci      // Callback function for the seek operation.
806e41f4b71Sopenharmony_ci      avPlayer.on('seekDone', (seekDoneTime: number) => {
807e41f4b71Sopenharmony_ci        console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
808e41f4b71Sopenharmony_ci      })
809e41f4b71Sopenharmony_ci      // Callback function for errors. If an error occurs during the operation on the AVPlayer, reset() is called to reset the AVPlayer.
810e41f4b71Sopenharmony_ci      avPlayer.on('error', (err: BusinessError) => {
811e41f4b71Sopenharmony_ci        console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
812e41f4b71Sopenharmony_ci        listener?.onError();
813e41f4b71Sopenharmony_ci        avPlayer.reset(); // Call reset() to reset the AVPlayer, which enters the idle state.
814e41f4b71Sopenharmony_ci      })
815e41f4b71Sopenharmony_ci      // Callback function for state changes.
816e41f4b71Sopenharmony_ci      avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
817e41f4b71Sopenharmony_ci        switch (state) {
818e41f4b71Sopenharmony_ci          case 'idle': // This state is reported upon a successful callback of reset().
819e41f4b71Sopenharmony_ci            console.info('AVPlayer state idle called.');
820e41f4b71Sopenharmony_ci            avPlayer.release(); // Call release() to release the instance.
821e41f4b71Sopenharmony_ci            break;
822e41f4b71Sopenharmony_ci          case 'initialized': // This state is reported when the AVPlayer sets the playback source.
823e41f4b71Sopenharmony_ci            console.info('AVPlayer state initialized called.');
824e41f4b71Sopenharmony_ci            avPlayer.surfaceId = this.surfaceID; // Set the window to display the video. This setting is not required when a pure audio asset is to be played.
825e41f4b71Sopenharmony_ci            avPlayer.prepare();
826e41f4b71Sopenharmony_ci            break;
827e41f4b71Sopenharmony_ci          case 'prepared': // This state is reported upon a successful callback of prepare().
828e41f4b71Sopenharmony_ci            console.info('AVPlayer state prepared called.');
829e41f4b71Sopenharmony_ci            //avPlayer.play();
830e41f4b71Sopenharmony_ci            break;
831e41f4b71Sopenharmony_ci          case 'playing': // This state is reported upon a successful callback of play().
832e41f4b71Sopenharmony_ci            console.info('AVPlayer state playing called.');
833e41f4b71Sopenharmony_ci            listener?.onPlaying();
834e41f4b71Sopenharmony_ci            break;
835e41f4b71Sopenharmony_ci          case 'paused': // This state is reported upon a successful callback of pause().
836e41f4b71Sopenharmony_ci            console.info('AVPlayer state paused called.');
837e41f4b71Sopenharmony_ci            listener?.onPaused();
838e41f4b71Sopenharmony_ci            break;
839e41f4b71Sopenharmony_ci          case 'completed': // This state is reported upon the completion of the playback.
840e41f4b71Sopenharmony_ci            console.info('AVPlayer state completed called.');
841e41f4b71Sopenharmony_ci            avPlayer.stop(); // Call stop() to stop the playback.
842e41f4b71Sopenharmony_ci            //avPlayer.seek(0);
843e41f4b71Sopenharmony_ci            //avPlayer.play();
844e41f4b71Sopenharmony_ci            break;
845e41f4b71Sopenharmony_ci          case 'stopped': // This state is reported upon a successful callback of stop().
846e41f4b71Sopenharmony_ci            console.info('AVPlayer state stopped called.');
847e41f4b71Sopenharmony_ci            listener?.onEnded();
848e41f4b71Sopenharmony_ci            avPlayer.reset(); // Call reset() to reset the AVPlayer.
849e41f4b71Sopenharmony_ci            break;
850e41f4b71Sopenharmony_ci          case 'released':
851e41f4b71Sopenharmony_ci            console.info('AVPlayer state released called.');
852e41f4b71Sopenharmony_ci            break;
853e41f4b71Sopenharmony_ci          default:
854e41f4b71Sopenharmony_ci            console.info('AVPlayer state unknown called.');
855e41f4b71Sopenharmony_ci            break;
856e41f4b71Sopenharmony_ci        }
857e41f4b71Sopenharmony_ci      })
858e41f4b71Sopenharmony_ci      avPlayer.on('durationUpdate', (duration: number) => {
859e41f4b71Sopenharmony_ci        console.info('AVPlayer state durationUpdate success,new duration is :' + duration)
860e41f4b71Sopenharmony_ci        listener?.onDurationChanged(duration/1000);
861e41f4b71Sopenharmony_ci      })
862e41f4b71Sopenharmony_ci      avPlayer.on('timeUpdate', (time:number) => {
863e41f4b71Sopenharmony_ci        listener?.onTimeUpdate(time/1000);
864e41f4b71Sopenharmony_ci      })
865e41f4b71Sopenharmony_ci      avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => {
866e41f4b71Sopenharmony_ci        console.info('AVPlayer state bufferingUpdate success,and infoType value is:' + infoType + ', value is :' + value)
867e41f4b71Sopenharmony_ci        if (infoType == media.BufferingInfoType.BUFFERING_PERCENT) {
868e41f4b71Sopenharmony_ci        }
869e41f4b71Sopenharmony_ci        listener?.onBufferedTimeChanged(value);
870e41f4b71Sopenharmony_ci      })
871e41f4b71Sopenharmony_ci      avPlayer.on('videoSizeChange', (width: number, height: number) => {
872e41f4b71Sopenharmony_ci        console.info('AVPlayer state videoSizeChange success,and width is:' + width + ', height is :' + height)
873e41f4b71Sopenharmony_ci        listener?.onVideoSizeChanged(width, height);
874e41f4b71Sopenharmony_ci      })
875e41f4b71Sopenharmony_ci    }
876e41f4b71Sopenharmony_ci
877e41f4b71Sopenharmony_ci    // The following demo shows how to play live streams by setting the network address through the URL.
878e41f4b71Sopenharmony_ci    async avPlayerLiveDemo(url: string, listener?: AVPlayerListener) {
879e41f4b71Sopenharmony_ci      // Create an AVPlayer instance.
880e41f4b71Sopenharmony_ci      this.avPlayer = await media.createAVPlayer();
881e41f4b71Sopenharmony_ci      // Set a callback function for state changes.
882e41f4b71Sopenharmony_ci      this.setAVPlayerCallback(this.avPlayer, listener);
883e41f4b71Sopenharmony_ci      this.isSeek = false; // The seek operation is not supported.
884e41f4b71Sopenharmony_ci      this.avPlayer.url = url;
885e41f4b71Sopenharmony_ci    }
886e41f4b71Sopenharmony_ci
887e41f4b71Sopenharmony_ci    play() {
888e41f4b71Sopenharmony_ci      console.info('AVPlayer.play()');
889e41f4b71Sopenharmony_ci      this.avPlayer?.play()
890e41f4b71Sopenharmony_ci    }
891e41f4b71Sopenharmony_ci    pause() {
892e41f4b71Sopenharmony_ci      console.info('AVPlayer.pause()');
893e41f4b71Sopenharmony_ci      this.avPlayer?.pause()
894e41f4b71Sopenharmony_ci    }
895e41f4b71Sopenharmony_ci    release() {
896e41f4b71Sopenharmony_ci      console.info('AVPlayer.release()');
897e41f4b71Sopenharmony_ci      this.avPlayer?.release();
898e41f4b71Sopenharmony_ci    }
899e41f4b71Sopenharmony_ci    seek(time: number) {
900e41f4b71Sopenharmony_ci      console.info('AVPlayer.seek(' + time + ')');
901e41f4b71Sopenharmony_ci      this.avPlayer?.seek(time * 1000);
902e41f4b71Sopenharmony_ci    }
903e41f4b71Sopenharmony_ci  }
904e41f4b71Sopenharmony_ci  ```
905e41f4b71Sopenharmony_ci
906e41f4b71Sopenharmony_ci- Frontend page example.
907e41f4b71Sopenharmony_ci
908e41f4b71Sopenharmony_ci  ```html
909e41f4b71Sopenharmony_ci  <html>
910e41f4b71Sopenharmony_ci  <head>
911e41f4b71Sopenharmony_ci      <title>Video Hosting Test html</title>
912e41f4b71Sopenharmony_ci      <meta name="viewport" content="width=device-width">
913e41f4b71Sopenharmony_ci  </head>
914e41f4b71Sopenharmony_ci  <body>
915e41f4b71Sopenharmony_ci  <div>
916e41f4b71Sopenharmony_ci    <video src='https://media.w3.org/2010/05/sintel/trailer.mp4'></video>
917e41f4b71Sopenharmony_ci  </div>
918e41f4b71Sopenharmony_ci  </body>
919e41f4b71Sopenharmony_ci  </html>
920e41f4b71Sopenharmony_ci  ```
921