第一次在手机淘宝浏览器内做h5(以下简称手淘),记录一下开发过程中碰到的坎。
项目简介
视频类h5,只有三个按钮,所以几乎不用互动。首尾两页加上中间的视频页,所有流程都是自动跳转。由于内容很简单,所以决定采用
zepto
做,这样体积可以尽量小。
百度统计
百度统计支持淘宝域名
P.S. 真的是站在风口上猪都能飞,我们的h5上线4天快破千万了
浏览器内核
猜测是同属阿里旗下的UC浏览器内核,所以这次碰到的一些
css
问题,今后在uc浏览器中可能也会遇到,比如
-
css
不支持rem
,这个实在让我有点惊讶,但这是我亲自试出来的。当然,以后还有手淘的项目,仍然会先尝试rem
tida
手淘专用的
jssdk
叫做tida,引入tida
时,script
标签要写在主业务逻辑的script
标签之前,并在主业务逻辑中调用Tida.ready
进行声明,样例如下:
<script src="//g.alicdn.com/tmapp/tida/3.3.26/tida.js?appkey=xxxxxx"></script>
<script>
Tida.ready({
module: ["device", "media", "server", "social", "widget", "sensor", "share", "buy", "draw", "im", "calendar", "prize"],
console: 0, // 默认关闭, 值为1时打开浮层console.
}, function() {
Tida.hideTitle();
});
</script>
- 作为手机h5重地的微信,
weixin.js
要放在主业务script
标签之后,主业务中先实现WeixinJSBridgeReady
的监听事件,这是微信和手淘的区别。 - appkey有前台key和后台key之分,用的时候记得问清楚部署的同学用的是哪一个
视频播放
这次h5项目最核心的部分就是视频,从最后的实现结果来看,整体的视频效果比微信端要优秀一些,因为仅凭
video
标签,就能实现ios和android两端相同的,理想的播放效果。
播放时全屏
全屏,无进度条,无广告,并且可以有按钮浮在视频上方,主要代码如下:
<video id='video' raw-controls="true" class="videoPlay" src="http://cloud.video.taobao.com/xxxx.mp4" preload="load" x-webkit-airplay="allow" airplay="allow" x5-video-player-type="h5" x5-video-player-fullscreen="true" x5-video-orientation="portrait" x5-playsinline="" playsinline="" webkit-playsinline="">
</video>
- 这个标签是从淘宝大话西游的项目借鉴过来的
- 安卓的进度条其实能看见的,在屏幕的最底部,但是不注意看不容易发现,而且手指很难点到
-
raw-controls
,x-webkit-airplay
,airplay
三个属性在做这个项目之前,都没有接触过,之后做淘宝h5时要特别注意,现在想来可能是uc浏览器的内置标签,事后需要再去了解一下 - 其他的标签属性,例如
x5
开头的,都是微信端浏览器中惯用的属性,另外,playsinline
用来阻止ios自动弹窗全屏播放,都是之前用过的,可能其中仍有些属性是可以删除的,但是这次项目直到最后,都没有明确说过不在微信端投放,所以这些属性一直保留着,没有删除。 - 这里说一下为什么手淘的视频播放比微信端要好,播放效果上,ios的效果差不多,但是android这边区别就很大:
- 视频上不能有按钮,否则就要实现同层播放器,即
x5-video-player-type="h5" x5-video-player-fullscreen="true"
,这样就可以使其他div
标签通过z-index
浮在视频上方,但这样就会导致一个很严重的问题:浏览器标题消失了! FXXK!! - 如果既要实现视频上按钮,同时还要实现浏览器有标题,也有办法,那就是将
video
的流媒体转换成ts
流媒体播放。但这也有问题,第一,ts
文件若要产生和video
同样的清晰度,几乎不可能,而且此时码率已经要大一倍,文件会大3倍左右;第二,video
转ts
,包括项目中对系统的判断都会产生额外的开发开销;第三,ts
视频结束后的跳转,需要修改源码,不太方便。第四,在白鹭引擎下开发时,.ts
后缀名的文件会全部默认为typescript
文件,ts
视频会被误认为是typescript
导致编译失败,这时候需要将ts
视频改后缀,导致开发不畅。
- 视频上不能有按钮,否则就要实现同层播放器,即
被省掉的poster
属性
这次很常用的
poster
属性最终被舍弃了,以下说明原因:
- 在项目的一开始,加入
poster
后,ios上视频不能全屏播放,四周都有黑边,视频长宽比是正确的,但是面积小了许多,删除poster
之后立即恢复正常。但问题不是一直出现的,当video
采用了大话西游的标签之后,即使加了poster
,也不会改变视频面积了。怀疑和其他标签也有关系(raw-controls
,x-webkit-airplay
,airplay
) - android设备在视频播放时,即使
poster
存在,仍然会有一瞬间,poster
消失但是视频黑屏的现象,这样poster
的意义就没有了,但同样的黑屏现象,ios上没有。 - android设备在视频播放时,如果在4g环境下,可以看到在
poster
消失后,视频出现了一次明显的形变。形变大致是视频面积很小,以宽屏的形式在屏幕居中,能看到进度条,然后突然放大撑满屏幕。但是这个形变的现象在wifi环境下就没有。
视频自动播放
淘宝环境下,视频是可以实现自动播放的,实现方式如下:
Tida.network.getType(function(data) {
if(data.errorCode) {
return;
}
appView.playMainVideo();
});
来自阿里巴巴技术人员的原话:成功回调是客户端的能力,操作权限会高一些。
隐藏h5标题栏
tida
自带hideTitle
方法来隐藏标题栏,但在iphoneX下,设备隐藏标题栏后的窗口宽高并不是全屏,隐藏后窗口宽度相同,但是高度会比屏幕短一截。这是手淘的bug。可以通过再来一遍showTitle
,hideTitle
来解决。所以总体解决流程为:hideTitle
,showTitle
,hideTitle
,最后手工render
渲染。
Tida.hideTitle();
setTimeout(function() {
Tida.showTitle();
}, 130);
setTimeout(function() {
Tida.hideTitle();
}, 260);
setTimeout(function() {
loadCss(); // 加载css
loadJs(); // 加载js
loadHtml(); // 加载html
}, 390);
隐藏h5标题栏是客户在半途中提出来的,这带来了一个挺严重的问题,高度太高,设计稿分辨率不足。自从有了全面屏,设计稿的尺寸就一变再变,如今我们的统一设计稿都用
640 * 1236
的分辨率,但都是有标题栏的,而且在微信中,除了在播放视频时,其他时候并不会有这样的问题出现。现在标题隐藏后,实际分辨率达到了640 * 1386
。最终采用的方案是画面整体宽高同时拉伸,使高度撑满屏幕,这样会导致宽度左右两边都超出屏幕一点,幸好机智的设计师们在一开始就考虑了安全区的问题,配上大行其道的flex布局,最后的效果还是比较满意的。
链接跳转≠网页关闭
当调用window.location.href
时,手淘的做法和微信不同,微信会直接修改当前链接地址,这就相当于当前网页关闭了,而手淘更像是打开了一个新标签页,并将这个新标签页置顶。手淘的这个做法会带来一个新的问题,就是原标签页并没有关闭,而是继续运行,只不过是被新的页面盖住了,这样就会造成比如动画,视频,背景音乐始终在播放,必须手动将这些停止。幸好tida
预料到了这种情况,给出了页面激活状态api来解决问题
var watchId = Tida.pageVisibility.watch(function(result){
///~ visible 1为激活 0为隐藏
///~ 移动端按Home键回到桌面js会挂起不执行,所有再次回到页面该方法会先后一起调用,注意区别该值
if(result.visible ==1 ){
// 页面显示了
}else{
// 页面隐藏了
}
});
但是这个api并不是完美的,官方自己也说了ios下回碰到问题
~ 移动端按Home键回到桌面js会挂起不执行,所有再次回到页面该方法会先后一起调用,注意区别该值
这句话很拗口,而且还有两层意思
- 第一层意思:当整个手淘被最小化退回系统桌面时,会触发一个
result.visible = 0
的pageVisibility
事件,但这个事件需要当你重新打开手淘后,才能收到。而当你打开页面的时候,如果当前标签页在最前方,还会在收到一个result.visible = 1
的pageVisibility
事件 - 第二层意思:ios端当按home键也好,手机屏幕底部上滑也好,总之当整个手淘被最小化,退回系统桌面后,再次点击打开手淘时,一定会触发一次
pageVisibility
事件,且result.visible = 1
,无论此时你的页面是不是被隐藏在后面。android和ios的区别就在这里了,android在整个退出回来的过程中,一定能收到一条visible = 0
,但是能不能收到第二条visible = 1
,这要取决于退出的时候,当前标签页是不是在最前方;而ios在整个退出回来的过程中,一定能收到两条消息,也就是visible = 0
和visible = 1
都会收到,晕!
嗯,是阿里的大牛们展示真正的技术了,面对这个尴尬的问题,人家轻描淡写的一句话就给我指明了方向:你可以加一个 requestAnimationFrame 来避免这个问题。牛逼,requestAnimationFrame
只在页面真正渲染时才调用,也就是说,当收到visible = 1
后,不要马上执行,而是将执行的内容延迟到requestAnimationFrame
里,如果这个延迟的时间间隔太长,就说明页面并没有被真正激活,问题解决,代码如下:
var watchId = Tida.pageVisibility.watch(function(result) {
///~ visible 1为激活 0为隐藏
///~ 移动端按Home键回到桌面js会挂起不执行,所有再次回到页面该方法会先后一起调用,注意区别该值
if(result.visible == 1) {
var evtTime = Date.now();
requestAnimationFrame(function(){
var reqTime = Date.now();
if(reqTime - evtTime > 1000){
return;
}
// do something
});
} else {
// 页面隐藏了
// do something
}
});
部署
不同于一般的部署方法(直接访问linux服务器部署相关文件),手淘使用了聚石塔作为工具,这是为了统一大家的部署方式,同时也解决了n台服务器n个系统如何同时部署的困难(我们这次一共是20台服务器上跑60个容器)。习惯了聚石塔的操作步骤后,使用起来还是比较方便的。但在实际过程中,仍然有很多槽点,我们的使用环境是tomcat,碰到的问题如下:
- 聚石塔页面逻辑非常奇怪,页面内的功能几下跳转后居然就跳出聚石塔管理端意外了,而且跳出来就回不去了
- 发布过程中,下方控制台输出的反馈不及时,有时明明正在部署中,但是控制台内容是空的,可以通过
F5
刷新一遍可以解决,但刷新也往往以为着需要重新部署一遍。 - 重新部署一遍
war
包的开销相当大,遇上控制台反馈不及时的时候,体验近乎崩溃,半个小时都部署不了一个war
包 - 后期经常采用单个文件部署的形式,但每次只能提交5个文件,导致这对序列帧这样的图片很不友好。一秒24张图片部署就要10分钟左右。
- 两个人同时登陆聚石塔进行部署,聚石塔可能会在一端直接卡死,想来逻辑确实不太好做,今后要注意避免这种情况
- 有时聚石塔莫名就慢下来了,这个时候可以通过更换浏览器,重新登录的方式解决
weex
weex
是阿里系的移动框架。在这次的项目中,我们的h5算是内嵌在阿里自己的weex
之中的,相比于h5,我觉得weex
的体验会更好:基本没有loading的过程,无缝适配iphoneX的无标题窗口,也没有h5碰到的这种需要反复hide,show才能解决的问题。当然,这其中也有一部分原因是因为写weex
就是阿里的大神们。。。
这次去云栖大会上,听了天施大牛的演讲,我们这套h5聚石塔的做法,在阿里的眼里其实已经落伍了,属于1.0时期的老技术。目前阿里前段已经进入了3.0时期,旨在阿里系的APP中全面使用weex
的做法,并且主打小程序应用。那为什么这次手淘还会采用两端weex
中间夹h5
呢?是给广大小公司的福利吗?还是因为weex
支持视频仍然不到位?还是本身这个项目需要跨淘宝,跨微信呢?可能还是最后一个理由比较说的通吧。。。