「实践」在IOS中实现音乐自动播放

2,139 阅读2分钟

🎵前言

今天在公司接到一个需求。需求如下,首先前端发起一个异步请求,接着后端会通过socket发送一个携带音乐url的消息到前端, 前端拿到url后需要自动播放这个音乐。众所周知,因为流量,安全等因素的限制,在现代浏览器中,尤其是移动端的浏览器中,是不允许在没有用户交互的情况下自动播放音乐的。在业务中获取音乐url的socket消息,会触发的比较频繁,显然不太可能在每一次接受消息后,弹一个模态框让用户确认播放音乐。难道,我们真的没有办法解决这个问题吗?其实是有的。(因为目前光顾着实现功能,还没有来得及探究背后的原理,还请见谅🙊)

⚠️ps: 此办法只适用于发生过一次用户交互行为的情况下,比如在上述的需求中,前端发送异步请求需要点击一个按钮

💡思路

其实一开始是,我是没有任何思路的。无论是stackoverflow,还是思否,掘金搜了一圈都没有好的解决方法。但是在无意间,我发现了一个项目拥有类似的功能(异步获取音频url后,自动播放音频)。于是看了一下项目的源码,发现了其中的奥妙所在😂

✨这一切的实现,主要依赖了这个包StartAudioContext

On iOS, the Web Audio API requires sounds to be triggered from an explicit user action, such as a tap. Calling noteOn() from an onload event will not play sound. StartAudioContext listens for the first non-dragged touchend or mouseup event on any of the given elements, then triggers a silent AudioBuffer which will start the AudioContext if it isn't already started.

StartAudioContext会监听任意的元素(没有指定参数时将会监听document.body)的除了ouchend或mouseup以外的任意事件。触发事件后,会触发一个静音的AudioBuffer。(在IOS中实现音频自动播放,需要依赖这个AudioBuffer)

💻代码

这里肯定不是公司的源码,因为涉及到保密原则。但是对于理解如何实现这个功能,还是足够的。

import StartAudioContext from 'startaudiocontext'

let audioCtx

window.onload = function () {
  audioCtx = new AudioContext || webkitAudioContext()
  // 移动端需要在页面初始化时,就需要创建
  StartAudioContext(audioCtx)
}

function autoPlay (url) {
  let source = audioCtx.createBufferSource()
  let request = new XMLHttpRequest()
  request.open('GET', url, true)
  request.responseType = 'arraybuffer'
  request.onreadystatechange = () => {
    if (request.readyState !== 4) {
      return
    }
    audioCtx.decodeAudioData(
      request.response,
      (buffer) => {
        source.buffer = buffer
        source.connect(audioCtx.destination)
        source.loop = false
        // 开始播放
        source.start(0)
      })
    }
  }
  request.send()
}

button.onclick = function () {
    // 我需要音乐
}

// 接受消息
socket('msg', ({ url }) => {
  // 自动播放
  autoPlay(url)
})

🙏感谢