1e41f4b71Sopenharmony_ci# Rendering and Drawing Video and Button Components at the Same Layer
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ciWith the same-layer rendering feature of ArkWeb, you can render and draw native components at the same layer as the **\<Web>** component for your application. For details about the components that support same-layer rendering, see [NodeRenderType](../reference/apis-arkui/js-apis-arkui-builderNode.md#noderendertype).
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci- To start with, add the Internet permission to the **module.json5** file. For details, see [Declaring Permissions in the Configuration File](../security/AccessToken/declare-permissions.md).
6e41f4b71Sopenharmony_ci  
7e41f4b71Sopenharmony_ci   ```
8e41f4b71Sopenharmony_ci   "requestPermissions":[
9e41f4b71Sopenharmony_ci      {
10e41f4b71Sopenharmony_ci        "name" : "ohos.permission.INTERNET"
11e41f4b71Sopenharmony_ci      }
12e41f4b71Sopenharmony_ci    ]
13e41f4b71Sopenharmony_ci   ```
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci## Constraints
16e41f4b71Sopenharmony_ciThe following constraints apply when same-layer rendering is used:
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ci- W3C standards-based tags cannot be defined as tags for same-layer rendering.
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci- The **<object>** tags and **\<embed>** tags cannot be configured for same-layer rendering at the same time.
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci- To deliver best possible performance, keep the number of tags at the same layer on a page within five.
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci- The maximum height of tags at the same layer is 8192 px, and the maximum texture size is 8192 px.
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci- Only one nesting level is supported for the **\<Web>** component. If multiple nesting levels are detected, an error message is displayed.
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci- The touchscreen events supported in the region for same-layer rendering include swiping, taping, scaling, and long pressing, while dragging is not supported.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci- When same-layer rendering is enabled, web pages opened by the **\<Web>** component do not support the pinch gesture or scale APIs, including [initialScale](../reference/apis-arkweb/ts-basic-components-web.md#initialscale), [zoom](../reference/apis-arkweb/js-apis-webview.md#zoom), [zoomIn](../reference/apis-arkweb/js-apis-webview.md#zoomin), and [zoomOut](../reference/apis-arkweb/js-apis-webview.md#zoomout).
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci- The region for same-layer rendering does not support mouse, keyboard, and touchpad events.
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci- When same-layer rendering is enabled, web pages opened by the **\<Web>** component do not support the unified rendering mode [RenderMode](../reference/apis-arkweb/ts-basic-components-web.md#rendermode).
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci## Drawing the XComponent+AVPlayer and Button Components
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ci### Enabling Same-Layer Rendering
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ciYou can enable or disable same-layer rendering through [enableNativeEmbedMode()](../reference/apis-arkweb/ts-basic-components-web.md#enablenativeembedmode11). To use same-layer rendering, the **\<embed>** element must be explicitly used in the HTML file, and the **type** attribute of the element must start with **native/**. The background of the elements corresponding to the tags at the same layer is transparent.
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci- Example of using same-layer rendering on the application side:
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci  ```ts
46e41f4b71Sopenharmony_ci  // HAP's src/main/ets/pages/Index.ets
47e41f4b71Sopenharmony_ci  // Create a NodeController instance.
48e41f4b71Sopenharmony_ci  import { webview } from '@kit.ArkWeb';
49e41f4b71Sopenharmony_ci  import { UIContext, NodeController, BuilderNode, NodeRenderType, FrameNode } from "@kit.ArkUI";
50e41f4b71Sopenharmony_ci  import { AVPlayerDemo } from './PlayerDemo';
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ci  @Observed
53e41f4b71Sopenharmony_ci  declare class Params {
54e41f4b71Sopenharmony_ci    textOne : string
55e41f4b71Sopenharmony_ci    textTwo : string
56e41f4b71Sopenharmony_ci    width : number
57e41f4b71Sopenharmony_ci    height : number
58e41f4b71Sopenharmony_ci  }
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ci  declare class nodeControllerParams {
61e41f4b71Sopenharmony_ci    surfaceId : string
62e41f4b71Sopenharmony_ci    type : string
63e41f4b71Sopenharmony_ci    renderType : NodeRenderType
64e41f4b71Sopenharmony_ci    embedId : string
65e41f4b71Sopenharmony_ci    width : number
66e41f4b71Sopenharmony_ci    height : number
67e41f4b71Sopenharmony_ci  }
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci  // The NodeController instance must be used with a NodeContainer for controlling and feeding back the behavior of the nodes in the container.
70e41f4b71Sopenharmony_ci  class MyNodeController extends NodeController {
71e41f4b71Sopenharmony_ci    private rootNode: BuilderNode<[Params]> | undefined | null;
72e41f4b71Sopenharmony_ci    private embedId_ : string = "";
73e41f4b71Sopenharmony_ci    private surfaceId_ : string = "";
74e41f4b71Sopenharmony_ci    private renderType_ :NodeRenderType = NodeRenderType.RENDER_TYPE_DISPLAY;
75e41f4b71Sopenharmony_ci    private width_ : number = 0;
76e41f4b71Sopenharmony_ci    private height_ : number = 0;
77e41f4b71Sopenharmony_ci    private type_ : string = "";
78e41f4b71Sopenharmony_ci    private isDestroy_ : boolean = false;
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci    setRenderOption(params : nodeControllerParams) {
81e41f4b71Sopenharmony_ci      this.surfaceId_ = params.surfaceId;
82e41f4b71Sopenharmony_ci      this.renderType_ = params.renderType;
83e41f4b71Sopenharmony_ci      this.embedId_ = params.embedId;
84e41f4b71Sopenharmony_ci      this.width_ = params.width;
85e41f4b71Sopenharmony_ci      this.height_ = params.height;
86e41f4b71Sopenharmony_ci      this.type_ = params.type;
87e41f4b71Sopenharmony_ci    }
88e41f4b71Sopenharmony_ci    // Method that must be overridden. It is used to build the number of nodes and return the number of nodes that will be mounted to the corresponding NodeContainer.
89e41f4b71Sopenharmony_ci    // Called when the corresponding NodeContainer is created or called by the rebuild method.
90e41f4b71Sopenharmony_ci    makeNode(uiContext: UIContext): FrameNode | null{
91e41f4b71Sopenharmony_ci      if (this.isDestroy_) { // rootNode is null.
92e41f4b71Sopenharmony_ci        return null;
93e41f4b71Sopenharmony_ci      }
94e41f4b71Sopenharmony_ci      if (!this.rootNode) { // When rootNode is set to undefined
95e41f4b71Sopenharmony_ci        this.rootNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId_, type: this.renderType_});
96e41f4b71Sopenharmony_ci        if (this.type_ === 'native/video') {
97e41f4b71Sopenharmony_ci          this.rootNode.build(wrapBuilder(VideoBuilder), {textOne: "myButton", width : this.width_, height : this.height_});
98e41f4b71Sopenharmony_ci        } else {
99e41f4b71Sopenharmony_ci          // other
100e41f4b71Sopenharmony_ci        }
101e41f4b71Sopenharmony_ci      }
102e41f4b71Sopenharmony_ci      // Return the FrameNode object.
103e41f4b71Sopenharmony_ci      return this.rootNode.getFrameNode();
104e41f4b71Sopenharmony_ci    }
105e41f4b71Sopenharmony_ci
106e41f4b71Sopenharmony_ci    setBuilderNode(rootNode: BuilderNode<Params[]> | null): void{
107e41f4b71Sopenharmony_ci      this.rootNode = rootNode;
108e41f4b71Sopenharmony_ci    }
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ci    getBuilderNode(): BuilderNode<[Params]> | undefined | null{
111e41f4b71Sopenharmony_ci      return this.rootNode;
112e41f4b71Sopenharmony_ci    }
113e41f4b71Sopenharmony_ci
114e41f4b71Sopenharmony_ci    updateNode(arg: Object): void {
115e41f4b71Sopenharmony_ci      this.rootNode?.update(arg);
116e41f4b71Sopenharmony_ci    }
117e41f4b71Sopenharmony_ci    getEmbedId() : string {
118e41f4b71Sopenharmony_ci      return this.embedId_;
119e41f4b71Sopenharmony_ci    }
120e41f4b71Sopenharmony_ci
121e41f4b71Sopenharmony_ci    setDestroy(isDestroy : boolean) : void {
122e41f4b71Sopenharmony_ci      this.isDestroy_ = isDestroy;
123e41f4b71Sopenharmony_ci      if (this.isDestroy_) {
124e41f4b71Sopenharmony_ci        this.rootNode = null;
125e41f4b71Sopenharmony_ci      }
126e41f4b71Sopenharmony_ci    }
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci    postEvent(event: TouchEvent | undefined) : boolean {
129e41f4b71Sopenharmony_ci      return this.rootNode?.postTouchEvent(event) as boolean
130e41f4b71Sopenharmony_ci    }
131e41f4b71Sopenharmony_ci  }
132e41f4b71Sopenharmony_ci
133e41f4b71Sopenharmony_ci  @Component
134e41f4b71Sopenharmony_ci  struct VideoComponent {
135e41f4b71Sopenharmony_ci    @ObjectLink params: Params
136e41f4b71Sopenharmony_ci    @State bkColor: Color = Color.Red
137e41f4b71Sopenharmony_ci    mXComponentController: XComponentController = new XComponentController();
138e41f4b71Sopenharmony_ci    @State player_changed: boolean = false;
139e41f4b71Sopenharmony_ci    player?: AVPlayerDemo;
140e41f4b71Sopenharmony_ci
141e41f4b71Sopenharmony_ci    build() {
142e41f4b71Sopenharmony_ci      Column() {
143e41f4b71Sopenharmony_ci        Button(this.params.textOne)
144e41f4b71Sopenharmony_ci
145e41f4b71Sopenharmony_ci        XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController})
146e41f4b71Sopenharmony_ci          .border({width: 1, color: Color.Red})
147e41f4b71Sopenharmony_ci          .onLoad(() => {
148e41f4b71Sopenharmony_ci            this.player = new AVPlayerDemo();
149e41f4b71Sopenharmony_ci            this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId());
150e41f4b71Sopenharmony_ci            this.player_changed = !this.player_changed;
151e41f4b71Sopenharmony_ci            this.player.avPlayerLiveDemo()
152e41f4b71Sopenharmony_ci          })
153e41f4b71Sopenharmony_ci          .width(300)
154e41f4b71Sopenharmony_ci          .height(200)
155e41f4b71Sopenharmony_ci      }
156e41f4b71Sopenharmony_ci      // The width and height of the outermost container in the custom component must be the width and height of the tag at the same layer.
157e41f4b71Sopenharmony_ci      .width(this.params.width)
158e41f4b71Sopenharmony_ci      .height(this.params.height)
159e41f4b71Sopenharmony_ci    }
160e41f4b71Sopenharmony_ci  }
161e41f4b71Sopenharmony_ci  // In @Builder, add the specific dynamic component content.
162e41f4b71Sopenharmony_ci  @Builder
163e41f4b71Sopenharmony_ci  function VideoBuilder(params: Params) {
164e41f4b71Sopenharmony_ci    VideoComponent({ params: params })
165e41f4b71Sopenharmony_ci      .backgroundColor(Color.Gray)
166e41f4b71Sopenharmony_ci  }
167e41f4b71Sopenharmony_ci
168e41f4b71Sopenharmony_ci  @Entry
169e41f4b71Sopenharmony_ci  @Component
170e41f4b71Sopenharmony_ci  struct WebIndex {
171e41f4b71Sopenharmony_ci    browserTabController: WebviewController = new webview.WebviewController()
172e41f4b71Sopenharmony_ci    private nodeControllerMap: Map<string, MyNodeController> = new Map();
173e41f4b71Sopenharmony_ci    @State componentIdArr: Array<string> = [];
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci    aboutToAppear() {
176e41f4b71Sopenharmony_ci      // Enable web frontend page debugging.
177e41f4b71Sopenharmony_ci      webview.WebviewController.setWebDebuggingAccess(true);
178e41f4b71Sopenharmony_ci    }
179e41f4b71Sopenharmony_ci
180e41f4b71Sopenharmony_ci    build(){
181e41f4b71Sopenharmony_ci      Row() {
182e41f4b71Sopenharmony_ci        Column() {
183e41f4b71Sopenharmony_ci          Stack() {
184e41f4b71Sopenharmony_ci            ForEach(this.componentIdArr, (componentId: string) => {
185e41f4b71Sopenharmony_ci              NodeContainer(this.nodeControllerMap.get(componentId))
186e41f4b71Sopenharmony_ci            }, (embedId: string) => embedId)
187e41f4b71Sopenharmony_ci            // Load the local test.html page.
188e41f4b71Sopenharmony_ci            Web({ src: $rawfile("test.html"), controller: this.browserTabController })
189e41f4b71Sopenharmony_ci                // Enable same-layer rendering.
190e41f4b71Sopenharmony_ci              .enableNativeEmbedMode(true)
191e41f4b71Sopenharmony_ci                // Obtain the lifecycle change data of the embed element.
192e41f4b71Sopenharmony_ci              .onNativeEmbedLifecycleChange((embed) => {
193e41f4b71Sopenharmony_ci                console.log("NativeEmbed surfaceId" + embed.surfaceId);
194e41f4b71Sopenharmony_ci                // 1. If embed.info.id is used as the key for mapping nodeController, explicitly specify the ID on the HTML5 page.
195e41f4b71Sopenharmony_ci                const componentId = embed.info?.id?.toString() as string
196e41f4b71Sopenharmony_ci                if (embed.status == NativeEmbedStatus.CREATE) {
197e41f4b71Sopenharmony_ci                  console.log("NativeEmbed create" + JSON.stringify(embed.info))
198e41f4b71Sopenharmony_ci                  // Create a NodeController instance, set parameters, and rebuild.
199e41f4b71Sopenharmony_ci                  let nodeController = new MyNodeController()
200e41f4b71Sopenharmony_ci                  // 1. The unit of embed.info.width and embed.info.height is px, which needs to be converted to the default unit vp on the ets side.
201e41f4b71Sopenharmony_ci                  nodeController.setRenderOption({surfaceId : embed.surfaceId as string, type : embed.info?.type as string,
202e41f4b71Sopenharmony_ci                    renderType : NodeRenderType.RENDER_TYPE_TEXTURE, embedId : embed.embedId as string,
203e41f4b71Sopenharmony_ci                    width : px2vp(embed.info?.width), height : px2vp(embed.info?.height)})
204e41f4b71Sopenharmony_ci                  nodeController.setDestroy(false);
205e41f4b71Sopenharmony_ci                  // Save the NodeController instance to the map, with the ID attribute of the embed element passed in by the Web component as the key.
206e41f4b71Sopenharmony_ci                  this.nodeControllerMap.set(componentId, nodeController)
207e41f4b71Sopenharmony_ci                  // Save the ID attribute of the embed element passed in by the Web component to the @State decorated array variable for creating a node container dynamically. The push action must be executed after the set action.
208e41f4b71Sopenharmony_ci                  this.componentIdArr.push(componentId)
209e41f4b71Sopenharmony_ci                } else if (embed.status == NativeEmbedStatus.UPDATE) {
210e41f4b71Sopenharmony_ci                  let nodeController = this.nodeControllerMap.get(componentId)
211e41f4b71Sopenharmony_ci                  nodeController?.updateNode({textOne: 'update', width: px2vp(embed.info?.width), height: px2vp(embed.info?.height)} as ESObject)
212e41f4b71Sopenharmony_ci                } else {
213e41f4b71Sopenharmony_ci                  let nodeController = this.nodeControllerMap.get(componentId);
214e41f4b71Sopenharmony_ci                  nodeController?.setDestroy(true)
215e41f4b71Sopenharmony_ci                  this.nodeControllerMap.clear();
216e41f4b71Sopenharmony_ci                  this.componentIdArr.length = 0;
217e41f4b71Sopenharmony_ci                }
218e41f4b71Sopenharmony_ci              })// Obtain the touch event information of components for same-layer rendering.
219e41f4b71Sopenharmony_ci              .onNativeEmbedGestureEvent((touch) => {
220e41f4b71Sopenharmony_ci                console.log("NativeEmbed onNativeEmbedGestureEvent" + JSON.stringify(touch.touchEvent));
221e41f4b71Sopenharmony_ci                this.componentIdArr.forEach((componentId: string) => {
222e41f4b71Sopenharmony_ci                  let nodeController = this.nodeControllerMap.get(componentId)
223e41f4b71Sopenharmony_ci                  // Send the obtained event of the region at the same layer to the nodeController corresponding to embedId of the region.
224e41f4b71Sopenharmony_ci                  if (nodeController?.getEmbedId() === touch.embedId) {
225e41f4b71Sopenharmony_ci                    let ret = nodeController?.postEvent(touch.touchEvent)
226e41f4b71Sopenharmony_ci                    if (ret) {
227e41f4b71Sopenharmony_ci                      console.log("onNativeEmbedGestureEvent success " + componentId)
228e41f4b71Sopenharmony_ci                    } else {
229e41f4b71Sopenharmony_ci                      console.log("onNativeEmbedGestureEvent fail " + componentId)
230e41f4b71Sopenharmony_ci                    }
231e41f4b71Sopenharmony_ci                    if (touch.result) {
232e41f4b71Sopenharmony_ci                      // Notify the <Web> component of the gesture event consumption result.
233e41f4b71Sopenharmony_ci                      touch.result.setGestureEventResult(ret);
234e41f4b71Sopenharmony_ci                    }
235e41f4b71Sopenharmony_ci                  }
236e41f4b71Sopenharmony_ci                })
237e41f4b71Sopenharmony_ci              })
238e41f4b71Sopenharmony_ci          }
239e41f4b71Sopenharmony_ci        }
240e41f4b71Sopenharmony_ci      }
241e41f4b71Sopenharmony_ci    }
242e41f4b71Sopenharmony_ci  }
243e41f4b71Sopenharmony_ci  ```
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci- Example of using video playback on the application side:
246e41f4b71Sopenharmony_ci
247e41f4b71Sopenharmony_ci  ```ts
248e41f4b71Sopenharmony_ci  // HAP's src/main/ets/pages/PlayerDemo.ets
249e41f4b71Sopenharmony_ci  import { media } from '@kit.MediaKit';
250e41f4b71Sopenharmony_ci  import { BusinessError } from '@ohos.base';
251e41f4b71Sopenharmony_ci
252e41f4b71Sopenharmony_ci  export class AVPlayerDemo {
253e41f4b71Sopenharmony_ci    private count: number = 0;
254e41f4b71Sopenharmony_ci    private surfaceID: string = ''; // The surfaceID parameter specifies the window used to display the video. Its value is obtained through XComponent.
255e41f4b71Sopenharmony_ci    private isSeek: boolean = true; // Specify whether the seek operation is supported.
256e41f4b71Sopenharmony_ci
257e41f4b71Sopenharmony_ci    setSurfaceID(surface_id: string){
258e41f4b71Sopenharmony_ci      console.log('setSurfaceID : ' + surface_id);
259e41f4b71Sopenharmony_ci      this.surfaceID = surface_id;
260e41f4b71Sopenharmony_ci    }
261e41f4b71Sopenharmony_ci    // Set AVPlayer callback functions.
262e41f4b71Sopenharmony_ci    setAVPlayerCallback(avPlayer: media.AVPlayer) {
263e41f4b71Sopenharmony_ci      // Callback function for the seek operation.
264e41f4b71Sopenharmony_ci      avPlayer.on('seekDone', (seekDoneTime: number) => {
265e41f4b71Sopenharmony_ci        console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
266e41f4b71Sopenharmony_ci      })
267e41f4b71Sopenharmony_ci      // Callback function for errors. If an error occurs during the operation on the AVPlayer, reset() is called to reset the AVPlayer.
268e41f4b71Sopenharmony_ci      avPlayer.on('error', (err: BusinessError) => {
269e41f4b71Sopenharmony_ci        console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
270e41f4b71Sopenharmony_ci        avPlayer.reset();
271e41f4b71Sopenharmony_ci      })
272e41f4b71Sopenharmony_ci      // Callback function for state changes.
273e41f4b71Sopenharmony_ci      avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
274e41f4b71Sopenharmony_ci        switch (state) {
275e41f4b71Sopenharmony_ci          case 'idle': // This state is reported upon a successful callback of reset().
276e41f4b71Sopenharmony_ci            console.info('AVPlayer state idle called.');
277e41f4b71Sopenharmony_ci            avPlayer.release(); // Call release() to release the instance.
278e41f4b71Sopenharmony_ci            break;
279e41f4b71Sopenharmony_ci          case 'initialized': // This state is reported when the AVPlayer sets the playback source.
280e41f4b71Sopenharmony_ci            console.info('AVPlayer state initialized called.');
281e41f4b71Sopenharmony_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.
282e41f4b71Sopenharmony_ci            avPlayer.prepare();
283e41f4b71Sopenharmony_ci            break;
284e41f4b71Sopenharmony_ci          case 'prepared': // This state is reported upon a successful callback of prepare().
285e41f4b71Sopenharmony_ci            console.info('AVPlayer state prepared called.');
286e41f4b71Sopenharmony_ci            avPlayer.play(); // Call play() to start playback.
287e41f4b71Sopenharmony_ci            break;
288e41f4b71Sopenharmony_ci          case 'playing': // This state is reported upon a successful callback of play().
289e41f4b71Sopenharmony_ci            console.info('AVPlayer state prepared called.');
290e41f4b71Sopenharmony_ci            if(this.count !== 0) {
291e41f4b71Sopenharmony_ci              if (this.isSeek) {
292e41f4b71Sopenharmony_ci                console.info('AVPlayer start to seek.');
293e41f4b71Sopenharmony_ci                avPlayer.seek(avPlayer.duration); // Call seek() to seek to the end of the video clip.
294e41f4b71Sopenharmony_ci              } else {
295e41f4b71Sopenharmony_ci                // When the seek operation is not supported, the playback continues until it reaches the end.
296e41f4b71Sopenharmony_ci                console.info('AVPlayer wait to play end.');
297e41f4b71Sopenharmony_ci              }
298e41f4b71Sopenharmony_ci            } else {
299e41f4b71Sopenharmony_ci              avPlayer.pause(); // Call pause() to pause the playback.
300e41f4b71Sopenharmony_ci            }
301e41f4b71Sopenharmony_ci            this.count++;
302e41f4b71Sopenharmony_ci            break;
303e41f4b71Sopenharmony_ci          case 'paused': // This state is reported upon a successful callback of pause().
304e41f4b71Sopenharmony_ci            console.info('AVPlayer state paused called.');
305e41f4b71Sopenharmony_ci            avPlayer.play(); // Call play() again to start playback.
306e41f4b71Sopenharmony_ci            break;
307e41f4b71Sopenharmony_ci          case 'completed': // This state is reported upon the completion of the playback.
308e41f4b71Sopenharmony_ci            console.info('AVPlayer state paused called.');
309e41f4b71Sopenharmony_ci            avPlayer.stop(); // Call stop() to stop the playback.
310e41f4b71Sopenharmony_ci            break;
311e41f4b71Sopenharmony_ci          case 'stopped': // This state is reported upon a successful callback of stop().
312e41f4b71Sopenharmony_ci            console.info('AVPlayer state stopped called.');
313e41f4b71Sopenharmony_ci            avPlayer.reset(); // Call reset() to reset the AVPlayer.
314e41f4b71Sopenharmony_ci            break;
315e41f4b71Sopenharmony_ci          case 'released': // This state is reported upon the release of the AVPlayer.
316e41f4b71Sopenharmony_ci            console.info('AVPlayer state released called.');
317e41f4b71Sopenharmony_ci            break;
318e41f4b71Sopenharmony_ci          default:
319e41f4b71Sopenharmony_ci            break;
320e41f4b71Sopenharmony_ci        }
321e41f4b71Sopenharmony_ci      })
322e41f4b71Sopenharmony_ci    }
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci    // Set the live stream source through the URL.
325e41f4b71Sopenharmony_ci    async avPlayerLiveDemo(){
326e41f4b71Sopenharmony_ci      // Create an AVPlayer instance.
327e41f4b71Sopenharmony_ci      let avPlayer: media.AVPlayer = await media.createAVPlayer();
328e41f4b71Sopenharmony_ci      // Set a callback function for state changes.
329e41f4b71Sopenharmony_ci      this.setAVPlayerCallback(avPlayer);
330e41f4b71Sopenharmony_ci      this.isSeek = false; // The seek operation is not supported.
331e41f4b71Sopenharmony_ci      // Replace the URL with the actual URL of the video source.
332e41f4b71Sopenharmony_ci      avPlayer.url = 'https://xxx.xxx/demo.mp4';
333e41f4b71Sopenharmony_ci    }
334e41f4b71Sopenharmony_ci  }
335e41f4b71Sopenharmony_ci  ```
336e41f4b71Sopenharmony_ci
337e41f4b71Sopenharmony_ci- Example of the frontend page:
338e41f4b71Sopenharmony_ci
339e41f4b71Sopenharmony_ci  ```html
340e41f4b71Sopenharmony_ci  <!--HAP's src/main/resources/rawfile/test.html-->
341e41f4b71Sopenharmony_ci  <!DOCTYPE html>
342e41f4b71Sopenharmony_ci  <html>
343e41f4b71Sopenharmony_ci  <head>
344e41f4b71Sopenharmony_ci      <title>Same-layer rendering test html</title>
345e41f4b71Sopenharmony_ci      <meta name="viewport">
346e41f4b71Sopenharmony_ci  </head>
347e41f4b71Sopenharmony_ci  <body>
348e41f4b71Sopenharmony_ci  <div>
349e41f4b71Sopenharmony_ci      <div id="bodyId">
350e41f4b71Sopenharmony_ci          <embed id="nativeVideo" type = "native/video" width="1000" height="1500" src="test" style = "background-color:red"/>
351e41f4b71Sopenharmony_ci      </div>
352e41f4b71Sopenharmony_ci  </div>
353e41f4b71Sopenharmony_ci  </body>
354e41f4b71Sopenharmony_ci  </html>
355e41f4b71Sopenharmony_ci  ```
356e41f4b71Sopenharmony_ci  
357e41f4b71Sopenharmony_ci  ![web-same-layer](figures/web-same-layer.png)
358e41f4b71Sopenharmony_ci
359e41f4b71Sopenharmony_ci### Enabling Same-Layer Rendering and Specifying the Label Name and Custom Type
360e41f4b71Sopenharmony_ci
361e41f4b71Sopenharmony_ciYou can also use [registerNativeEmbedRule(tag: string, type: string)](../reference/apis-arkweb/ts-basic-components-web.md#registernativeembedrule12) to specify the tag and type.
362e41f4b71Sopenharmony_ci
363e41f4b71Sopenharmony_ciFor the **tag** parameter, only **embed** and **object** are supported. For the **type** parameter, you can specify any string. These two parameters are case insensitive: The ArkWeb kernel converts the values into lowercase letters. The **tag** parameter uses the full string for matching, and **type** uses the prefix for matching.
364e41f4b71Sopenharmony_ci
365e41f4b71Sopenharmony_ciIf you do not use this API or the API receives an invalid string (for example, an empty string), the kernel uses the default prefix mode "embed" + "native/". If the specified type is the same as any object or embedded type defined by W3C, as in **registerNativeEmbedRule("object", "application/pdf")**,
366e41f4b71Sopenharmony_ciArkWeb will follow the W3C standard behavior and will not identify it as a tag at the same layer.
367e41f4b71Sopenharmony_ci
368e41f4b71Sopenharmony_ci- Example of using **registerNativeEmbedRule** on the application side: 
369e41f4b71Sopenharmony_ci
370e41f4b71Sopenharmony_ci  ```ts
371e41f4b71Sopenharmony_ci  class MyNodeController extends NodeController {
372e41f4b71Sopenharmony_ci    ...
373e41f4b71Sopenharmony_ci    makeNode(uiContext: UIContext): FrameNode | null{
374e41f4b71Sopenharmony_ci
375e41f4b71Sopenharmony_ci      if (this.type_ === 'test') {
376e41f4b71Sopenharmony_ci        ...
377e41f4b71Sopenharmony_ci      } else if (this.type_ === 'test/video') {
378e41f4b71Sopenharmony_ci        ...
379e41f4b71Sopenharmony_ci      } else {
380e41f4b71Sopenharmony_ci        // other
381e41f4b71Sopenharmony_ci      }
382e41f4b71Sopenharmony_ci	  ...
383e41f4b71Sopenharmony_ci    }
384e41f4b71Sopenharmony_ci    ...
385e41f4b71Sopenharmony_ci  }
386e41f4b71Sopenharmony_ci  ...
387e41f4b71Sopenharmony_ci
388e41f4b71Sopenharmony_ci    build(){
389e41f4b71Sopenharmony_ci        ...
390e41f4b71Sopenharmony_ci          Stack() {
391e41f4b71Sopenharmony_ci            ...
392e41f4b71Sopenharmony_ci            Web({ src: $rawfile("test.html"), controller: this.browserTabController })
393e41f4b71Sopenharmony_ci               // Enable same-layer rendering.
394e41f4b71Sopenharmony_ci              .enableNativeEmbedMode(true)
395e41f4b71Sopenharmony_ci               // Register the same-layer tag of "object" and type of "test."
396e41f4b71Sopenharmony_ci              .registerNativeEmbedRule("object", "test")
397e41f4b71Sopenharmony_ci              ...
398e41f4b71Sopenharmony_ci		  }
399e41f4b71Sopenharmony_ci		...
400e41f4b71Sopenharmony_ci	}
401e41f4b71Sopenharmony_ci
402e41f4b71Sopenharmony_ci  ```
403e41f4b71Sopenharmony_ci
404e41f4b71Sopenharmony_ci- Example of using **registerNativeEmbedRule** on the frontend page, with the tag of "object" and type of "test":
405e41f4b71Sopenharmony_ci
406e41f4b71Sopenharmony_ci  ```html
407e41f4b71Sopenharmony_ci
408e41f4b71Sopenharmony_ci  <!DOCTYPE html>
409e41f4b71Sopenharmony_ci  <html>
410e41f4b71Sopenharmony_ci  <head>
411e41f4b71Sopenharmony_ci      <title>Same-layer rendering test html</title>
412e41f4b71Sopenharmony_ci      <meta name="viewport">
413e41f4b71Sopenharmony_ci  </head>
414e41f4b71Sopenharmony_ci  <body>
415e41f4b71Sopenharmony_ci  <div>
416e41f4b71Sopenharmony_ci      <div>
417e41f4b71Sopenharmony_ci          <object id="nativeButton" type="test" width="800" height="800" data="test?params1=xxx?" style = "background-color:red"/>
418e41f4b71Sopenharmony_ci            <param name="id" value="playerId" />
419e41f4b71Sopenharmony_ci            <param name="data" value='{}' />
420e41f4b71Sopenharmony_ci		  </object>
421e41f4b71Sopenharmony_ci      </div>
422e41f4b71Sopenharmony_ci      <div>
423e41f4b71Sopenharmony_ci          <object id="nativeVideo" type="test/video" width="500" height="500" data="test" style = "background-color:red"/><object>
424e41f4b71Sopenharmony_ci      </div>
425e41f4b71Sopenharmony_ci  </div>
426e41f4b71Sopenharmony_ci  <div id="button" width="500" height="200">
427e41f4b71Sopenharmony_ci      <p>bottom</p>
428e41f4b71Sopenharmony_ci  </div>
429e41f4b71Sopenharmony_ci
430e41f4b71Sopenharmony_ci  </body>
431e41f4b71Sopenharmony_ci  </html>
432e41f4b71Sopenharmony_ci  ```
433e41f4b71Sopenharmony_ci
434e41f4b71Sopenharmony_ci## Drawing the TextInput Component and Synchronizing Position Information Returned During Same-Layer Element Updates to the Component
435e41f4b71Sopenharmony_ci
436e41f4b71Sopenharmony_ciThe same-layer elements are updated as a result of scrolling, scaling, or any other behavior that may cause a re-layout. The positions of same-layer elements are based on the **\<Web>** component coordinate system. For web page scaling that does not change the element size, only the position changes, and the width and height remain at the initial values.
437e41f4b71Sopenharmony_ci
438e41f4b71Sopenharmony_ciFor components that require location information, such as **\<TextInput>** and **\<TextArea>**, you need to synchronize the location information reported by the same-layer elements to the components in real time.
439e41f4b71Sopenharmony_ci
440e41f4b71Sopenharmony_ci- Complete sample code on the application side:
441e41f4b71Sopenharmony_ci
442e41f4b71Sopenharmony_ci  ```ts
443e41f4b71Sopenharmony_ci  ...
444e41f4b71Sopenharmony_ci  class MyNodeController extends NodeController {
445e41f4b71Sopenharmony_ci    ...
446e41f4b71Sopenharmony_ci    makeNode(uiContext: UIContext): FrameNode | null{
447e41f4b71Sopenharmony_ci
448e41f4b71Sopenharmony_ci      if (this.type_ === 'application/view') {
449e41f4b71Sopenharmony_ci        this.rootNode.build(wrapBuilder(TextInputBuilder), {
450e41f4b71Sopenharmony_ci          textOne: "myInput",
451e41f4b71Sopenharmony_ci          width: this.width_,
452e41f4b71Sopenharmony_ci          height: this.height_
453e41f4b71Sopenharmony_ci        }); 
454e41f4b71Sopenharmony_ci      } else {
455e41f4b71Sopenharmony_ci        // other
456e41f4b71Sopenharmony_ci      }
457e41f4b71Sopenharmony_ci      ...
458e41f4b71Sopenharmony_ci    }
459e41f4b71Sopenharmony_ci    ...
460e41f4b71Sopenharmony_ci  }
461e41f4b71Sopenharmony_ci
462e41f4b71Sopenharmony_ci
463e41f4b71Sopenharmony_ci  @Component
464e41f4b71Sopenharmony_ci  struct TextInputComponent {
465e41f4b71Sopenharmony_ci    @Prop params: Params
466e41f4b71Sopenharmony_ci    @State bkColor: Color = Color.Red
467e41f4b71Sopenharmony_ci    mXComponentController: XComponentController = new XComponentController();
468e41f4b71Sopenharmony_ci
469e41f4b71Sopenharmony_ci    build() {
470e41f4b71Sopenharmony_ci      Column() {
471e41f4b71Sopenharmony_ci        TextInput({ text: `${this.params.textOne}` })
472e41f4b71Sopenharmony_ci          .height(50)
473e41f4b71Sopenharmony_ci          .width(200)
474e41f4b71Sopenharmony_ci          .backgroundColor(Color.Green)
475e41f4b71Sopenharmony_ci          .onTouch((event) => {
476e41f4b71Sopenharmony_ci            console.log('input1 event ' + JSON.stringify(event));
477e41f4b71Sopenharmony_ci          }).margin({ top: 30})
478e41f4b71Sopenharmony_ci
479e41f4b71Sopenharmony_ci        TextInput({ text: `${this.params.textOne}` })
480e41f4b71Sopenharmony_ci          .height(50)
481e41f4b71Sopenharmony_ci          .width(200)
482e41f4b71Sopenharmony_ci          .backgroundColor(Color.Green)
483e41f4b71Sopenharmony_ci          .onTouch((event) => {
484e41f4b71Sopenharmony_ci            console.log('input2 event ' + JSON.stringify(event));
485e41f4b71Sopenharmony_ci          }).margin({ top: 30})
486e41f4b71Sopenharmony_ci
487e41f4b71Sopenharmony_ci        TextInput({ text: `${this.params.textOne}` })
488e41f4b71Sopenharmony_ci          .height(50)
489e41f4b71Sopenharmony_ci          .width(200)
490e41f4b71Sopenharmony_ci          .backgroundColor(Color.Green)
491e41f4b71Sopenharmony_ci          .onTouch((event) => {
492e41f4b71Sopenharmony_ci            console.log('input2 event ' + JSON.stringify(event));
493e41f4b71Sopenharmony_ci          }).margin({ top: 30})
494e41f4b71Sopenharmony_ci      }
495e41f4b71Sopenharmony_ci      .width(this.params.width)
496e41f4b71Sopenharmony_ci      .height(this.params.height)
497e41f4b71Sopenharmony_ci    }
498e41f4b71Sopenharmony_ci  }
499e41f4b71Sopenharmony_ci
500e41f4b71Sopenharmony_ci  @Builder
501e41f4b71Sopenharmony_ci  function TextInputBuilder(params: Params) {
502e41f4b71Sopenharmony_ci    TextInputComponent({ params: params })
503e41f4b71Sopenharmony_ci      .height(params.height)
504e41f4b71Sopenharmony_ci      .width(params.width)
505e41f4b71Sopenharmony_ci      .backgroundColor(Color.Red)
506e41f4b71Sopenharmony_ci  }
507e41f4b71Sopenharmony_ci
508e41f4b71Sopenharmony_ci  @Entry
509e41f4b71Sopenharmony_ci  @Component
510e41f4b71Sopenharmony_ci  struct Page {
511e41f4b71Sopenharmony_ci    browserTabController: WebviewController = new webview.WebviewController()
512e41f4b71Sopenharmony_ci    private nodeControllerMap: Map<string, MyNodeController> = new Map();
513e41f4b71Sopenharmony_ci    @State componentIdArr: Array<string> = [];
514e41f4b71Sopenharmony_ci    @State edges: Edges = {};
515e41f4b71Sopenharmony_ci
516e41f4b71Sopenharmony_ci    build() {
517e41f4b71Sopenharmony_ci      Row() {
518e41f4b71Sopenharmony_ci        Column() {
519e41f4b71Sopenharmony_ci          Stack(){
520e41f4b71Sopenharmony_ci            ForEach(this.componentIdArr, (componentId: string) => {
521e41f4b71Sopenharmony_ci              NodeContainer(this.nodeControllerMap.get(componentId)).position(this.edges)
522e41f4b71Sopenharmony_ci            }, (embedId: string) => embedId)
523e41f4b71Sopenharmony_ci
524e41f4b71Sopenharmony_ci            Web({ src: $rawfile('test.html'), controller: this.browserTabController})
525e41f4b71Sopenharmony_ci              .enableNativeEmbedMode(true)
526e41f4b71Sopenharmony_ci              .registerNativeEmbedRule("object", "APPlication/view")
527e41f4b71Sopenharmony_ci              .onNativeEmbedLifecycleChange((embed) => {
528e41f4b71Sopenharmony_ci                const componentId = embed.info?.id?.toString() as string;
529e41f4b71Sopenharmony_ci                if (embed.status == NativeEmbedStatus.CREATE) {
530e41f4b71Sopenharmony_ci                  // You are advised to use position in edges mode to avoid extra precision loss caused by floating-point calculation during the conversion between px and vp.
531e41f4b71Sopenharmony_ci                  this.edges = {left: `${embed.info?.position?.x as number}px`, top: `${embed.info?.position?.y as number}px`}
532e41f4b71Sopenharmony_ci                  let nodeController = new MyNodeController()
533e41f4b71Sopenharmony_ci                  nodeController.setRenderOption({surfaceId : embed.surfaceId as string,
534e41f4b71Sopenharmony_ci                    type : embed.info?.type as string,
535e41f4b71Sopenharmony_ci                    renderType : NodeRenderType.RENDER_TYPE_TEXTURE,
536e41f4b71Sopenharmony_ci                    embedId : embed.embedId as string,
537e41f4b71Sopenharmony_ci                    width : px2vp(embed.info?.width),
538e41f4b71Sopenharmony_ci                    height :px2vp(embed.info?.height)})
539e41f4b71Sopenharmony_ci                  nodeController.rebuild()
540e41f4b71Sopenharmony_ci
541e41f4b71Sopenharmony_ci                  this.nodeControllerMap.set(componentId, nodeController)
542e41f4b71Sopenharmony_ci                  this.componentIdArr.push(componentId)
543e41f4b71Sopenharmony_ci                } else if (embed.status == NativeEmbedStatus.UPDATE) {
544e41f4b71Sopenharmony_ci                  console.log("NativeEmbed update" + JSON.stringify(embed.info))
545e41f4b71Sopenharmony_ci
546e41f4b71Sopenharmony_ci                  this.edges = {left: `${embed.info?.position?.x as number}px`, top: `${embed.info?.position?.y as number}px`}
547e41f4b71Sopenharmony_ci                  let nodeController = this.nodeControllerMap.get(componentId)
548e41f4b71Sopenharmony_ci
549e41f4b71Sopenharmony_ci                  nodeController?.updateNode({text: 'update',   width : px2vp(embed.info?.width),
550e41f4b71Sopenharmony_ci                    height :px2vp(embed.info?.height)} as ESObject)
551e41f4b71Sopenharmony_ci                  nodeController?.rebuild()
552e41f4b71Sopenharmony_ci                } else {
553e41f4b71Sopenharmony_ci                  let nodeController = this.nodeControllerMap.get(componentId)
554e41f4b71Sopenharmony_ci                  nodeController?.setBuilderNode(null)
555e41f4b71Sopenharmony_ci                  nodeController?.rebuild()
556e41f4b71Sopenharmony_ci                }
557e41f4b71Sopenharmony_ci              })
558e41f4b71Sopenharmony_ci              .onNativeEmbedGestureEvent((touch) => {
559e41f4b71Sopenharmony_ci                this.componentIdArr.forEach((componentId: string) => {
560e41f4b71Sopenharmony_ci                  let nodeController = this.nodeControllerMap.get(componentId)
561e41f4b71Sopenharmony_ci                  if (nodeController?.getEmbedId() === touch.embedId) {
562e41f4b71Sopenharmony_ci                    let ret = nodeController?.postEvent(touch.touchEvent)
563e41f4b71Sopenharmony_ci                    if (ret) {
564e41f4b71Sopenharmony_ci                      console.log("onNativeEmbedGestureEvent success " + componentId)
565e41f4b71Sopenharmony_ci                    } else {
566e41f4b71Sopenharmony_ci                      console.log("onNativeEmbedGestureEvent fail " + componentId)
567e41f4b71Sopenharmony_ci                    }
568e41f4b71Sopenharmony_ci                  }
569e41f4b71Sopenharmony_ci                })
570e41f4b71Sopenharmony_ci              })
571e41f4b71Sopenharmony_ci          }
572e41f4b71Sopenharmony_ci        }
573e41f4b71Sopenharmony_ci        .width('100%')
574e41f4b71Sopenharmony_ci      }
575e41f4b71Sopenharmony_ci      .height('100%')
576e41f4b71Sopenharmony_ci    }
577e41f4b71Sopenharmony_ci  }
578e41f4b71Sopenharmony_ci
579e41f4b71Sopenharmony_ci  ```
580e41f4b71Sopenharmony_ci
581e41f4b71Sopenharmony_ci- Example of the frontend page:
582e41f4b71Sopenharmony_ci
583e41f4b71Sopenharmony_ci  ```html
584e41f4b71Sopenharmony_ci  <!DOCTYPE html>
585e41f4b71Sopenharmony_ci  <html>
586e41f4b71Sopenharmony_ci  <head>
587e41f4b71Sopenharmony_ci      <title>Same-layer rendering test html</title>
588e41f4b71Sopenharmony_ci      <meta charset="UTF-8">
589e41f4b71Sopenharmony_ci      <style>
590e41f4b71Sopenharmony_ci      html {
591e41f4b71Sopenharmony_ci          background-color: blue;
592e41f4b71Sopenharmony_ci      }
593e41f4b71Sopenharmony_ci      </style>
594e41f4b71Sopenharmony_ci  </head>
595e41f4b71Sopenharmony_ci  <body>
596e41f4b71Sopenharmony_ci
597e41f4b71Sopenharmony_ci  <div id="bodyId" style="width:800px; height:1000px; margin-top:1000px;">
598e41f4b71Sopenharmony_ci      <object id="cameraTest" type="application/view" width="100%" height="100%" ></object>
599e41f4b71Sopenharmony_ci  </div>
600e41f4b71Sopenharmony_ci  <div style="height:1000px;">
601e41f4b71Sopenharmony_ci  </div>
602e41f4b71Sopenharmony_ci
603e41f4b71Sopenharmony_ci  </body>
604e41f4b71Sopenharmony_ci  </html>
605e41f4b71Sopenharmony_ci  ```
606