众所周知,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应用,主窗口和播放窗口在打开时会有一个比较耗时的加载过程,为了提升用户体验我们专门针对窗口创建和打开过程做了优化。
-
在启动时(首次打开主窗口),会先创建一个隐藏的主窗口,加载一个相对简单的开屏页。
-
当开屏页渲染完成后,调用主进程splashPageReady接口,主进程控制显示主窗口。(防止开屏页白屏)
-
主窗口和开屏页显示之后,在主窗口开屏页下方加载和渲染比较大的主页面。
-
主页面渲染完成时,调用主进程mainWindowReady接口,并关闭盖在主页面上面的开屏页。
-
主进程收到mainWindowReady后,创建一个隐藏的播放窗口。
-
当用户点击播放视频时,显示已渲染好的播放窗口,并加载和播放视频。
-
关闭主窗口和播放窗口时,只将窗口隐藏并不真实销毁窗口实例,当再次打开或播放视频时,就可以快速打开窗口,提升用户体验。
图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构建平台和魔镜测试平台,通过命令行选择渠道、类型和其它参数,并使用配置列表发起构建。
-
快速发起Fawkes构建,提高打包配置效率。
-
多种模式可选,快速发起debug/release、签名、推CD的包。
-
可以避免渠道包打了debug或未签名的情况。
-
可以避免环境变量配错、渠道号和渠道名对不上的问题。
-
接入魔镜自动化测试平台,保证构建包可靠性,不用人力挨个校验,提高构建效率。
图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 联想应用商店~搜索“哔哩哔哩”