一直想開通一個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。有興趣的同學可以嘗試下~
未完待續,今天暫時就這樣吧~ ?下班了~