HTML5のaudio/video要素のイベントcanplayがiOS Safariで発動しないんだけど?

2019年12月18日HTML, JavaScript, フロントエンド, 初心者向け, 問題解決

画面読み込み時にaudio要素にゴニョゴニョしたかったのに、iOS Safariだけうまく動かなくてハマったので備忘録。

addEventListenerがiOSだけ動かない問題

音声再生機能をつけた画面のjsに、次のような処理を追加しました。

let audio = new Audio()
audio.src = <オーディオのソース>

// 再生位置が変更されたときのイベント
audio.addEventListener('timeupdate', this.timeupdate, false)
// 再生準備できたときのイベント
audio.addEventListener('canplay', this.canplay, false)
// 再生終了時のイベント
audio.addEventListener('ended', this.ended, false)

audioオブジェクトに対して、アドイベントリスナーでいろんなイベントをハンドリング(拾う)ことができるんだけど、この実装をしていたらデバイスごとに動作が違うという報告が。

実際に検証してみると、

  • Mac Chrome → OK
  • Mac Safari → OK
  • Android Chrome → OK
  • iOS Safari → NG

という結果に。

【対応策】ワンチャン対応してないイベントだったりする?

iOSがaddEventListenerのcanplayイベントだけ使えなかったりするのかも、と思ったので、類似のタイミングで呼ばれるイベントで根こそぎ試してみた。

loadedmetadata メタデータの読み込み完了時
loadeddata メディアデータを描画できる状態になった時
canplay メディアデータの再生ができる時
canplaythrough メディアデータの再生ができ、バッファリングで止まることはないであろう時

読み込み完了・またはある程度準備できたときに発動するイベントはこの4つ。

が、しかしどれを試してもだめだった。

【解決策】最後にたった一行入れるだけだった

audio.load()

結論としては、addEventListenerを発行したあと、最後にaudio.load()という一行を追加するだけで動いた。

MacやらAndroid Chromeやらではaudioオブジェクトの読み込みをよしなに行ってくれているが、iOSのSafariでは明示的にロードさせないといつまで経ってもaudioが読み込まれないらしい。