废话不多说,直接上代码。
// 微信、支付宝音频Hack方案
; void function (win, doc, undefined) {
// 原理:调用链中的某个事件被标识为用户事件而非系统事件
// 进而导致浏览器以为是用户触发播放而允许播放
Audio.prototype._play = Audio.prototype.play;
HTMLAudioElement.prototype._play = HTMLAudioElement.prototype.play;
function wxPlay(audio) {
/// <summary>
/// 微信播放Hack
/// </summary>
/// <param name="audio" type="Audio">音频对象</param>
WeixinJSBridge.invoke('getNetworkType', {}, function (e) {
audio._play();
});
}
function alipayPlay(audio) {
/// <summary>
/// 支付宝播放Hack
/// </summary>
/// <param name="audio" type="Audio">音频对象</param>
AlipayJSBridge.call('getNetworkType', function (result) {
audio._play();
});
}
function play() {
var self = this;
self._play();
try {
wxPlay(self);
} catch (ex) {
document.addEventListener("WeixinJSBridgeReady", function evt() {
wxPlay(self);
document.removeEventListener("WeixinJSBridgeReady", evt, false);
}, false);
}
try {
alipayPlay(self);
} catch (ex) {
document.addEventListener('AlipayJSBridgeReady', function evt() {
alipayPlay(self);
document.removeEventListener("AlipayJSBridgeReady", evt, false);
}, false);
}
}
Audio.prototype.play = play;
HTMLAudioElement.prototype.play = play;
}(window, document);
起因:
在IOS及Android中无法自动播放音频(出于流量和用户体验的考虑,所以用JS直接调用play是无效的)。
但是产品们却要求必须打开页面就播放声音,这可难倒了很多人。
那么我们首先要知道什么情况下调用play函数是有效的,什么时候是无效的。
var audio = new Audio("xxx.mp3");
audio.play(); // 无效
document.body.onclick = function(){
audio.play(); // 有效
};
从上面的代码中可以看出,只有用户事件中触发play函数才有效。
什么是用户事件?click事件、touch事件、mouse事件以及keyboard事件等必须用户手动触发的事件为用户事件。
解决原理:
既然是用户事件才会触发,那我们有没有办法模拟一个用户事件?
答案是肯定的,由于微信、支付宝有扩展API,而此类API是直接内嵌入Js中的,这时Js会把这些内容当成是用户手动触发的内容。
所以我们就可以利用这个来达到效果。
首先将原生的play函数保存下来,然后重写Audio以及HTMLAudioElement原型中的play函数。
接下来是重点,我们要调用一个不会产生任何影响的应用扩展函数,并在回调函数中触发play。
仔细看了一下微信以及支付宝中的接口,发现获取网络信息的接口最符合,因为即使失败了也会调用回调,而且没有任何不良影响。
总结:
有时候解决问题的方法有很多,只要能解决问题的方法就是好方法。