android微信视频播放填坑指南

达芬奇密码2018-06-20 09:28

前言

某日,正在愉快着敲着代码的我,突然发现了一个诡异的现象,在android微信中,只要视频播放后,不能把普通dom元素(div等)覆盖在video上,就算是z-index为9999999也无法实现,如图:

我只是播放了一下视频,怎么结构样式全部发生了变化,还有我覆盖在视频上的小按钮


正文

我们知道,android的微信浏览器,是基于X5内核进行渲染。那么,这样的现象会不会X5的一个bug?经过资料的查询,发现在android微信中,video标签会自动被X5所劫持,换成原生的播放器去播放,也就是说,我们看到的video其实不在是html5规范里面的那个video了,已经脱离文档流换成微信的播放器,自然,z-index已经起不到什么作用了,同时播放完成后你甚至可以看到腾讯的广告(是不是有一万只草泥马飘过)。官方的人是这么解释的:

X5内核视频播放使用了自研的播放器,考虑用户体验,我们使用了统一的播放界面。如果有相关问题,请联系腾讯浏览服务产品经理做进一步交流。(就是这么霸气~不要问为什么,因为很cooooooool~~~)

那么有没有什么方法去解决被劫持的问题呢?答案是有的


方案1

我们发现X5内核加载页面后,会有这么一段JS代码注入到页面中。同时发现这一些网站上的video没有被劫持,拿bilibili为例,发现bilibili的视频上只是加了一个(如下图)但是,对应到我们自己的video加上该属性,没有起到任何作用,也就是说,x5内核存在白名单机制,只要申请了白名单,就可以不被劫持,愉快的使用标准的video标签渲染视频了。

Q: 那么怎么申请白名单呢?

A:官方已经去掉了申请白名单入口,已经没有办法在申请了

Q:既然不能申请白名单,还说什么?浪费时间!

A:这样才能愉快的介绍方案2


方案2

在浏览X5的时候,我们找到了这样一个文档https://x5.tencent.com/tbs/guide/video.html, 同层浏览器,什么意思呢,就是说,如果你在video标签上添加 x5-video-player-type="h5" x5-video-player-fullscreen="true"就可以实现用元素去覆盖video这样一个功能了(初见文档内心还有一点小激动,可用起来,还有很多坑需要去填)

既然官方已经声明了可以用,那么我们就用来试试看,根据官方定义,使用同层浏览器后,就可以将普通元素覆盖到video上,但是,声明同层浏览器,会自动在播放视频的时候,进行全屏,像这样:

按照官方文档所述,只要修改video元素的「object-position」属性,就可以修改视频部分的显示位置,但实际上还要把video元素的宽高设成屏幕的宽高才行:


使用NEJ语法改写如下

_event._$addEvent(this._videoNode, "x5videoenterfullscreen", this._onx5VideoEnterFullScreen._$bind(this));
_event._$addEvent(this._videoNode, "x5videoexitfullscreen", this._onx5VideoExitFullScreen._$bind(this));

 // x5内核浏览器全屏
    _pro._onx5VideoEnterFullScreen = function () {
        _element._$setStyle(this._videoNode, 'width', window.screen.width + 'px');
        _element._$setStyle(this._videoNode, 'height', window.screen.height + 'px');
        _element._$addClassName(document.body,'z-x5-video-fullscreen');
    }

    _pro._onx5VideoExitFullScreen = function () {
        _element._$setStyle(this._videoNode, 'width', '');
        _element._$setStyle(this._videoNode, 'height', '');
        _element._$delClassName(document.body,'z-x5-video-fullscreen');
        _element._$delClassName(document.body,'z-x5-video-fullscreen-landscape');
    }
video{
    object-position:center top
}

改写后

使用object-position样式配合全屏video,就可以将显示部分加到任意想要的地方了,然后通过给其他元素设置z-index值大于video的z-index,就可以完成覆盖了(欢呼,撒花 ╰(°▽°)╯)

你以为文章这么简单就完了吗?太天真了,产品同学是不会提这么简单的需求的

产品同学:你的这个不能全屏啊,给加个全屏。

A: 全屏还不容易吗,全屏api就是requestFullScreen嘛,微信里面就是webkitRequestFullScreen

来我们掉用一下,诶?怎么不对劲,用控制台打印微信内容,确实有这个方法,怎么调用无效呢;诶,我先调用api,在去播放视频就可以全屏了;但是我先播放视频在去调用api发现X5是不会理我们的!!这应该是一个X5的bug,同时还发现,使用video原生controls上的全屏按钮而不是api也是可以全屏的!

也就是说,在播放的时候去调用全屏api是无法实现全屏的,那么只能通过其他手段来实现全屏,通过不断的去摸索,发现文档中介绍了x5内核的video会有这样一个属性x5-video-orientation,这个属性用于控制播放器全屏状态下是横屏展示还是竖屏展示,默认是竖屏,那么基于这个属性,可否间接满足全屏条件呢。经过探索在调用全屏api时,设置该属性,可以实时的控制播放器横屏和竖屏,那么实现就简单了。

//判断
  if (_mobileUtil._$isWeixin() && _mobileUtil._$isAndroid()) {
                var node = document.querySelector('#video');
                // 模拟全屏
                _element._$attr(node, 'x5-video-orientation', 'landscape');
                //添加全屏全局样式
                _element._$addClassName(document.body, 'z-x5-video-fullscreen-landscape');
                setTimeout(function () {  
                   //因为横屏宽高发生了变化,所以设置宽高
                    node.style.width = window.screen.width + 'px';
                    node.style.width = window.screen.height + 'px';
                });
            } else {
                this._rootNode.webkitRequestFullScreen();
            }

同理,取消全屏,只需要设置x5-video-orientation的值为portrait即可

 if (_mobileUtil._$isWeixin() && _mobileUtil._$isAndroid()) {
                var node = document.querySelector('.j-mainVideo video');
                node.setAttribute('x5-video-orientation',"portrait");
                setTimeout(function () {
                    node.style.width =window.screen.width+'px';
                    node.style.width =window.screen.height+'px';
                }._$bind(this));
            } else {
                document.webkitCancelFullScreen();
            }

同时,点击左上角的按钮会退出视频播放,也应该清除全屏

 _pro._onx5VideoExitFullScreen = function () {
        _element._$setStyle(this._videoNode, 'width', '');
        _element._$setStyle(this._videoNode, 'height', '');
        _element._$delClassName(document.body,'z-x5-video-fullscreen');
        _element._$delClassName(document.body,'z-x5-video-fullscreen-landscape');
  // 退出后需要设置为竖屏全屏,x5内核
        _element._$attr(this._videoNode, 'x5-video-orientation', 'portrait');
    }


结果


总结

  1. x5内核接管了video的播放,体验和苹果是不同的,如果能加入白名单最好加入白名单
  2. 默认的x5播放器会播放广告,体验极差
  3. 同级播放器有一定的bug,需要通过一些api手段去规避解决

参考文章

  1. H5 直播避坑指南
  2. X5同层播放器试用报告

本文来自网易实践者社区,经作者田翔授权发布。