エンジニアのはしがき

プログラミングの日々の知見を書き連ねているブログです

iPadOSのWKWebViewでaudioの鳴り始めが途切れる謎現象について対策した

f:id:tansantktk:20211031185240p:plain

SwiftでWKWebViewを触って1年以上経ちましたが、普通のブラウザと違いiOS上でシミュレートされたブラウザ環境であるためか、メモリをよく食うらしく実装にはかなり気を遣います。

今回はそんなWKWebViewで音を鳴らそうとしたら割と手こずった話です。

環境

  • Swiftで開発したiPadOS向けアプリにWKWebViewを配置。いわゆるガワネイティブを実装している。
  • アプリの処理のほとんどはWKWebView(JavaScript)側で担い、Swift側では補助的な処理しか行わない。

発生した現象

  • WKWebViewでレンダリングするWebページのaudioタグを連続でJavaScript側から発音させると、1回目は問題ないが、何故か2回目以降は鳴り始めの部分が途切れて発音される。
  • WKWebViewだけでなく、iPadOSのSafariChromeでも同様の現象を確認。
  • WindowsChromemacOSChromeSafariでは現象は確認できず。

例えば下記のようなaudioタグを予めHTMLに配置する。

<audio id="audio" src="***************.mp3" preload="auto"></audio>

そしてJavaSciprt側から下記のようにaudioタグを参照して発音させると、2回目以降の発音がおかしくなりました。何故…?🤔

// HTMLからaudioタグを参照
const audio= document.getElementById("audio");
// 連続で鳴らす場合は再生位置を以前の状態からリセットする必要がある
audio.pause();
audio.currentTime = 0;
// 再生
audio.play();

対策

  • HTMLにaudioタグを配置せず、JavaScriptでAudioオブジェクトを毎回生成して発音させた。
const audio = new Audio('***************.mp3');
// 再生
audio.play();

この方法だと発音は何回鳴らしても安定しました。 初回だけロード時間がかかるようで僅かに発音が遅れ、それ以降は軽快に動作しました。何故…??🤔🤔

しかしまだ安定しなかった(2021/10/28追記)

new Audio()を発音の度に実行すると、100~200回に1度くらいの頻度で3~5秒程度のフリーズが発生しました。 フリーズ中はWkWebView側は動作や入力を保留した状態になり、フリーズから解放されると保留中の処理が一気に実行されるという挙動をします。

audioタグで実装するならば、音が途切れることを見越して200ms程度の無音を音声ファイルの頭に挿入して誤魔化すか、もしくはフリーズを許容するか、どちらかでしょうか…。 WkWebViewに拘る必要性がなければ、Swift側に音声再生処理を委譲してしまった方が良いかもしれません。