移动端纠结(二):video在移动端h5中的问题

前言

这是《移动端纠结》系列的第二篇,主讲video的问题。

之前,工作上有一个需求。需要在我司移动端网站文章页上投放视频广告。这个广告的代码由我们组负责。移动端的视频播放,首选当然是video标签。

看起来很简单

看起来很简单,对吧?不就是在适当的位置使用video标签播放视频,然后再对视频进行控制。

但是坑很多

video标签在h5中的坑很多,尤其是在国产移动浏览器中,如uc, qq, sogou等。

第一坑: 视频原生UI不一致

因各浏览器对video UI实现的不一致,就导致原生video标签的样式在各大浏览器中都各不一样,像这样(图片来源于网络):

视频效果图

对于我们来说,当然是需要统一ui。通常的做法是通过dom模拟一个视频播放视图,比如初始加载时放一个封面图和一个播放按钮,然后将视频本体隐藏,通过模拟视图来间接控制视频播放。隐藏视频的代码如下:

1
2
3
4
5
6
7
8
video {
  width:1px;
  height:1px;
}
/*或者*/
video {
  display: none;/*如果使用display='none'的话,播放视频时需在play之前显示video*/
}

本文以下情况都是通过模拟视图来间接控制视频。

第二坑:国产浏览器对播放器劫持

我们知道国产的浏览器大多是使用了webkit内核,在其基础上进行开发而成。这里的劫持指:浏览器自己实现了一套播放器而非调用内核提供的播放器,劫持了内核提供的播放器样式和逻辑。主要表现包含但不限于:

  1. 强制出现controls控制条
  2. 强制全屏
  3. 强制画中画
  4. 强制浮动播放器且浮动有bug

劫持症状及浏览器分别有:

  • UC浏览器:播放时全屏横屏播放,置于最上层,出现UC的控制界面。播放完成时播放器不会自动关闭或者最小化,即便已将video移除/隐藏。在iOS8/9中,内联播放会收不到部分事件,将在内联播放小结细讲。(只测了UC 10.9,11.1版本)
  • QQ浏览器:坑最多最为吐血的浏览器,没有之一。在iOS版QQ浏览器随版本不同表现不同,主要表现是窗口置顶播放或播放器随video位置及大小,但可以拖动浮动。且播放完成后播放器不会自动关闭,而会插入腾讯视频的广告。再次差评。
  • 其他Android机型自带浏览器:包括魅族/小米/华为等,默认为有控制条。

第三坑: 内联播放

(三.一) 内联播放不受控

Android中大部分浏览器支持内联播放,除特殊的UC(默认全屏)及QQ(播放器位于屏幕顶部)。

iOS10中新增了对内联播放支持(添加webkit-playsinlineplaysinline属性),但iOS8&9还是默认全屏,有一个开源的项目iphone-inline-video.js(git:https://github.com/bfred-it/iphone-inline-video)可以实现内联播放(仅对iOS8&9有效,对其它平台及版本无效)。

iphone-inline-video.js的主要原理如下:

  • Object.defineProperty(video, propertyName, {get: get, set: set});劫持了video的各种方法及属性。
  • 使用e.stopImmediatePropagation();劫持video的各种事件。
  • 使用audio播放视频声音。
  • play时使用requestAnimationFrame设置video.currentTime,使视频帧之向后移动。
  • 直到最后结束。

如之前所述,QQ及UC浏览器会劫持播放器,启用内联时可能导致收不到各种事件等异常,建议在这些浏览器下禁用内联播放。

其他浏览器,如Safari,Chrome,搜狗,360,手机百度,百度浏览器下启用内联时正常。

(三.二) 安卓下QQ及微信x5内核浏览器启用同屏层问题

QQ及微信内置浏览器视频播放默认会全屏播放且video置于最上层(除非申请白名单),且播放完成时不会自动关闭播放器而是播放腾讯视频广告或者腾讯视频推荐内容。

可以通过给video添加x5-video-player-type = 'h5' 属性启用同屏层,会小窗口播放,x5-video-player-fullscreen = 'true'启用全屏。

注意:通过测试发现,启用同屏层之后,在QQ轻聊版浏览器中会导致闪退,需谨慎使用。

第四坑: 其他奇葩小坑

(四.一)src赋值时机问题(延迟赋值src)

给video赋值src时浏览器将会触发加载metadata等,故延迟赋值src能加快网页打开速度。其次是对于部分安卓浏览器,如魅蓝U20自带浏览器在视频隐藏时赋值src,后续显示视频再播放时有声音无画面。故我们在点击播放按钮时显示video,赋值src。

然而,QQ浏览器又来捣乱了!

iOS版QQ浏览器6.9版本下,click事件触发时赋值src会导致视频无法播放!需在click之前赋值src。即使在click之前赋值,仍然会需调用两次play()才能播放(且播放器会浮到窗口顶部……差评!)。

这就完了?NoNoNo,

即便如此,在此版本下(iOS版QQ浏览器6.9版本),通过js控制的video收不到除timeupdate外的任何事件,并且timeupdate会触发大概15次左右就不再触发,即便视频已暂停或播放完成,且此时video.currentTime一直为0,video.paused一直为true。

WTF!

But,直接在html中插入video标签,点击video自带的播放按钮则一切正常,能收到事件能正常播放。WTF!

QQ浏览器:src不能二次赋值,播放器隐藏状态时无法正常播放

(四.二)静音及音量控制问题

亲测在iOS9.3.2下,包括:搜狗浏览器,百度浏览器,Safari等,video.mutedvideo.volume设置无效,两者的值一直为false1

而在QQ浏览器下,播放器飘起浮动时设置video.muted时值会变但video并不会静音,只想呵呵。

(四.三)iOS7 Safari浏览器 video高度异常Bug

在iOS7下,Safari播放video时会全屏播放,暂停最小化后video.offsetHeight异常达7000多。

解决方案:暂停后根据宽高比重设video高度。

(四.四)LG5手机自带浏览器播放video提示网络连接异常,请重试

此异常跟我们视频资源服务器有关。

我们视频CDN会通过中转机302转发到真正的视频源,在转换的过程中http协议发生了变化,从https变化成http,而且最终的视频源服务器不支持https

解决办法:在LG5自带浏览器环境下将视频src强制使用http协议

(四.五)部分UC浏览器下,视频源有302跳转时报媒体格式不被支持error.code=4问题,但视频可以被正常播放

如(四.四)所说:

此异常跟我们视频资源服务器有关。 我们视频CDN会通过中转机302转发到真正的视频源。

UC浏览器响应了中途的302返回状态,以此判断不是一个合适的视频资源,所以报告了错误,但视频可以正常播放。只需要在UC下将此错误屏蔽即可。

(四.六)部分浏览器自带控制条及播放按钮

播放按钮:UC ,使用样式隐藏

1
2
3
video::-webkit-media-controls-start-playback-button {
  display:none;
}

控制条:搜狗iOS版,暂停后出现,使用样式隐藏

1
2
3
video::-webkit-media-controls {
  display:none;
}

(四.七)安卓QQ或者微信内置浏览器play时会触发2次window.onscroll事件

会滚动到顶部之后再次滚动到视频位置,因为视频会全屏覆盖网页,所以从视觉上并没有明显异常感觉。 处理办法:从window.onscroll逻辑(如果有的话)中特别判断这两种浏览器。

后记

超累。

做这个工作的时候比较早了。现在才记录下来,可能当你看到这篇文章的时候,某些问题已经不存在了。不过,希望对你有所帮助。

特别鸣谢我的好同事好朋友: quanyong

结语

工作不易,且行且珍惜。