🎲

【Next.js】iOS端末でページ遷移時に音声を再生させる

2023/03/27に公開

はじめに

iOS端末にて、特定のページ遷移時に音声を再生させる必要がありました。iOS端末では自動再生に関するポリシーが存在するため、それを突破するための記事がたくさん存在します。(autoplay属性が効かないためひと工夫必要になります。) 今回はその実装例を共有したいと思います。

方針

基本的に方針は他記事と同様です。

  1. 遷移前のイベント時に音声ファイルをload()する
  2. 遷移先コンポーネントにてplay()する

load()する

今回は目的のページに遷移するための次へボタンがあるという前提で、そのボタンを押下したときにload()する方針でいきたいと思います。

まず、音声ファイルを操作するためのインスタンスを作成したいと思います。今回はRecoilを使用して状態として持ちたいと思います。(シンプルにグローバル変数とかで持つのもいいと思います。今回はグローバルに扱いたいものは状態で持つ方針だったので、音声ファイルについてもそのようにします。)
Audioコンストラクタはクライアント側で生成する必要があるので、typeof window !== 'undefined'の条件を指定してあげます。(process.browserでも問題ありませんが、deprecatedらしいです。)
Next.jsでAudioコンストラクタを呼ぶ方法は上記以外にも、next/dynamicssr:falseを指定してあげたり、useEffect内で実行してあげることで実現できると思います。(useEffect内で実行する方は試してないので怪しいですが...)
また、Next.jsでは画像や音声等静的ファイルは/public下に配置し、以下のように指定してあげます。

use-audio.ts
const audioState = atom<HTMLAudioElement>({
  key: "audio-state",
  default: typeof window !== 'undefined'
    ? new Audio("/target-audio.mp4")
    : undefined,
});

export const useAudio = () => {
  const [audio, setAudio] = useRecoilState(audioState);
  return { audio };
};

今回はatomのdefaultにて初回にAudioインスタンスを生成していますが、fetchAudio()のようなメソッドを作成して音声ファイルを入れ替えたりすることもできます。

次に、次へボタン押下時にload()してあげます。

home-page.ts
const HomePage = () => {
  const audioHooks = useAudio();
  return (
  <>
    <h1>Home</h1>
    <NextButton href="/next" 
      onClick={() => {
        audioHooks.audio.load();
      }}
      Next
    </NextButton>
  </>
 )
};

play()する

あとは、NextPage()内でplay()してあげるだけです。

next-page.ts
const NextPage = () => {
  const audioHooks = useAudio();
  audioHooks.audio?.play();
  return (
  <>
    <h1>Next</h1>
  </>
 )
};

play()メソッドを使用する時、NextPage()へ遷移後すぐに、再度前のページに遷移した場合、残りの音声が再生され続けてしまうため(例えば、音源が10sあり、NextPage()遷移後10s以内に再度HomePage()に戻った場合など)(単純にautoplayを使用するaudioタグであれば、遷移後は音声は止まってくれます)、先ほどのHomePage()にてpause()をしてあげます。

home-page.ts
const HomePage = () => {
  const audioHooks = useAudio();
+ audioHooks.audio?.pause()

以上です。ありがとうございました。

Discussion