html5 中 video 在安卓与 ios 实际应用中遇到的问题及解决
安卓和 IOS 对于 html5 中的 video 兼容一直是大问题,各种不一样,体验还很差。这段时间做一个 html 的 video 播放的时候,要求全屏展示,真是各种问题。下面就就记一下这个项目中遇到的一下手机兼容问题和对应的处理方法。查资料的过程中,发现针对于 video 的兼容问题还是比较多个,会罗列视频播放的通用场景和各个场景下踩过的坑,希望在需求开发的时候,能够针对合适的场景,选择合适的技术方案。有相关的补充,欢迎大家进行补充。
1. 先了解一下 Video 相关的属性
-
src
视频的地址 -
poster
允许用户控制视频的播放,包括音量,跨帧,暂停 / 恢复播放。 -
controls
属性规定视频下载时显示的图像,或者在用户点击播放按钮前显示的图像 -
preload
在页面加载后载入视频 -
webkit-playsinline
&&playsinline
视频播放时局域播放,不脱离文档流。但是这个属性比较特别,需要嵌入网页的 APP 比如 WeChat 中 UIwebview 的 allowsInlineMediaPlayback = YES webview.allowsInlineMediaPlayback = YES,才能生效。换句话说,如果 APP 不设置,你页面中加了这标签也无效,这也就是为什么安卓手机 WeChat 播放视频总是全屏,因为 APP 不支持 playsinline,而 ISO 的 WeChat 却支持。 -
x-webkit-airplay
这个属性应该是使此视频支持 ios 的 AirPlay 功能。使用 AirPlay 可以直接从使用 iOS 的设备上的不同位置播放视频、音乐还有照片文件,也就是说通过 AirPlay 功能可以实现影音文件的无线播放,当然前提是播放的终端设备也要支持相应的功能 -
x5-video-player-type
启用同层 H5 播放器,就是在视频全屏的时候,div 可以呈现在视频层上,也是 WeChat 安卓版特有的属性。同层播放别名也叫做沉浸式播放,播放的时候看似全屏,但是已经除去了 control 和微信的导航栏,只留下 ”X” 和 ”<“ 两键。目前的同层播放器只在 Android(包括微信)上生效,暂时不支持 iOS。至于为什么同层播放只对安卓开放,是因为安卓不能像 ISO 一样局域播放,默认的全屏会使得一些界面操作被阻拦,如果是全屏 H5 还好,但是做直播的话,诸如弹幕那样的功能就无法实现了,所以这时候同层播放的概念就解决了这个问题。不过在测试的过程中发现,不同版本的 IOS 和安卓效果略有不同 安卓效果图 - 如图所示 -
x5-video-orientation
声明播放器支持的方向,可选值 landscape 横屏, portraint 竖屏。默认值 portraint。无论是直播还是全屏 H5 一般都是竖屏播放,但是这个属性需要 x5-video-player-type 开启 H5 模式 -
x5-video-player-fullscreen
全屏设置。它又两个属性值,ture 和 false,true 支持全屏播放,false 不支持全屏播放。其实,IOS 微信浏览器是 Chrome 的内核,相关的属性都支持,也是为什么 X5 同层播放不支持的原因。安卓微信浏览器是 X5 内核,一些属性标签比如 playsinline 就不支持,所以始终全屏。
2. 常见的各种场景
- 自动播放
- 全屏处理
- 播放控制
- 隐藏视频播放的控制条
- video 设置封面显示空白
- video 在某些机型上,再次播放会黑屏,没图像只有声音
- 安卓手机播放结束后,会有广告弹出
- … 后边问题会逐步完善 …
- webview 对于 video 原生标签的支持(存在过闪退的现象)
- 多视频播放的时候,会存在播放黑屏??
- video 和 audio 同时播放的场景,怎么兼容更好??
1. 自动播放
早期的安卓和 IOS 都需要用户手势才能自动播放,后期逐渐放宽的自动播放的策略,逐渐开始支持自动播放,当然在不同的安卓微信手机和对应的浏览器上,展示略有差异,这个没有完全清楚所以机型展示情况。
PC 端的浏览器具体情况有所差别,这个没有进行深入研究,大家有采坑欢迎进行补充。
真正的做法是,检测当前的浏览器是否能支持自动播放,示例代码:
var promise = document.querySelector('video').play();
if (promise !== undefined) {promise.then(() => {// video can play}).catch(err => {// video cannot play})
}
- 不同的应用下,展示情况略有差异,钉钉可以支持,但是微信就禁止,但是自己提供了内置的事件来支持自动播放,示例代码:
document.addEventListener('WeixinJSBridgeReady', function () {music.play()
}, false)
2. 全屏处理
这个其实并不难,安卓和 IOS,在微信环境下打开,默认应该都是全屏(不是视频占据整个手机的全屏,而是占用 body 内的视窗范围之内)
安卓全屏效果,没有顶部的导航栏,只有”>“和”…“,[效果如下]:
IOS 会直接打开全屏模式。效果如下:
IOS 的非全屏展示。对安卓无影响 IOS 效果图 - 如图所示:
但是有的时候不想全屏展示,只需要加上 webkit-playsinline
&& playsinline
即可,视频播放不脱离文档流,进行局部播放。安卓情况下有 ’…’,如果安装过 QQ 浏览器会能进行小窗播放,悬浮在页面的最上面,这个现象符合条件都有,但是不能去掉。这个还是解决不了的,不过一般这样操作的用户还是在少数。
3. 播放控制
video 元素有提供多个行为事件供开发者控制视频播放,兼容性比较好的有 onended、ontimeupdate、onplay、onplaying 等,有些事件在不同浏览器不同设备上的的表现情况并不一致,不同的系统,设备,浏览器显示的特性还是很不一样的,还是看业务场景需要兼容到什么样,尽量不要大量处理这些事件,不然用户去浏览的时候,兼容问题较多。
我处理的基本是,安卓和 IOS 进入全屏,退出全屏,暂停和停止这 4 个事件,其中进入全屏,退出全屏需要针对安卓和 IOS 做不同的处理。
安卓监听进入全屏的事件:
jsvideo.addEventListener("x5videoenterfullscreen", () => {console.log("进入全屏通知");
})
jsvideo.addEventListener("x5videoexitfullscreen", () => {console.log("退出全屏通知");
})
IOS 监听进入全屏的事件:
jsvideo.addEventListener("webkitbeginfullscreen", () => {console.log("进入全屏通知");
})
jsvideo.addEventListener("webkitendfullscreen", () => {console.log("退出全屏通知");
})
监听暂停事件
jsvideo.addEventListener('pause', () => {console.log('暂停了')
})
监听停止事件
jsvideo.addEventListener(‘ended’, () => {
console.log(‘ 停止了 22’)
})
4. 隐藏视频播放的控制条
重头戏来了,相信这个这个问题已困扰无数的前端开发人员,再搜寻这个问题的解决方法时,几乎所有的文章都是告诉你 android 下,播放器的控件是去不了的。其实似乎确实是这样的,但后边在的 android 下,也是没有控制条的。最初看到那些 H5 视频我首先并没有去看他们的内容多么新颖,传播量多么广,我是第一时间测试了 android 下的兼容问题,发现并没有出现控制条。在我研究半天未果时,在一篇技术帖中看到说:因是腾讯自己的项目,微信是腾讯自己的,他们在浏览器里做了一些配置,对旗下出品的 H5 有所“优待”,才能确保视频的顺利“乔装”。
上面的说法我并没有真正核实过,不过可以使用 css 进行操作,我实现的方式是在 video 外层套一个 div,height 设置为 100% 并且设置 overflow:hidden,video 大于 100%,就能把控制条顶到视窗外。这算是视觉的隐藏(惊喜万分~),这个时候对于 video 可能会造成放大,视频要留有一定的安全区,防止遮挡主体内容。对于用户体验来说,长视频没有控制栏还是挺不合适的,当然这个只是一个思路,具体的情况还是看产品的形式适合哪种。
5. video 设置封面显示空白
现象描述:设置 poster 在不同设备上表现不同,浏览器没问题,但是微信浏览器和 IOS 就是死活显示空白,展示效果就是:孤零零的一个播放按钮展示在白纸上一样
解决方案:
- 方案 1:如果有视频合成的封面图,就自定义一个 div,将封面放在 div 中,然后 div 盖在 video 的上面。
- 方案 2:没有封面图就通过 canvas 截取视频第一帧作为默认显示的图片。
var cut = function() {
// 1. 创建画布
let canvas = document.createElement("canvas");
canvas.width = video.videoWidth * scale;
// 2. 设定宽高比
canvas.height = video.videoHeight * scale;
// 3. 将视频此刻帧数画入画布
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
let img = document.createElement("img");
img.src = canvas.toDataURL("image/png");
// 4. 写入到 Dom
Dom.appendChild(img);
};
video.addEventListener('loadeddata',cut);// 在视频帧数已加载时执行截取
6. video 在某些机型上,再次播放会黑屏,没图像只有声音
现象描述:第一次播放视频 ok, 但是在 IOS12.* 以下的机型,再次播放视频会出现黑屏的现象。检查代码发现,video 使用了v-show
, 关闭之后,对应的方法执行,但是只有声音没有图像,为啥???
解决方案:
- 方案 1:尝试加了代码
webkit-playsinline
&&playsinline
,能保证再次进入不黑屏,但是 IOS 自动全屏的失效。
思考:但是为啥这样子??不太符合逻辑的呢,仔细又看了代码,发现外边有 v -show(代码如:代码 1 所示), 猜测可能是这样引起的,第二次使用的时候,难道 IOS12.* 以下的手机本身有兼容问题,因此,没有使用 v -show 处理,只用 css 处理了。,这样能保证 IOS 打开视频全屏,再次打开也不黑屏。根本原因还是有待深究的。
- 方案 2:没有使用 v -show 处理,只用 css 进行兼容处理(代码如:代码 2 所示)
代码片 1:<div class="video-fullscreen-mask'" v-show="!isShowVideoCover">
<video id='js-video' controls
:class="{'width-auto': babyInfo.isNewModel,'height-auto': !babyInfo.isNewModel}"
:poster="babyInfo.videoCover"
webkit-playsinline="true"
playsinline="true"
x5-video-player-type="h5"
x5-video-player-fullscreen="true"
x5-video-orientation="portraint"
>
<source :src="babyInfo.videoUrl"></source>
</video>
</div>
---- 分割线 -----
代码片 2:<div class="default-video" :class="{'video-fullscreen-mask':!isShowVideoCover}">
<video id='js-video' controls
:class="{'width-auto': babyInfo.isNewModel,'height-auto': !babyInfo.isNewModel}"
:poster="babyInfo.videoCover"
:src="babyInfo.videoUrl"
v-if="!userInfo.isApp"
x5-video-player-type="h5"
x5-video-player-fullscreen="true"
x5-video-orientation="portraint"
></video>
</div>
7. 安卓手机播放结束后,会有广告弹出
如果你没有付费的话 从理论来说 广告是不可避免的 但是可以通过一些方法绕过广告:
简单粗暴解决方案:
- 首先判断设备是安卓还是 iOS
- 在视频播放完成事件中添加,先播放视频再暂停视频即可
let isiOS = !!navigator.userAgent.match(/\(i[^;]+;(U;)? CPU.+Mac OS X/)
let videoContext = document.getElementById('video');
videoContext.addEventListener('ended', () => {if (!isiOS) {videoContext.play();
setTimeout(() => {videoContext.pause();
}, 100)
}
}
3. 总结
总结上面的问题,发现正是的场景下不同设备的手机兼容情况还是真的不一样的,我们针对特定的情况考虑一个合适的兜底方案即可,尽量使用最保险的做法,毕竟上线尽量保证没有 bug 才是极好的。
当使用 video 进行视频播放,相对于早期来说,现在手机的性能越来越好,流量时代也要迎来 5G, 会越来越放宽限制,现在表现虽然不太一样,但是未来还是会走向统一的。
参考
视频播放 – 踩坑小计
html5 中 video 在安卓与 ios 实际应用中遇到的问题及解决
视频标签 video 的一些特殊属性详解
微信中 H5 同层 Video 播放器接入教程
video 标签在微信浏览器的问题解决方法