一直想开通一个blog,但是由于工作太忙(此处写给领导看),还有自己的有三个原因,一是懒,二是懒,三是懒,把这个事情耽搁了,然后直到今天。
那我们直接进入今天的主题。因为最近广告项目里面有个需求,要在移动端用web的HTML5中的Audio来实现音频播放。之前做过PC端的音频播放器,移动端的接触的不是很深入。然后我跌入了一个接一个的坑,在这里我做个记录,种棵树给后面的人乘凉~
需求
做一个SPA的web互动测试游戏。题目是自动切换播放的音频,根据音频内容选择正确选项。
兼容移动端的微信,APP,浏览器和PC端的主流浏览器。
准备
第一步,我们先查看兼容性,打开Can I Use,CanIUse提供了各种浏览器所能支持的桌面和移动端网络前端Web技术,可以提高网站开发人员的工作效率(官方解释哈,不过这个工具确实不错,建议收藏)。
下面是关于audio兼容性图表:
可以看到,在移动端上用Audio是完全可行的(理论上是这样,实际操作你们懂的)。
第二步,我们查看下的开发文档关于Audio标签的描述。
入坑
基础的就不多说了,前端采用zepto.js框架,实现的一个单页面测试,后端用了thinkphp框架,调用了微信获取用户信息接口等,数据库采用的是MySql。
问题
1.音频自动播放问题;2.音频预加载的问题;3.多个音频文件切换问题;4音频文件暂停和播放操作间隔时间问题;
今天我们只说音频控件,对于视频控件后面整理。上面的图片展示了音频标签的属性,pc端主流浏览器下,这些属于都是支持的,BUT!移动端有的就扯蛋了~
1.音频自动播放问题;
这是我在PC端的谷歌模拟器下调试成功后,移动端调试遇到的第一个问题。PC端耍的好好的,到手机上突然没了声音,这尼玛好蛋疼,好想骂娘,突然感觉到人生好艰难~~~但是再难也要走下去,平复心情,解决问题~~在网上查了资料后,这个问题能够解决,但是无法完美。
关于音频自动播放属性autoplay的问题,目前分为三大类:
一,支持audio的autoplay,大部分安卓手机的自带浏览器和微信(无需特殊处理);
二,不支持audio的autoplay,部分的IOS手机的微信(解决方案下面提供);
三,不支持audio的autoplay,部分的安卓手机的自带浏览器(比如小米)和全部的IOS safari浏览器(这种只能做用户触屏时触发播放了)。
以前的IOS是支持音频自动播放的,但是在IOS4.2.1版本之后,苹果不支持自动播放,网上查了下发现IOS上禁止了Audio的Autoplay属性,原因如下:
User Control of Downloads Over Cellular Networks
In Safari on iOS (for all devices, including iPad), where the user may be on a cellular network and be charged per data unit, preload and autoplay are disabled. No data is loaded until the user initiates it. This means the JavaScript play() and load() methods are also inactive until the user initiates playback, unless the play() or load() method is triggered by user action. In other words, a user-initiated Play button works, but an onLoad="play()" event does not.
OK,找到问题根源了,我们开始入手解决,安卓端主流手机都支持,所以不需要处理;IOS微信里面不能自动播放,微信做了很好的支持,调用微信的“WeixinJSBridgeReady”方法;IOS的safari浏览器下,只有用触屏播放的变通方法处理了。代码如下:
functionaudioAutoPlay(id){
varaudio = document.getElementById(id),
play =function(){
audio.play();
document.removeEventListener("touchstart",play,false);
};
audio.play();
document.addEventListener("WeixinJSBridgeReady",function() {
play();
},false);
document.addEventListener('YixinJSBridgeReady',function() {
play();
},false);
document.addEventListener("touchstart",play,false);
}
audioAutoPlay('myAudio');
2.音频预加载的问题;
IOS Safari 中和微信是不支持preload属性的,和autoplay一样。我靠!要你们有啥用~
即便是 HTML markup中使用了preload属性,IOS仍会忽视此属性,并且不会加载此文件,除非由用户触摸事件触发(这样很low)。
3.多个音频文件切换问题;
因为测试的每到题目都涉及到一个音频文件播放,IOS下面音频切换出现了播放不了的问题。
一开始我的页面结构如下:
我把整个Audio进行了循环,PC和安卓上,这种方式是都可以播放的,IOS下不能播放。后来我把页面结构改成只放一个Audio,然后把所有的音频地址放进数组,循环播放。就OK了...后来我查了些资料,分析了原因可能如下(以后有时间等我做更多测试):
var audio1 = document.getElementById('audio1');
var audio2 = document.getElementById('audio2');
audio1.play();
// at a later time
audio2.play();
// there will be a few-seconds delay as iOS is instantiating a new audio object.
// at an even later time
audio1.play(); // there will also be a few-seconds delay, as the audio object
// for audio1 in iOS was destroyed when we played audio2.
在切换音频对象时的 HTML5 音频延时,调用play()在默认情况下会失败,如果在将要加载但尚未载入其元数据的音频流上尝试设置currentTime,则会抛出一个致命错误。音频文件不能缓存在 iOS 上的移动版 manifest 中。只有在对某个离线应用程序使用清单 (manifest) 时,这才适用。如果一个音频文件包含在此清单中,iOS 将会忽略它,并且不会缓存此文件。每当此 Web 应用程序需要访问此音频文件时,都需要从该网络访问此文件。
用 JavaScript 以编程方式进行相关设置时,移动版 Safari 并不会尊重此音量和playbackRate属性。更改属性也不会实际调整这些值。音量总是在用户控制下,并且playbackRate在移动版 Safari 中仍然不受支持。音量总是保持设置为 1,playbackRate则会设置为希望设置的新值,但是音频流回放的实际速度不会发生改变。这会为onratechange事件带来某些复杂性,我们将在不受支持的事件部分对此进行讨论。
在 iOS 5 之前,循环属性是不受支持的。为了解决缺乏支持的问题,可以向onended事件添加了一个事件侦听程序,并在该函数中调用play()。
4音频文件暂停和播放操作间隔时间问题;
上面三个问题解决了,测试基本没有问题。但是打开谷歌的模拟器看到了一个报错,“The play() request was interrupted by a call to pause()”,虽然不影响程序功能,但是身为处女座的我,这个红色的一栏我不能忍,于是我找到如下方法解决:
var isPlaying = myaudio.currentTime > 0 && !myaudio.paused && !myaudio.ended && myaudio.readyState > 2;
if (!isPlaying) {
setTimeout(function () {
myaudio.play().catch(function (e) {
console.log("", e.message);
console.log("", e.description);
});
}, 150);
} else {
alert("网络缓慢,正在加载音频...");
}
先判断音频加载状态等,然后用setTimeout延时处理播放,把抛出的异常接收~然后整个测试就几乎完美~
问题三还有种更优雅的解决办法,那就是用Audio sprite,它的原理类似于CSS sprite,就是把所有音频放入一个音频文件里,根据不同的判断,播放不同的片段~~ 这个是国外的DEMO。有兴趣的同学可以尝试下~
未完待续,今天暂时就这样吧~ 下班了~