淘宝直播PC客户端的hybrid探索
穆冰2022-06-10

如何兼具“Native App良好交互体验的优势”和“Web App跨平台开发的优势”在当前互联网时代保持高效的业务迭代是一个非常重要的课题。

什么是hybrid

通俗易懂的翻译

hybrid
英 [ˈhaɪbrɪd]   美 [ˈhaɪbrɪd]  
adj.
混合的;杂种的
n.
杂种;杂种动物;杂交植物;(不同事物的)混合物,合成物
复数:hybrids
派生词:hybrid adj.

客户端世界里的“hybrid”

“hybrid app”,混合开发模式下的应用。目前移动端主要包含两种平台IOS和android,而PC也包含windows和Mac OS,如何兼具“Native App良好交互体验的优势”和“Web App跨平台开发的优势”在当前互联网时代保持高效的业务迭代是一个非常重要的课题。

hybrid方案

移动端的hybrid方案

基于开源框架,如:weex、flutter、RN

对比类型

React Native

weex

Flutter

支持平台

Android/IOS

Android/IOS/web

Android/IOS

实现技术

JavaScript

JavaScript

原声编码/渲染

引擎

JS V8

JScore

Flutter Engine

编程语言

React

VUE

Dart

框架程度

较重

较轻


社区

活跃,FB维护

不活跃

活跃(Google)

原生+小程序,如支付宝小程序

使用WebView容器渲染+NA的方式,前端页面在webview的容器内渲染绝大部分业务交互。其开发效率高,被很多app所使用,但webview也有其缺点,web应用的体验无法达到原生应用的体验,适合做一些非核心业务。

PC端如何去做?

PC客户端从 UI交互、窗口层级、系统资源、网络环境、用户使用习惯等都与移动端有着很大的区别,例如对于PC来说当前APP可以同时有多个窗口并且这几个窗口都可以同时操作移动、缩放、隐藏、关闭等行为,但是对于移动端来说当前 APP窗口内主窗口是无法与子窗口一样可以保持保持移动。如下图的Netlimiter限速限速软件的窗口层级。

几种常见的PC客户端方案:

对比类型

Chrome

Electron

QT+QWebEnfine/Qt+CEF

Qt

支持平台

Windows/Mac/Linux

Windows/Mac/Linux

Windows/Mac/Linux

Windows/Mac/Linux

实现技术

H5

node+H5

QT+CEF

QT

引擎

V8+blink

node+v8+blink

QT+v8+blink

QT

编程语言

javascript+H5

javascript+H5+C++

javascript+H5+C++

C++

框架程度

较轻

较重



社区

活跃

活跃

活跃

活跃

QT:是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些宏,Qt很容易扩展,并且允许真正地组件编程。(摘抄自百度百科)

官网:https://www.qt.io/zh-cn/

CEF:Chromium Embedded Framework (CEF)是个基于Google Chromium项目的开源Web browser控件,支持Windows, Linux, Mac平台。除了提供C/C++接口外,也有其他语言的移植版。(摘抄自百度百科)

官网:https://bitbucket.org/chromiumembedded/cef/src/master/

Electron:Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发经验。(摘抄自官网文档)

官网:https://www.electronjs.org/

淘宝直播PC端hybrid的应用

最早的淘宝主播端脱身与OBS Studio的二次开发,OBS(Open Broadcaster Software) Studio 是一个免费的开源的视频录制和视频实时流软件。其有多种功能并广泛使用在视频采集,直播等领域。UI交互架构采用的是QT,底层渲染、音视频采集、混音等能力采用的是C架构并实现了跨屏台能力,对于windows/macOS/Linux都有很好的支持。

(20.1.0版本OBS截图)

基于20.1.0版本二次开发的淘宝直播端

面对的问题

技术上

前期主播端的版本迭代是以月度迭代为周期进行版本迭代的,经常会收到业务方的询问什么时间发版?跟不上版本月度版本节奏的就会小步快跑发布小版本进行迭代。这不仅仅对于开发、测试造成了困扰,也给用户带来了频繁升级的不友好的体验。同时原有的业务技术架构以C++、Qt为主,曾经有个三方业务想要接入主播端,但是主播端的开发人力有限三方又找不到具备此类技术栈的开发同学就只能延期进行。

对以上问题总结为以下节点:

  1. 沿用纯Qt Native客户端开发,所有功能实现都需要使用Qt+&C++进行开发,开发周期长人力资源紧张;
  2. 客户端的迭代升级依赖发布,客户端的迭代周期前期在一个月左右,目前的迭代周期保持在两周,升级对于用户的干扰性比较大;
  3. 三方业务接入困难,没有C++ PC平台开发经验的同学很难介入继续开发;

业务上

主播的分类

  1. 有专业直播团队和运营团队的主播
  2. MCN机构的主播
  3. 为自己店铺直播的普通直播

对于头部或者部分MCN的机构主播来说大概的角色划分如下图

运营A,使用中控台页面在直播前、中、后进行场次运营的工具,在直播前创建预告,在直播中可以进行红包发放、产品上架管理等。

运营B,使用推流客户端登录后选择对应场次进入直播间进行贴片、摄像头、滤镜等直播画面采集渲染以及推流的相关工作。

使用过程中的痛点

曾经去过直播现场支持的同学有可能都会感到震惊,一场直播幕前幕后居然有这么多人来支持,当然这是在上述头部主播或者MCN机构中出现的场景,那如果是普通的用户群体直播他们应该怎么办呢?对于此类问题经过上述角色的划分也不难看出对于中小主播来说我们就要化繁为简、创建一站式工作台,为直播运营减负。

对于以上问题总结如下:

  1. 对于普通用户(主播+运营合二为一)需要同时打开主播端(负责推流)、中控台(负责运营)进行直播,用户在直播的过程中需要来回切换不同的端完成直播过程。
  2. 中控台是一个前端页面,用户可以在Mac、windows上无缝运行,但是在Chrome中各种插件也造成了很多的问题,用户舆情关于在中控台中的使用问题很大一部分都是源自于插件对于页面的干扰。

相关产品的架构分析

以上主要是拿2020年左右的主播端与当时版本的斗鱼、抖音直播伴侣的一个对比,通过对比发现只有我们的客户端除了左侧评论区外都还是以Qt为主的架构,从结构上来看抖音的最具有灵活性。

我们怎么做

确定下来以Qt->Qt+CEF->Electron+node的架构演变路径,通过Qt+CEF过渡到最终的架构形态,当前最终的架构形态也许在未来还可能会有不一样的迭代过程。

为什么要选择 QT+CEF过渡?

CEF框架选择

Chrome多进程模型

(chrome中的task manager和对应的进程数量一致)

(chrome中的task manager和对应的进程数量一致)

  1. CEF是基于Google Chromium项目的开源组件,有非常活跃的社区支持;
  2. 保持与Chrome一样的速度的迭代更新,对于H5、CSS的兼容性很高,同版本下与Chrome的特性保持一致;
  3. 有丰富的API可供定制化开发;离屏渲染,这个能力在后续的开发中起到了很大的作用;重定向请求回调处理;下载方法回调处理;资源请求拦截启用本地缓存以及可以实现HTTPS;JS 桥接C++方法处理;加载开始、完成、错误等回调处理;cookie植入;Chrome开关命令处理(Chrome预制开关参数,如是否开启OpenGL渲染、进程数量限制等)
  4. 考虑到当前的人力情况,改造当前的部分功能为容器化页面,并提供通用底层能力,给后续的功能迭代提供底层支持

当前现状

(中控台整合进入 PC客户端)

(直播间推流洁面)

  1. 中控台页面整合进入PC客户端、直播间内整合直播中常用工具进入工具箱,便于普通直播对于直播中的运营把控;
  2. 直播间内区域1、2、3均为web容器承载的前端页面,尤其是区域1整合了工具箱,提供基础底层能力,对于目前线上新增需求与底层推流无关的完全可以不跟随主播端发版随时配置页面上线达到迭代效率提升同时没有依赖于升级过程。
  3. 直播中可以返回中控台同时不断流进行其他数据的运营操作;

Electron+node框架的迭代

依托于Node API实现一套C++提供一套音视频采集、渲染、推流的底层能力,面向前端提供基础场景、元素、滤镜的操作能力,前端业务层可以根据具体的业务形态进行不同的组合达到效果最大化。

淘宝直播端Electron+node框架下的底层设计

Electron+node方案下的淘宝直播端框架

期间碰到的问题

(当前electron客户端)

预演区域渲染呈现问题,上图红色选中框区域内是底层渲染的画面,考虑到性能问题该区域由c++底层进行渲染,底层创建窗口前端对于该窗口的位置、宽高做限制,在PC系统下设置父窗口为Electron的主窗口,但是随即会有个问题,前端的渲染窗口总在底层C++创建的层级之下,但是我们前端老师通过Electron的也通过父子关系解决了这个问题,图中预览窗口的中间区域的倒计时就是通过这种方法解决的。

层级演示

  1. 层级1:为可以理解为我们经常看到的Chrome浏览器的主窗口、Electron应用的主窗口,HTML/CSS页面再渲染的过程中都是交付给浏览器的主窗口进行渲染展示的,所渲染的frame内部层级都是局限在此窗口页面渲染内的。
  2. 层级2:为底层新创建的windows窗口,此时根据系统的窗口层级设置层级1为层级2的主窗口,同时C++底层渲染绘制再层级2的窗口上。
  3. 页面mock对应层级2窗口的布局、位置,底层提供位置、宽高、隐藏、展示、销毁的接口,可以提供前端业务布局使用。
  4. 弹框类提示创建新的election自窗口并按照父子关系设置为层级1的自窗口,本身窗口内部也自带order顺序,新创建的弹框也就在当前进程内部了。

底层库加载路径问题,底层的MTOP、Accs等底层依赖对于霸下安全组件的依赖动态加载过程中是从可执行程序目录寻找的,但是我们提供的node底层插件是作为node模块动态记载进来的且node模块在electron的依赖中有固定的目录,此时我们就利用系统的修改寻址方法的接口进行hook修改,达到了加载同级目录下的依赖。

Electron+node框架下的主播客户端目录结构

windows 动态库寻找顺序

  1. 如上图所示,整体新框架下安装路径最外层主要为Electron框架的相关资源依赖;
  2. 底层是以node包为基础提供的底层依赖,SDK基础依赖就全部被放进resources中的node依赖包中,有一些依赖的底层库是通过获取当前执行进程的路径动态加载的方式载入的,这里就无法正确获取加载路径。此时我们通过修改加载路径的方案进行了规避;
  3. 通过切换当前进程工作目录兼容底层对于相对目录寻址的依赖;

总结

现阶段已完成对于基础框架的改造,新框架下的淘宝直播客户端已经开始逐步灰度和放量,但是接下来还有很多事情要做

  1. 完善底层能力建设,提供更多的元能力作为业务发开发支持,如纯净流录制、贴片元素移动限制等;
  2. 对于渲染模块优化的探索,C++提供渲染好的画面交付前端使用canvas进行渲染;
  3. 对于当前框架下业务插件的实现及扩展;
  4. 开发、测试基础设置建设完善;