同层渲染是ArkWeb组件为应用提供原生组件和Web元素渲染在同一层级的能力。支持的组件范围请参考 NodeRenderType 说明。
- 使用前请在module.json5中添加网络权限,添加方法请参考 在配置文件中声明权限 。
"requestPermissions":[
{
"name" : "ohos.permission.INTERNET"
}
]
约束限制
使用同层渲染的功能时会有如下限制。
-
不支持W3C规格标准标签定义为同层标签。
-
不支持同时配置Object标签和Embed标签作为同层渲染标签。
-
一个页面内同层标签的个数建议不超过五个,超过这个范围性能体验可能得不到保障。
-
同层标签最大高度不超过8192px,最大纹理大小为8192px。
-
Web组件嵌套Web只支持一层嵌套,不支持多层嵌套。如果多层嵌套,会显示 “该插件不受支持”。
-
同层渲染区域支持的触屏事件包括:滑动、点击、缩放、长按,不支持拖拽。
-
同层渲染区域不支持鼠标、键盘、触摸板事件
-
开启同层渲染后,Web组件打开的所有Web页面将不支持统一渲染模式 RenderMode 。
绘制XComponent+AVPlayer和Button组件
使能同层渲染模式
开发者可通过 enableNativeEmbedMode() 控制同层渲染开关。Html文件中需要显式使用embed标签,并且embed标签内type必须以“native/”开头。同层标签对应的元素区域的背景为透明。
- 应用侧代码组件使用示例。
// HAP's src/main/ets/pages/Index.ets
// 创建NodeController
import { webview } from '@kit.ArkWeb';
import { UIContext, NodeController, BuilderNode, NodeRenderType, FrameNode } from "@kit.ArkUI";
import { AVPlayerDemo } from './PlayerDemo';
@Observed
declare class Params {
textOne : string
textTwo : string
width : number
height : number
}
declare class nodeControllerParams {
surfaceId : string
type : string
renderType : NodeRenderType
embedId : string
width : number
height : number
}
// 用于控制和反馈对应的NodeContainer上的节点的行为,需要与NodeContainer一起使用。
class MyNodeController extends NodeController {
private rootNode: BuilderNode<[Params]> | undefined | null;
private embedId_ : string = "";
private surfaceId_ : string = "";
private renderType_ :NodeRenderType = NodeRenderType.RENDER_TYPE_DISPLAY;
private width_ : number = 0;
private height_ : number = 0;
private type_ : string = "";
private isDestroy_ : boolean = false;
setRenderOption(params : nodeControllerParams) {
this.surfaceId_ = params.surfaceId;
this.renderType_ = params.renderType;
this.embedId_ = params.embedId;
this.width_ = params.width;
this.height_ = params.height;
this.type_ = params.type;
}
// 必须要重写的方法,用于构建节点数、返回节点数挂载在对应NodeContainer中。
// 在对应NodeContainer创建的时候调用、或者通过rebuild方法调用刷新。
makeNode(uiContext: UIContext): FrameNode | null{
if (this.isDestroy_) { // rootNode为null
return null;
}
if (!this.rootNode) { // rootNode 为undefined时
this.rootNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId_, type: this.renderType_});
if (this.type_ === 'native/video') {
this.rootNode.build(wrapBuilder(VideoBuilder), {textOne: "myButton", width : this.width_, height : this.height_});
} else {
// other
}
}
// 返回FrameNode节点。
return this.rootNode.getFrameNode();
}
setBuilderNode(rootNode: BuilderNode<Params[]> | null): void{
this.rootNode = rootNode;
}
getBuilderNode(): BuilderNode<[Params]> | undefined | null{
return this.rootNode;
}
updateNode(arg: Object): void {
this.rootNode?.update(arg);
}
getEmbedId() : string {
return this.embedId_;
}
setDestroy(isDestroy : boolean) : void {
this.isDestroy_ = isDestroy;
if (this.isDestroy_) {
this.rootNode = null;
}
}
postEvent(event: TouchEvent | undefined) : boolean {
return this.rootNode?.postTouchEvent(event) as boolean
}
}
@Component
struct VideoComponent {
@ObjectLink params: Params
@State bkColor: Color = Color.Red
mXComponentController: XComponentController = new XComponentController();
@State player_changed: boolean = false;
player?: AVPlayerDemo;
build() {
Column() {
Button(this.params.textOne)
XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController})
.border({width: 1, color: Color.Red})
.onLoad(() => {
this.player = new AVPlayerDemo();
this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId());
this.player_changed = !this.player_changed;
this.player.avPlayerLiveDemo()
})
.width(300)
.height(200)
}
//自定义组件中的最外层容器组件宽高应该为同层标签的宽高
.width(this.params.width)
.height(this.params.height)
}
}
// @Builder中为动态组件的具体组件内容。
@Builder
function VideoBuilder(params: Params) {
VideoComponent({ params: params })
.backgroundColor(Color.Gray)
}
@Entry
@Component
struct WebIndex {
browserTabController: WebviewController = new webview.WebviewController()
private nodeControllerMap: Map<string, MyNodeController> = new Map();
@State componentIdArr: Array<string> =