虎牙开放平台文档

主播端白板

本章节介绍如何创建和使用主播端白板,以及向观众端展示在主播端创建的白板信息。主播端白板是显示在直播间上的一个自定义大小的图层,比如直播挂件,公屏显示等等。当前共有3种白板类型:

  • 独立白板:白板与调用者(PC主播端)共用相同的代码,但有着完全分割开的数据,类似组件复用。
  • 普通白板:相当于是小程序面板在视频中的投影,白板和调用者(PC主播端)共用一套数据。
  • EXE白板:类似于普通白板,参考外部EXE能力的使用。

其中,虎牙小程序提供了独立白板这一重要功能,提供给开发者更大的开发空间。

由于独立白板的使用难度较高,开发者在理解下述白板渲染原理解析后,就可以跟着本章节会新建一个简单入门例子,逐步地学会白板的使用和进一步理解白板的相关概念。

白板渲染原理解析

白板是直播间一个特定的图层,与小程序直播面板不同。因此白板的开发是和主播端面板不同的。尤其,独立白板与调用者(PC主播端)共用相同的代码,但有着完全分割开的数据,类似组件复用。创建白板相当于创建一个新组件,数据是独立开的,且白板所处的环境状态与主播端不同。

使用流程大致如下:创建白板->克隆组件->持续监听数据->修改白板端数据->根据白板数据渲染白板

由于流程的特殊性以及代码复用的特点。白板的代码与主播端的代码有一定耦合,需要借助条件渲染使得白板得以渲染出不同的东西。

准备工作

参考创建小程序项目,初始化一个小程序项目,其中小程序类型选择:

  • 虎牙直播主站-面板
  • 虎牙直播APP-面板
  • PC主播端-面板

参考创建小程序,创建一个小程序和创建一个开发版本。

新增示例组件

完整的创建白板使用流程就涉及多个SDK,包含:创建白板获取初始化参数监听发往白板的数据发送数据给白板等SDK。

新建两个文件,streamer/common.js:

import { UI } from "@hyext/hy-ui"; import React, { useState, useEffect } from "react"; const { View, Text, Input, Button } = UI; import "./WhiteBoard.hycss"; export const Example = () => { const [wb, setWb] = useState(false); const [wbData, setWbData] = useState(""); const [wbMsg, setWbMsg] = useState(""); const [wbId, setWbId] = useState(""); const [isSendSuccess, setIsSendSuccess] = useState(false); /** * 创建普通白板 * SDK:hyExt.stream.createWB() */ const createNormalWb = () => { hyExt.stream .createWB({ width: 750, height: 1200, type: "NORMAL", // 普通白板 wbName: "huya_wbName", offsetX: 100, offsetY: 100, canvasWidth: 500, canvasHeight: 600, x: 0, y: 0, force: true, }) .then(({ wbId }) => { // 返回id setWbId(wbId); }) .catch((err) => { console.log(err); }); }; /** * 创建独立白板 * SDK:hyExt.stream.createWB() */ const createExtraWb = () => { hyExt.stream .createWB({ width: 750, height: 1200, type: "EXTRA", // 独立白板 wbName: "huya_wbName", offsetX: 100, offsetY: 100, canvasWidth: 500, canvasHeight: 600, x: 0, y: 0, force: true, }) .then(({ wbId }) => { // 返回id setWbId(wbId); }) .catch((err) => { console.log(err); }); }; /** * 向独立白板发送数据 * SDK:hyExt.stream.sendToExtraWhiteBoard() */ const sendToWb = () => { hyExt.stream .sendToExtraWhiteBoard({ wbId, data: wbData, }) .then((res) => { setIsSendSuccess(true); }) .catch((err) => { console.log(err); }); }; useEffect(() => { /** * 获取初始化参数 * SDK:hyExt.env.getInitialParam() */ hyExt.env.getInitialParam().then((param) => { // 包含wb参数 => 独立白板模式 if (param.wb) { setWb(true); // 改变白板状态 } }); /** * 监听从原来小程序发送过来的独立白板数据 * SDK:hyExt.stream.onExtraWhiteBoardMessage() */ hyExt.stream.onExtraWhiteBoardMessage({ // 接收到数据,刷新视图 callback: (callbackWbMsg) => { setWbMsg(callbackWbMsg); }, }); }); // 主播端面板内容 const renderForm = () => { return ( <View className="container"> <View className="section"> <Text>请在输入框输入数据</Text> <Input className="input" blurOnSubmit={false} placeholder="输入需要发送的数据" value={wbData} onChange={(value) => setWbData(value)} /> </View> <View className="section"> <Button className="button" onPress={() => sendToWb()}> 发送数据 </Button> </View> <View className="section"> <Button className="button" onPress={() => createNormalWb()}> 创建普通白板 </Button> </View> <View className="section"> <Button className="button" onPress={() => createExtraWb()}> 创建独立白板 </Button> </View> <View className="section"> <Text className="text"> 发送结果:{isSendSuccess ? "发送成功" : "暂无发送"} </Text> </View> </View> ); }; // 主播端白板内容 const renderWb = () => { return ( <View className="wb"> <Text className="data">白板里面接收到的数据:{wbMsg || "暂无接收"}</Text> </View> ); }; // 条件渲染 return wb ? renderWb() : renderForm(); }; export default Example;

WhiteBoard.hycss:

.container{ display: flex; justify-content: center; } .section { margin: 10px auto; } .button { height: 100px; width: 400px; background-color: rgb(253, 69, 69); border-radius: 50px; } .input { width: 600px; height: 80px; border: gray solid 3px; border-radius: 20px; } .text { font-size: 30px; } .data { font-size: 50px; margin: 150px 0 0 20px; }

其中:

  • 使用React.useState()记录 wb(白板的存在状态)、wbData(向白板发送的数据)、wbMsg(白板接收的数据)、wbId(白板Id)、isSendSuccess(是否发送数据成功)等信息;

  • createNormalWb():创建普通白板,在创建白板时可以设置白板的大小,这里设置width为750,height为1200,这个数字刚好和主播端面板的大小一致。创建好白板后,可以通过拖动面板的红框进行大小缩放。

    若开发者关注的是独立白板的创建,可查看下述的createExtraWb()方法。

在小程序中使用组件

  • 修改streamer/app.js:
--- a/streamer/app.js +++ b/streamer/app.js @@ -1,5 +1,6 @@ import { UI } from '@hyext/hy-ui' import React, { Component } from 'react' +import { Example } from './common' import './app.hycss' const { View, Text } = UI @@ -7,7 +8,9 @@ const { View, Text } = UI class App extends Component { render () { return ( - <View className="container"><Text>hello world</Text></View> + <View className="container"> + <Example /> + </View> ) } }
  • 修改app.hycss
.container { display: flex; flex: 1; justify-content: center; align-items: center; + background-color: #bfc; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; }

在直播间预览

普通白板

参考在直播间预览的方式,运行npm start,启动开发服务,在直播间添加开发版小程序,使用主播端打开小程序。

2022 03 17 14 24 14

点击"创建普通白板"按钮之后,可以看到,此时白板和主播端面板外观基本一致。原因是在创建白板这一操作中,白板将会“克隆”当前组件,除了state不同外,其他函数正常调用。

注意:

  1. 字体可能大小差距很大,原因是白板的默认字体大小是很小的,如果给所有文本都设定好px值则不会出现差异。
  2. 向普通白板发送数据或接收数据是无效的,因为hyExt.stream.sendToExtraWhiteBoard(向白板发送数据)和 hyExt.stream.onExtraWhiteBoardMessage(监听白板数据)这两个SDk只适用于独立白板。

独立白板

上图是调用新增的组件streamer/common.js中的createNormalWb()方法 创建的是 NORMAL普通白板。

将小程序关闭后重新在主播端打开,点击"创建独立白板"按钮,会调用createExtraWb()创建 EXTRA独立白板:

2022 03 17 15 14 34

可以明显发现,创建的普通白板和独立白板渲染的内容是不一样的,原因是独立白板数据和主播端数据是分开的,因此可以根据数据的不同进行条件渲染,让白板渲染出和主播端完全不一样的效果出来。

条件渲染

在新增的streamer/common.js的代码useEffect中,调用SDK hyExt.env.getInitialParam(获取当前小程序初始化参数),返回的结果中通过编写一个if语句,判断当前代码环境是不是白板代码环境。由于创建的白板在执行初始化时环境不同,会执行if里面的代码,而主播端则不会执行if里面的代码,因此,该语句可以让主播端和白板端执行不同的代码,产生不同的状态。

流程:主播端初始化->主播端不执行特定代码->主播端wb为false->创建白板->白板复用组件并执行组件初始化函数->白板环境执行特定代码->修改白板的state->白板wb为true->主播端state与白板state出现差异化->根据差异化进行条件渲染。

最后组件渲染时根据初始化函数产生的差异(wb值不同)进行渲染, return wb ? renderWb() : renderForm(),从而在主播端渲染 renderForm 组件,白板环境渲染 renderWb 组件。

白板数据监听与修改

创建独立白板成功之后,可以尝试在输入框输入文本内容,点击“发送数据”按钮。此时会调用sendToWb()方法,从而调用SDK hyExt.stream.sendToExtraWhiteBoard(向白板发送数据)。

2022 03 17 16 15 24

注意:

直接通过主播端函数修改state是变更不了白板数据的,这是因为白板数据的state和主播端面板的state是分割开的。因此还需要在在新增的streamer/common.js的代码useEffect中调用SDK hyExt.stream.onExtraWhiteBoardMessage(监听函数),提供一个修改白板端数据的桥梁。在业务开发中,不能直接在独立白板内调用其他的SDK,必须要经过这个桥梁。

另外,发送到白板的文本内容,是虎牙小程序内容规范的一部分,还需要开发者调用SDK hyExt.order.reportText进行文本的秩序审核

如图,主播端面板的wbData数据成功传送到了独立白板的wbMsg上,与此同时,主播端面板和白板的显示出现了一定差异,再次印证了主播端面板的数据和独立白板的数据是独立分开的这一特性。

总结

本章节的示例小程序讲解了白板的原理以及用法:白板与主播端共用一套代码,但有着独立的数据状态。主要通过以下sdk方法实现了主要功能:

其他相关SDK:

github仓库:https://github.com/huya-ext/hyext-examples/tree/master/examples/wb

FAQ

  • 将小程序关闭后重新在主播端打开:原来的创建成功的白板是不会主动销毁的,再次创建时可能会出现重复创建白板报错addWhiteBoard faild,whiteBoard count is morethan 5 or wbName existed。因此,开发者可以重新打开该小程序对整个小程序进行初始化 或 调用hyExt.stream.deleteWB(删除白板sdk)传入对应的wbId和wbName参数删除原先创建的白板后,再创建新的白板;
  • 小程序白板的开发调试:在 SDK 创建白板PC主播端白板调试均有所阐述,开发者可跳转查看。
  • 虎牙助手端与PC主播端区别
    • 在实际开发中,虎牙助手端会受到手机屏幕的尺寸比例与实际推流的比例(16:9)不一致 和 横屏与竖屏切换的影响,导致创建白板时裁切的区域与实际推流区域不完全一致,出现助手端的可视区域小于实际推流出去 观众端的可视区域的情况。因此开发者可以根据获取到手机设备信息 适配实际推流比例信息,从而在助手端展现较完整的功能界面;
    • 在助手端创建白板时不能直接在本地进行预览,必须将小程序发布到测试环境中,通过虎牙小程序云端合流之后再进行预览。