bilibili PC客户端架构设计——基于Electron

众所周知,bilibili是个学习的网站,网页端和粉版移动端都非常的好用,不过,相对其它平台来说bilibili的PC客户端也算是大器晚成了。在有些场景PC客户端的优势也是显而易见的,比如,跓留电脑桌面的快捷、独立的应用窗口、特有的交互方式等,因此就有了很多喜欢bilibili的技术大佬整出了不少体验不错的第三方PC应用,比如云之幻版、逍遥橙子版等。

当然bilibili也有一个源自三方的UWP客户端,但是由于历史原因一直没有得到很好的维护,在21年底,一个需要在电脑端预装的需求让我们有了开发一个全新的PC客户端的想法。

图片

一、PC客户端的技术选型

选择一个什么样的技术,可以在降本增效的大背景下实现一个体验相对较好、易维护、跨平台且能快速推进的PC应用呢?

图片

图2 PC端开发技术对比

调研了一些PC端应用开发的技术方案之后,基于开发效率、跨平台和成熟度等因素考虑,最终bilibili选择了使用WEB技术栈的Electron做为新PC客户端的开发框架。

图片

图3 Electron框架的优势

在确定了开发框架后,先来看看Electron到底是什么。我们知道Electron是背靠微软基于WEB技术的开源项目,最初源自GitHub团队的Atom Shell项目,结合NodeJs和Chromium实现,并对系统API做了封装,比如系统对话框、系统托盘、系统菜单、剪切板等,开发者可以直接通过js访问这些API。

图片

图4 Electron的构成

图片

图5 一般Electron应用的运行时

我们知道Electron程序主要分为主进程(Main Process)和渲染进程(Render Process),主进程主要为NodeJs和原生API,渲染进程主要为前端技术,主进程和渲染进程之间通过IPC进行通信。

为了易维护、好拓展、可复用等目的,我们选择了NodeJs+NestJs+Esbuild的方案来开发主进程,选择了和WEB首页Laputa项目相同的技术栈Vue3+Vite2+TypeScript开发渲染进程。

图片

图6 PC客户端技术选型

主进程的NestJs是一个受Angular启发的NodeJS后端框架,风格有点像SpringBoot,结合OOP (Object Oriented Programming)、FP (Functional Programming)和 FRP (Functional Reactive Programming)等编程范式,能够开发出高可测、好拓展、松耦合、易维护的应用。Esbuild是使用go语言实现的js极速打包工具,可以助力更高效的开发主进程。

图片

图7 Esbuild官网展示的构建性能对比

渲染进程使用和WEB相同的技术栈,除了方便复用WEB现成的很多组件之外,同时WEB业务线的开发人力也可以无障碍的投入到PC客户端的业务开发中来,因此可以最大限度的降低开发成本、提高开发效率。另外,我们还在项目中实践和应用了我们自研的Vue3组件库vivid-ui、函数库@bilibili/b-utils和样式库@bilibili/b-style等工具库。

图片

图8 PC客户端自研工具库

二、PC客户端的整体架构

PC客户端是bilibili的一个全新的端,除了推荐、直播、热门、OGV、动态、空间、搜索等常规功能之外,还需具备电脑端本地软件的其它能力,包括安装升级、托盘隐藏、本地存储、专有窗口、离线缓存、自定义配置、唤端拉活等等。

图片

图9 下载中心

(其中Windows版、MacOS版、微软商店版都是PC客户端)

我们先来看看PC客户端的业务功能设计,在1.0的版本我们其实就已经实现了安装卸载、开屏页、首页、动态、搜索、我的和空间、播放页、登录、主题和设置等功能,随着版本迭代,我们陆续完成了一键三连安装界面、离线缓存、播单、消息等功能。

图片

图10 PC客户端业务功能设计

在明确业务功能后,结合框架和技术栈,我们设计了PC客户端的整体架构:由渲染进程实现业务功能的UI和交互,由主进程实现本地日志、存储、下载、上报、升级等服务和支持的功能,渲染进程和主进程之间封装IPC为统一的JSB接口进行通信。

图片

图11 PC客户端整体架构设计

在渲染进程中,账号登录、大会员充值、直播间和开播页都是使用webview嵌WEB页的方式接入的,其它业务模块均为本地应用页面;在主进程中,本地日志、本地存储和下载SDK都是引入的模块,其它各个模块和服务之间通过依赖注入和rxjs主题订阅的方式实现相互调用;JSB则由主进程通过preload的方式注入到渲染进程各页面的window对象中,渲染进程不论是外嵌还是本地页面都能访问到JSB对象实现和主进程通信。

由于客户端基于Electron和WEB技术开发,一个窗口页面其实本质上就是一个HTML页面。当然,我们的主页面都是从由主进程创建的本地服务器上拉取的Local页面,因此断网的情况也能响应,像首页、动态网络强相关的页面,在断网时会显示失败提示,而离线缓存、设置等功能都能正常使用。

由于我们渲染层是基于Vue开发的SPA应用,主窗口和播放窗口在打开时会有一个比较耗时的加载过程,为了提升用户体验我们专门针对窗口创建和打开过程做了优化。

  1. 在启动时(首次打开主窗口),会先创建一个隐藏的主窗口,加载一个相对简单的开屏页。

  2. 当开屏页渲染完成后,调用主进程splashPageReady接口,主进程控制显示主窗口。(防止开屏页白屏)

  3. 主窗口和开屏页显示之后,在主窗口开屏页下方加载和渲染比较大的主页面。

  4. 主页面渲染完成时,调用主进程mainWindowReady接口,并关闭盖在主页面上面的开屏页。

  5. 主进程收到mainWindowReady后,创建一个隐藏的播放窗口。

  6. 当用户点击播放视频时,显示已渲染好的播放窗口,并加载和播放视频。

  7. 关闭主窗口和播放窗口时,只将窗口隐藏并不真实销毁窗口实例,当再次打开或播放视频时,就可以快速打开窗口,提升用户体验。

图片

图12 PC客户端执行过程

图片

图13 窗口创建和打开流程

事实上,采用隐藏的窗口进程做预渲染和并行处理是提升Electron应用体验的常用方法,在Electron中可以用ChildProcess、BrowserWindow、BrowserView、webview等方式开启子进程,突破进程限制,充分利用机器的性能。

可以通过主进程app.getAppMetrics()方法获取APP各进程的CPU和内存数据统计,PC客户端主要包含7个常跓进程:1个浏览器(Browser)进程、1个GPU进程、1个网络服务(Network Service)进程、1个音频服务(Audio Service)进程和3个页面(Tab)进程。

图片

图14 PC客户端的进程

由于渲染进程占用资源比较大,如果用户长时间未使用又没有关闭的话就会造成资源浪费,因此我们还为APP设计了“节能模式”,当APP隐藏到托盘超过一定时间未点开后会进入到此模式,这时程序会杀掉主窗口和播放窗口对应的渲染进程,释放资源占用。进入节能模式之后,如果用户再打开APP则会进入前面提到的窗口创建和打开流程,不过这个过程没有APP初始化的任务,速度会比冷启动时要快很多。

图片

图15 PC客户端节能模式

PC客户端使用Fawkes平台打包构建、进行数据上报并建立数据报表、平台进行自动化巡检测试、建有专门的产品和开发文档,开发方面也有明确的代码规范要求

图片

图16 项目设计开发平台工具

三、PC客户端工程化构建

PC客户端渲染进程和主进程都是基于TypeScript进行开发的,Ts提供的类型定义和规范可以大幅度提高代码的可读性,在主进程和渲染进程的中间,我们还设计了一个common共享层,用来实现Ts类型和常量的共享。

PC客户端项目结构:

bilibili-electron├── app/*                              # 构建生成代码├── build/*                            # 构建资源目录├── dist/*                             # 安装包生成目录├── scripts/*    ├── build.main.ts                  # 主进程构建配置├── src    ├── common/*                       # 共享类型    ├── main/*                         # 主进程    └── render/*                       # 渲染进程├──  electron-builder.config.js        # 安装包打包配置├──  vite.config.ts                    # 渲染进程构建配置├──  pckage.json

PC客户端项目运行和构建都基于NPM Script,构建release包只需要运行: yarn build:prod。构建代码位于app目录下,由于构建产物也是js代码,很容易被人拿去套壳、植入或篡改。为了防范这些所知的风险,增加被篡改和攻击的难度,我们需要对构建包进行加密处理。经过不断的迭代优化,我们实现了一套使用结合代码混淆、对称加密、字节码处理、WASM解密啥希校验的组合式客户端加密防破解方案。

在打Release包时,会把构建生成的代码先进行混淆、压缩处理,再将主进程主程序代码使用AES-256对称加密生成/app/main/.biliapp文件,将解密和执行入口使用字节码处理,最后计算出APP的哈希值。

图片

图17 PC客户端主程序加密

当PC客户端启动时,会先根据操作系统和系统架构找到对应字节码入口、解密并运行主程序、主程序中校验APP的哈希值,在确定运行环境安全后再正常启动程序。

图片

图18 pc客户端运行流程

PC客户端基于electron-builder进行打包,Mac的安装窗口通过electron-builder配置可以直接生成,Windows的专属一键三连安装程序则是使用NSIS + QT独立开发的。

图片

图19 PC客户端安装引导界面

图片

图20 基于NSIS+QT的专属一键三连界面

PC客户端前期版本基于electron-updater进行升级更新,每次进行版本升级后,都需要用户重新下载完整的安装包进行覆盖安装,由于安装包体积比较大在网络比较差的情况下,升级过程会比较耗时影响用户体验。

在1.9.x版本之后,我们已集成增量更新的功能,只需对app.asar代码包进行更新而不是包含框架的完整安装包,因此可以提高了升级更新效率和体验。

图片

图21 PC客户端升级更新流程

四、PC客户端的播放体验

类似爱奇艺和腾讯视频,我们的PC客户端也是双窗口模式,即主窗口和播放窗口是独立的,可以让用户一边播放视频一边刷动态、逛空间、看消息。

得益于PC客户端渲染进程使用WEB技术开发,稍加适配,PC客户端的播放器直接用上了WEB强大的Nano播放器,这使得PC客户端也拥有了高级弹幕、播放设置、播放器快捷键等功能。PC客户端还将UGC和OGV播放器集成在同一个播放窗口,让视频类型切换更加顺畅,还可以通过前进后退播放历史纪录。

PC客户端的播放质量对比WEB播放页来说,首帧和VV卡顿率会优于WEB,主要原因为能更多预载,单实例,编码支持统一;而百分钟卡顿率和错误率相对WEB来说要略高一些,新平台有更多case需要处理,此项会略高但重试机制尽量不影响体验。

图片

图22 PC客户端和WEB播放页质量对比

对比bilibili其它端来说,PC客户端的人均播放时长是最高的,目前均值已超80分钟,峰值可达100分钟。

另外,PC客户端还实现了贴心的“小窗”播放模式,当点击播放窗口右上角的小窗模式按钮时或拖动改变播放窗口到小尺寸时便会进入小窗模式。

在小窗模式下:

  • 播放窗口可以适配视频大小比例,实现无黑边播放。

  • 搭配固定窗口在最前端的功能,可以让用户一边看教程学习,一边实际动手操作。

  • 相对网页的画中画,PC客户端的小窗不仅可以显示弹幕,而且还没有原画页面的各种限制。

  • 这里小窗其实指的是一种简洁播放模式,因为小窗也可以拖动边缘调整大小,变成比“大窗”还大。

图片

图23 极致的小窗播放体验

图片

图24 固定小窗在最前端

五、PC客户端的质量保证

PC客户端在每次上线之前都需要经过严格的测试流程,一般在官网上线前4个工作日需要进行集成测试,前2个工作日出总包并进行总包回归测试。

除了功能测试之外,构建也需要保证准确性,PC客户端使用Fawkes打包构建,但是人工构建每次都需要根据不同的渠道选择不同的环境变量,渠道也比较多构建容易出错,因此我们开发了CLI打包工具。

命令行打包工具打通了Fawkes构建平台和魔镜测试平台,通过命令行选择渠道、类型和其它参数,并使用配置列表发起构建。

  1. 快速发起Fawkes构建,提高打包配置效率。

  2. 多种模式可选,快速发起debug/release、签名、推CD的包。

  3. 可以避免渠道包打了debug或未签名的情况。

  4. 可以避免环境变量配错、渠道号和渠道名对不上的问题。

  5. 接入魔镜自动化测试平台,保证构建包可靠性,不用人力挨个校验,提高构建效率。

图片

图25 通过命令行工具发起构建

图片

图26 魔镜PC客户端自动化测试

六、PC客户端发布和上线

PC客户端于22年5月10日在官网正式上线,在bilibili WEB首页顶导、bilibili下载中心和常用的PC的软件平台如:微软商店、联想商店、华为应用市场、腾讯管家等搜索“哔哩哔哩”都能下载到最新版本。

PC客户端的发布渠道较多,不同的渠道也有不同的要求,新版本会根据渠道ID来构建并分别投放上架。

图片

图27 PC客户端渠道汇总

上线以来,PC客户端DAU稳步增长,目前已达300万+。

图片

图28 PC客户端DAU数据稳步增长

各渠道安装量稳步上长,对比官网包占比已达40%。

图片

图29 微软商店~入选精选娱乐应用

图片

图30 华为应用市场~闲暇时光首选

图片

图31 联想应用商店~搜索“哔哩哔哩”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/811865.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#在后台自动化截图指定网站并保存图片

先安装PuppeteerSharp的库 然后调用如下方法 private async Task ScreenShotAsync(string url){//using var browserFetcher new BrowserFetcher();//await browserFetcher.DownloadAsync();await using var browser await Puppeteer.LaunchAsync(new LaunchOptions { Headle…

gitlab 搭建

cat etc/initial_root_password Password: ipGg5y7GJPp/YmVHf3c3ViMKzCWYJSjU4JzUktrw8cY ###### 可修改,可不修改,并###并#并 #初始密码 #本次未修改 vim /data/gitlab/etc/gitlab.rb external_url http://ip/gitlab #访问网址及端口 #ssh远程地址 gi…

时钟周期检测标志信号

在某些情况下需要对系统时钟分频后的时钟进行周期检测,引出周期标志信号以便在后续其他情况的使用。虽然在大多数情况下我们能够知道分频后的时钟是系统时钟的几倍分频,但为增强在分频时钟改变情况下周期标志信号的复用性或对未知时钟的周期检测&#xf…

FFmpeg: 简易ijkplayer播放器实现--06封装打开和关闭stream

文章目录 流程图stream openstream close 流程图 stream open 初始化SDL以允许⾳频输出;初始化帧Frame队列初始化包Packet队列初始化时钟Clock初始化音量创建解复用读取线程read_thread创建视频刷新线程video_refresh_thread int FFPlayer::stream_open(const cha…

如何解决Uniapp更新数据不重新渲染组件

办法就是在修改数据的函数里面,用let thatthis,再给that用赋值。 原因是给数据赋值的函数没用箭头函数,this是函数自己的this。比如success(res){} 或者用箭头函数,比如success(res&#xff0…

在Ubuntu服务器上快速安装一个redis并提供远程服务

一、快速安装一个Redis 第一步:更新apt源 sudo apt update第二步:下载Redis sudo apt install redis第三步:查看Redis是否已自启动 systemctl status redis二、配置Redis提供远程服务 第一步:先确保6379端口正常开放 如果是…

STM32F427+RTthread——USB虚拟串口

书接上回说到,RT-Thread完整版移植完毕,接下来做USB虚拟串口的功能 打开MX工程文件,配置USB CDC 先在ENV上选好USB CDC选项 在CubeMX_Config文件夹下就有生成的usb相关文件,添加到Project工程里 然后引入驱动drv_usbd.c&#xff…

【Android Surface】从Activity的创建到Surface的创建,源码分析1

文章目录 activity的创建performLaunchActivityhandleResumeActivitysetContentViewmInstrumentation.newActivitynew出phonewindowWindowManager的创建 回到setContextViewfindViewById addViewViewRootAndroid在哪里“画画” 我们知道Android绘制图形依靠的是surface和surfac…

PostgreSQL数据库基础--简易版

数据库 其中runoobdb为数据库名 查看已经存在的数据库 \l进入数据库 \c runoobdb创建数据库 CREATE DATABASE runoobdb;删除数据库 DROP DATABASE runoobdb;表 其中COMPANY为表名 创建表格 CREATE TABLE COMPANY(ID INT PRIMARY KEY NOT NULL,NAME TEXT…

Harmony鸿蒙南向驱动开发-UART接口使用

功能简介 UART指异步收发传输器(Universal Asynchronous Receiver/Transmitter),是通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输。 两个UART设备的连接示意图如下,UART与其他模块一…

外观模式:简化复杂系统的统一接口

在面向对象的软件开发中,外观模式是一种常用的结构型设计模式,旨在为复杂的系统提供一个简化的接口。通过创建一个统一的高级接口,这个模式帮助客户端通过一个简单的方式与复杂的子系统交互。本文将详细介绍外观模式的定义、实现、应用场景以…

【Hadoop大数据技术】——Flume日志采集系统(学习笔记)

📖 前言:在大数据系统的开发中,数据收集工作无疑是开发者首要解决的一个难题,但由于生产数据的源头丰富多样,其中包含网站日志数据、后台监控数据、用户浏览网页数据等,数据工程师要想将它们分门别类的采集…

什么是RMVB视频?如何把视频转成RMVB格式?视频格式转换的方法

一,什么是RMVB视频格式 RMVB是一种视频文件格式,它基于RealNetworks公司开发的RealMedia编解码器,被广泛应用于互联网上的视频流媒体传输和下载。RMVB文件通常具有较小的文件大小,同时保持较高的视频质量,因此在网络传…

python之堆的实现

堆本质是一个完全二叉树,分为大根堆和小根堆,大根堆每个结点的值都大于它的孩子的值,小根堆相反,每个结点的值都小于它的孩子的值 heapq是python的标准库,用于维护堆,非常方便 heapq库常用的几个函数 he…

React添加到现有项目

1.检查现有项目的根目录下是否有package.json文件 如果没有,则在项目的根目录下初始化一个package.json配置文件 2.在根目录下安装react和react-dom依赖 npm install --save react react-dom react-scripts安装成功后,react、react-dom以及react-scr…

上位机图像处理和嵌入式模块部署(qmacvisual缺失的光源控制)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 有些场景下面,是不需要光源和光源控制的,比如说利用摄像头识别对应区域的库位,这部分直接利用红外光采集对应的…

Nuttx系统在 imx6ul 开发板上的移植(一、环境准备和交叉编译)

Nuttx应该是一个不错的系统,有瓜可挖。小米的澎湃os底层内核使用的就是它。 翻出之前别人送我的imax6ul开发板,在那安安静静的吃灰,有了想动一动的冲动。于是想到给自己定一个小目标,逐步实现Nuttx内核系统在imax6ul的开发板上移植…

十五届web模拟题整理

模拟赛一期 1.动态的Tab栏 请在 style.css 文件中补全代码。 当用户向下滚动的高度没有超过标题栏(即 .heading 元素)的高度时,保持 Tab 栏在其原有的位置。当滚动高度超过标题栏的高度时,固定显示 Tab 栏在网页顶部。 /* TODO…

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题2

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题2 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发 任务书,赛题,解析等资料,知识点培训服务 添加博主wx:liuliu548…

Python人工智能教学之掌握机器学习深度学习并提升实战能力(共72个视频教学+课程资料)云盘下载

人工智能是未来的发展方向,掌握了人工智能,就掌握了钱图。。。 Python人工智能教学之掌握机器学习深度学习并提升实战能力(共72个视频教学课程资料) 下载地址: 链接:https://pan.baidu.com/s/1ryJd5PNx1tLD…