前端杂记----更换播放器

310 阅读7分钟

这两天在弄播放器改造,准备从原来的播放器组件过渡到中台提供的新的播放器组件。 新的播放器文档中提供了一个很简洁的例子,大概是script标签引入播放器js文件,之后播放器的构造函数就被挂载到了window上,随后 const player = new window.player(config); player.play(url) 即可,但是我动手以后整个过程还是比较坎坷的......并且还没改造完成。下面记录一下每个阶段遇到的一些情况

着手阶段

一开始的工作肯定是找到当前播放器的源头,毕竟公司现成的项目中的播放器不可能是直接通过script标签引入的吧?层层溯源,捋清楚了整个引用逻辑,感觉还是比较合理、层级分明的:

1.在presetSdk.js中定义了一个对象sdkDict(字典), 对象中的key是sdk名,对应的值是该sdk的cdn地址

const sdkDict = {
    player: 'http://cdn.com/player.js'
}

2.在loadSdk.js中import一个load包(在项目的lib中找到的,以前没有听说过这个,看了一下源码大概是通过script async引入,监听引用完成触发回调,api长这样:load(url, callback)。加载完成才触发回调函数callback)引用presetSdk.JS中的对象,在loadSdk中编写loadSdk函数(直接export default这个函数,这里不用在意命名),函数参数为sdk名,返回一个promise对象,伪代码如下

export default function(sdkName){
    return new Promise((resolve, reject) => {
        load(sdkDict(sdkName), () => {
            resolve()
        }
    })
}

嗯......这只是简略代码,真实代码肯定是考虑到了导入失败等情况的,这里先当作它一定是成功的,继续说

3.编写playerController.js,引用loadSdk.js文件,使用loadSdk方法,当返回的promise对象状态fulfilled以后在回调中初始化一个播放器,向外暴露一个openPlayer函数

function openPlayer(videoUrl, container){
    let player = null
    loadSdk('player').then(() => {
        player = new window.player({
            container,
            url: videoUrl,
        })
        player.play()
    })
}

4.在使用播放器的地方引用playerController.js,直接使用即可。 好了,最基本的使用大概就是这么个逻辑,后边可能会来完善一下容错处理和重复使用相关的逻辑....其实这种代码并没有什么阅读障碍,也谈不上有什么技巧,但我觉得这种四层结构是一种“设计”。让整体逻辑更加清晰,维护起来也很方便。

动手阶段

明白了原来播放器的使用逻辑,接下来就开始动手更换播放器了。首先第一步就是替换掉cdn链接,也是原先“四层结构”中的第一层。第二层结构是对sdk的操作(不管是什么sdk),所以是不用管的,接下来修改第三层。因为第三层直接使用了引入的播放器的构造函数、方法,不同播放器的属性、方法肯定有所差异,所以在这里修改。不过播放器的api使用起来都差别不太大,很快就替换完成并且可以播放了。但是这时候开始遇到一些需要考虑如何处理的问题了

1.原先的播放器有自动播放功能,新的播放器没有。我观察到新播放器在创建完成后直接播放的话总是阻塞,查了资料发现是浏览器的自动播放阻塞策略----非静音状态下不能自动播放(还有一些规则,这里不赘述),所以如果调整player.volumn = 0,再使用player.play(),就可以实现静音自动播放,和原来的播放器效果一样。为了追求代码美学,把这小功能也封装成方法

window.player.autoPlay = function(){
    this.volumn = 0
    this.play()
}
//用法如下
player = new window.player({
    container,
    url: videoUrl,
})
player.autoPlay()

2.视频格式并非只有mp4。这也是我第一次接触其他格式的视频文件,这次必须兼容hls文件,但是这个视频播放器在pc端下无法直接支持hls文件,会显示缺少hls.js文件。但是!我要记录的并非是如何在pc下正常使用这个视频播放器(只要多引入一个js文件就行),而是发现这个问题所付出的代价!!因为这是一个移动端的网站,所以我一开始就是在移动端下进行调整、观察,发现一切正常。但是第二天当我到公司打开这个网页时,我发现播放器直接用不了了,我人傻了。这时候我没有意识到是因为我在pc状态下打开了这个页面,我以为这是一个随机事件。不知不觉中我的chrome又调整成了手机模式,这时候一切正常。但是!!无法复现的bug,是最难受的bug。我在chrome无痕模式下打开页面,没有调整成手机模式,于是又触发了这个问题,我以为是环境隔离下播放器包没有成功引入,于是又去看了前面的几层是否正常.......当然,我没有发现任何问题,十分痛苦。。下次排查问题时一定要注意pc/mobile状态!!!!

3.有一个短视频频道,元素大概是封面+按钮+视频,视频不是自动播放的,需要在封面上点击播放按钮才能播放。直接接入中台播放器以后有以下情况:视频1的画面(1) -> 加载中状态(2) -> 视频2开始播放(3)

也就是用户播放视频1以后,滑动到下一个视频(此时看到视频2的封面和播放按钮),点击播放按钮以后,一闪而过视频1的画面(200毫秒左右),然后再显示加载中,之后才播放视频2,这个用户体验是非常差的。我的解决历程:在用户滑动到第二个视频以后(此时看到视频2的封面和播放按钮),开始调用播放器的load方法加载视频2,这样就能在点击播放按钮以后看到视频2的初始画面。一开始这样确实可以解决问题,并且和原来的播放器效果一样,但是第二天播放器又更新版本了,由于我是cdn引入的,所以直接就更新了,离了大谱了!!短视频页面又恢复之前的问题了!!现在load方法也不改变画面了!!我的解决方案是监听事件(2),监听到发生了以后才撤掉封面,显示播放器,但是这样的话用户感知到的是,点击了播放按钮后停顿了200毫秒才有反应。目前没有其他解决方案,等待播放器提供方解决

5.端内端外视频全屏问题。用两个小时的痛苦排查,搞清楚了整个视频是否支持全屏的逻辑:对于安卓,视频在端内能否全屏,首先看webview能不能横过来,跟播放器其实没太大关系了。如果webview横不过来,那么视频也没法全屏;对于ios,浏览器或者webview内的播放器应该都是用的自己的播放器,所以都可以全屏。

2022.3.27 更新

之前还是过于稚嫩了呀,播放器能踩的坑还是很多的。像上面提到的自动播放问题其实不能那么简单地封装,因为不同浏览器有诸多不同的自动播放限制策略,只是简单地设置音量为0自动播放,会导致微信里播放器显示第一帧然后就不动了,这是因为被微信环境自动阻塞了;所以需要去监听广告被阻塞、内容被阻塞等事件,然后放上播放按钮。后来还遇到一个很有意思的问题,组件大仓的模拟器里播放器广告样式出问题了,排查发现是因为模拟器并没有模拟UA,显示的是PC的播放器,哈哈。