近期接到一个新需求,要在PC端和小程序端实现新订单语音提醒,其实许多需求前端的实现难度并不高,难的是各浏览器的限制、兼容不一等,此次也不例外。
常规做法
我们都知道HTML5中audio及video有这样的基础属性autoplay,例如:
<!-- audio -->
<audio controls autoplay>
<source src="audio.mp3" type="audio/mp3">
</audio>
<!-- video -->
<video controls autoplay>
<source src="video.mp4" type="video/mp4">
</video>
又或者使用JavaScript更精确地控制音频、视频的播放。
// audio
const audio = new Audio('audio.mp3');
audio.play();
// video
const video = document.createElement('video')
video.src = 'video.mp4';
video.play()
咋一看没什么错,官方文档也明确写着支持,然而还是“太年轻了”,当开始打开页面,且用户还没有产生什么交互时,谷歌、火狐浏览器赫然报错了。
报错如下:
谷歌浏览器
火狐浏览器
谷歌浏览器的提示比较明了,原因是用户还没有跟document产生交互,这主要是考虑到用户体验问题,那么回到正题,交互具体是什么呢?实测移动端的touchstart和PC端的mousedown触发后都会产生用户交互,前提这是用户自己触发的,而不是用JS模拟的。
解决办法
那么既然浏览器的规则是确定的(详见谷歌的Autoplay描述文档),我们应该如何解决需求,搞定产品经理呢?
在作者看来应该要具体需求具体分析,比如说是否允许用户产生交互后,才做播放?这样只要监听document的touchstart或mousedown事件,再做播放就是了;又或者一般我们都是做单页网站,恰好又需要登录,那么交互都会提前产生,也就没有这个问题了。
回到篇首所说的需求,基本是上面说的第二种情况,需要自动播放,而查看订单是需要登录的,咋一看似乎没啥问题了,然而又有一个其他的问题。用户登录会有个登录过期的规则,时间一般会设定在30分钟左右,如果用户刚好在这个页面登录超时,超时后登录会直接跳转到订单列表页,此时用户又刚好晾着不管,没有做任何操作,那么我们所做的音频提醒是不靠谱的。
这个时候有两种解决办法
- 登录后拦截特定的URL并重定向到临近该URL的页面;
- 使用上面 Autoplay文档里介绍的方法,给予用户友善的提示;
第二种方式如下
const promise = audio.play();
if (promise !== undefined) {
promise.then(res => {
// 播放成功
}).catch(error => {
// 提醒用户点击激活播放,并查看新订单
});
}
由于play()方法返回的是一个Promise实例,那么监听其成功失败,就能知道结果并做相应的操作了,至于“点击激活”,点击哪里都是一样的。
以上是一些“曲线救国”的方案,尽管都不完美,但相信产品经理能够理解,毕竟浏览器规则不是我们前端开发能轻易改变的😂。如果哪位小伙伴有更好的办法,希望能共享下帮助大家解决这个自动播放的疑惑。
其他一些解决问题的API
通过翻阅资料和测试发现,用AudioContext播放音频兼容性更佳,尽管没有解决谷歌浏览器自动播放问题,但在火狐中能正常播放了,而在其他浏览器或在移动端的表现,暂时没有测试。
谷歌浏览器报错如下
示例代码(用了比较新的API,不建议直接使用)
// 注:需支持资源文件跨域
(async () => {
const audioCtx = new AudioContext();
const source = audioCtx.createBufferSource();
const getData = async () => {
const myRequest = new Request("audio.mp3");
await fetch(myRequest).then((response) => {
response.arrayBuffer().then((buffer) => {
audioCtx.decodeAudioData(buffer, (decodedData) => {
source.buffer = decodedData;
source.connect(audioCtx.destination);
});
});
});
};
getData();
source.start(0);
})();
使用了上面的示例,音频在部分浏览器就可以直接播放了。
小程序中自动播放音频/视频
小程序官方文档有介绍,这里就不多说了。
参考代码
// audio
const innerAudioContext = wx.createInnerAudioContext()
innerAudioContext.src = 'audio.mp3'
innerAudioContext.play();
// video
<video src="video.mp4" controls autoplay="{{true}}" />
一点题外话
行到技穷处,又见云起伏。
有时候纠缠于技术的泥潭中,反反复复不得其所,忽然过去了,过去的起起伏伏都是一道风景,值得去回味,去欣慰有一颗上下求索的心。