在手淘过去一年多的历史长河中存在五种类型的播放器。
下面从支持平台,loading 动画,全屏,模拟全屏和兼容性五个方面对各个播放器做个横向对比。
类型 | video IOS | video Android | UC SAC | UC HAC | PlayBuddy | Glue |
---|---|---|---|---|---|---|
平台 | IOS手淘 | android手淘 | android手淘>=5.3.2 | android手淘>=5.4.9 | android手淘>=5.3.2 | android手淘<5.3.2 |
loading | 可定制 | 可定制 | 无 | 可定制 | 不可定制,丑陋 | 有 |
控件可定制性 | 可以 | 可以 | 不可以 | 可以 | 不可以 | 不可以 |
全屏 | 支持竖全屏 | 不支持 | 支持竖全屏 | 可以 | 支持 | 支持 |
模拟全屏 | 支持 | 支持 | 不支持 | 有bug | – | – |
兼容性 | 好 | 较好 | 较好 | 好 | 较好 | 一般,不兼容 android 5.0及以上 |
上面介绍了手淘中可供 WebView 选择的播放器,对于业务方而言迫切需要一个解决方,无需关心底层差异。为此,我们屏蔽移动端不同系统平台、宿主环境、播放器的实现细节和兼容性问题,提供统一的接口和事件,具体如下:
事件
controls 播放控件(专指video)
接下来谈谈在开发过程中遇到的各种小问题及其解决办法。
内联播放。iPhone 在视频播放时默认全屏播放, 参考 。
WebView 中,可以对 UIWebView 做如下配置,并且在 video 中配置 webkit-playsinline 属性即可:
webview.allowsInlineMediaPlayback = YES;
iPhone Safari 在 IOS >= 8 的系统中,有人也提出了一个 方案
video::-webkit-media-controls-start-playback-button {
display: none;
}
播放首屏:IOS 通过监听 playing 事件可以准确获取视频播放的时间点;Android 中在该事件触发时,还没真正开始播放。我们通过监听 timeupdate 的事件做模拟处理。
_timeUpdate(e) {
var currentTime = this.getCurrentTime();
// 判断是否为首帧
if (currentTime !== undefined && currentTime !== 0) {
this.fire('firstpaint');
}
}
_playing() {
if (Env.os.ios) {
this.fire('firstpaint');
}
}
isWork() {
if (videoEl.readyState === 0 && videoEl.videoWidth === 0) {
return false;
}
return true;
}
全屏:手淘 IOS 支持竖全屏效果,Android 虽然具有全屏方法,但是被手淘限制,调用全屏方法无效。
方案一
:为了支持横全屏,我们使用 css3 的 rotate 对视频区域进行90度旋转,并且调用 bridge 接口隐藏 native 顶部的 navibar,并对自定义控件进行响应优化调整。基本到达 native全屏效果。当然顶部状态栏不能隐藏还是有些小瑕疵。同时旋转之后元素的 z-index失效,导致视频覆盖控件问题,可以通过设置 -webkit-transform: translate3d(0,0,0) 来修复
requestFullscreen() {
var element = this.el[0];
var method = FullscreenApi.requestFullscreen;
if (method) {
element[method]();
} else if (element.webkitEnterFullscreen || element.enterFullScreen) {
element.webkitEnterFullscreen && element.webkitEnterFullscreen();
element.enterFullScreen && element.enterFullScreen();
} else {
// 模拟全屏
// enterFullWindow();
}
}
// 模拟全屏js核心代码
_mockFullscreen() {
if (curEl.hasClass('normal')) {
this.fullscreen = false;
playerEl.css({
width: this.originWidth,
height: this.originHeight,
left: 0
}).removeClass('fullscreen');
wrapperEl.css({
width: this.wrapperOriginWidth,
height: this.wrapperOriginHeight
});
videoEl.css('height', '100%');
curEl.removeClass('normal');
contentEl.removeClass('fullscreen');
} else {
this.fullscreen = true;
this.originWidth = playerEl.width();
this.originHeight = playerEl.height();
this.wrapperOriginWidth = wrapperEl.width();
this.wrapperOriginHeight = wrapperEl.height();
playerEl.css({
width: $(window).height(),
height: $(window).width(),
left: $(window).width()
}).addClass('fullscreen');
wrapperEl.css({
width: $(window).height(),
height: $(window).width()
});
videoEl.css('height', videoEl.height() - controlsHeight);
curEl.addClass('normal');
contentEl.addClass('fullscreen');
}
}
效果图:
方案二
。方案一只是模拟了横全屏效果,对于追求完美的处女座不能忍。还有其他方案吗?有时候只需要转换下思维,问题即可迎刃而解。既然是横屏播放,只需要让 WebView 横屏即可,同时在横屏之后重新调整控件即可,关键手淘提供了打开应用横全屏的接口。注意点:横屏之后需要禁止页面滚动,要不然全屏就露馅了,因为本质还是个 WebView。 if (this.transverseFullScreen) {
if (curEl.hasClass('normal')) {
curEl.removeClass('normal');
this._transverseFullScreen(false).then(() => {
$('body').removeClass('co-fullscreen').attr({ height: 'auto' });
this.videoWrapperEl.height(this.videoOriginHeight).removeClass('fullscreen');
this.player.fire('transversefullscreen', { fullscreen: false });
this.resize();
} else {
curEl.addClass('normal');
this._transverseFullScreen(true).then(() => {
$('body').addClass('co-fullscreen').attr({ height: win.height() });
this.videoWrapperEl.height(win.height()).addClass('fullscreen');
this.player.fire('transversefullscreen', { fullscreen: true });
this.resize();
});
}
return;
}
方案3
。在 UC HAC 方案视频提供全屏接口 UCSettings.setVideoViewFullscreenByDefault(true),开启后,视频全屏默认为横屏 if (this.auoplay && env.app.TB && env.network.wifi) {
if (player.getCurrentTime() > 0 && !player.isPause()) {
return;
}
if (this.hasAutoPlay) {
return;
}
this.hasAutoPlay = true;
startEl.trigger('click');
function autoplay() {
doc.detach('touchstart', autoplay);
if (player.getCurrentTime() > 0) {
return;
}
startEl.trigger('click');
}
doc.on('touchstart', autoplay);
}
destroy:
PlayBuddy:在页面跳转时依然会继续播放
处理方式:页面跳转时需要手动的销毁native播放器。
document.addEventListener('WV.Event.Page.Refresh', $.proxy(this.destory, this), false);
document.addEventListener('WV.Event.Key.Back', $.proxy(this.destory, this), false);
win.on('unload', $.proxy(this.destory, this));
win.on('beforeunload', $.proxy(this.destory, this));
/__
* 返回值需要是整数,否则会有异常
*/
_getVedioPos(isDpr) {
var el = this.el,
offset = el.offset(),
dpr = 1;
if (isDpr) {
dpr = this._getDpr();
}
return {
x: parseInt(offset.left / dpr),
y: parseInt(offset.top / dpr),
w: parseInt(el.width() / dpr),
h: parseInt(el.height() / dpr)
};
}
品牌 | 机型 | 手淘版本 | 操作系统版本 | 播放器控件 | 视频列表切换 | 试看控制 | 观看进度同步 | 切换模式 | 问题 |
---|---|---|---|---|---|---|---|---|---|
苹果 | 6 plus | 5.2.7 | 8.11 | √ | √ | √ | √ | √ | * |
苹果 | 6 | 5.2.7 | 8.11 | √ | √ | √ | √ | √ | * |
苹果 | 5s | 5.2.7 | 8.11 | √ | √ | √ | √ | √ | * |
苹果 | 5 | 5.2.7 | 8.11 | √ | √ | √ | √ | √ | * |
苹果 | 4s | 5.2.7 | 8.11 | √ | √ | √ | √ | √ | * |
苹果 | 4 | * | * | √ | √ | √ | √ | √ | * |
nexus 5 | * | yun os 3 | √ | √ | √ | √ | × | * | |
nexus 5 | * | 安卓 5 | √ | √ | √ | √ | × | * | |
三星 | N7100 | 4.9 | * | √ | √ | √ | √ | × | * |
三星 | NOTE4 | 4.9 | * | √ | √ | √ | √ | √ | 模式二点最大化crash |
三星 | NOTE3 | 4.9 | * | √ | √ | √ | √ | × | * |
三星 | S4 | 5.2.7.3 | * | √ | √ | √ | √ | √ | 模式二,播放有问题 |
三星 | I9300 | 4.3 | * | √ | √ | √ | √ | √ | * |
三星 | S3 | 5.2.8.2 | * | √ | √ | √ | √ | √ | * |
三星 | S5 | 5.2.7.3 | * | √ | √ | √ | √ | √ | * |
魅族 | MX2 | * | * | √ | * | √ | √ | √ | * |
魅族 | MX4 PRO | * | * | √ | √ | √ | √ | √ | * |
魅族 | 魅蓝Note | * | * | √ | √ | √ | √ | √ | * |
魅族 | MX3(安装不上) | * | * | √ | √ | √ | √ | √ | * |
华为 | 荣耀6 | * | * | √ | √ | √ | √ | √ | 模式二可能播放不了 |
华为 | mate7 | * | * | √ | √ | √ | √ | √ | 模式二可能播放不了 |
华为 | c8816 | * | * | √ | √ | √ | √ | √ | 进度条拖动会跳 |
华为 | 荣耀3c | * | 4.4.2 | √ | √ | √ | √ | ×一直展示loading的图片 | 模式二播放不了 |
华为 | C8813 | * | 4.1.1 | √ | √ | √ | √ | √ | 高清视频不能播放 |
HTC | MAX | * | * | √ | √ | √ | √ | * | * |
HTC | 816w | * | * | √ | √ | √ | √ | √ | * |
VIVO | Find5 | * | 4.1.1 | √ | √ | √ | √ | √ | * |
VIVO | X3 | * | 4.2.2 | √ | √ | √ | √ | √ | * |
小米 | 2S | * | 4.3 | √ | √ | √ | √ | * | 高清的播放不了 |
小米 | 3 | * | * | * | √ | √ | √ | * | * |
小米 | 4 | * | 4.4.4 | √ | √ | √ | √ | * | * |
索尼 | M512 | * | 4.4.2 | √ | √ | √ | √ | √ | * |
索尼 | xperia 36l | * | 4.1.2 | √ | √ | √ | √ | * | * |
nubia | nx403 | * | 4.2.2 | √ | × | √ | √ | * | 模式一,模式二播放均有问题 |
锤子 | * | * | * | √ | √ | √ | √ | * | |
oppo | x907 | * | 4.0.3 | 很难点到 | √ | √ | √ | √ | * |
nexus5 | * | * | * | √ | √ | √ | √ | √ | 第二种模式crash |
注:模式1为video,模式2为glue native播放器