はじめに
本記事は DMMグループ Advent Calendar 2020 の10日目の記事です。
こんにちは、DMM.comの情報システム部で社内向けのサービスを開発しているmimicknです。
弊社では来客時の受付を専用のwebアプリを使用して受付さんが管理をしています。
そのアプリはiPadを使用して各来客用の会議室での時計&会議終了のアラートも兼ねているのですが、過去のiOSアップデートからSafariのポリシーに引っかかりアラートの音声が鳴らなくなってしまいました。
最近までは暫定回避策でiOSアプリでWebViewを使いWebViewからwebアプリを開くことで回避していましたが、アプリの管理コストの削減などによりブラウザで動くよう改修を加えました。
この記事はそのような場合で自動で音声を再生する方法(正確には自動再生っぽく見せる方法)を記載したいと思います。
なぜ音声は鳴らなくなった?
まず今回の音声が鳴らなくなってしまった原因ですが、前述で記述の通りiOSでのSafariのポリシーの変更があったためです。
ポリシーの内容としては音声の再生には ユーザのアクション
が必要というものです。
ユーザのアクション
というのは、ボタンの押下などがあたりそれに紐付けての音声の再生なら可能となります。
PC版Safariであれば設定から変更し自動再生を許可することができるのですが、iOS版ではその設定がありません。
そのため自動再生するためには実装でうまいこと回避する必要が出てきます。
回避方法
いくつか回避方法はあるかと思いますが、今回弊社のアプリで回避に使用した方法は以下のとおりです。
- 音声が再生されるページに訪れた際にダイアログを表示させる
- そのダイアログを閉じさせ、その閉じる挙動に紐付けて音声ファイルをロードさせる
- 2でロードした音声についてはユーザのアクションを必要とせず再生することができるようになる
になります。
より具体的に説明するために、Reactのコードを用いて説明します。
(少し古いシステムでのコードをベースにお話しているため書き方が古いですがご了承ください)
まず以下のような音声を再生するコンポーネントがあるとします。
import React from 'react';
const sound = new Audio('/sounds/sound.mp3');
export default class Sound extends Component {
constructor(props) {
super(props);
sound.play();
}
render() {
return (
<div></div>
);
}
}
このコンポーネントではコンストラクタで対象の音声を再生といった動作をしています。
次にこのコンポーネントを呼ぶアプリを以下に記載します。
import React from 'react';
import Sound from '../../components/Sound';
export default class App extends Component {
render() {
return (
<Sound />
);
}
}
この状態では音声は自動再生されません。
このコードに実際に回避策を入れてみようと思います。
1. 音声が再生されるページに訪れた際にダイアログを表示させる
まず前述で述べた1に該当するダイアログです。
ダイアログの詳細のコードは省きますが、作りとしては message
で表示させる文言を渡し、onClose
でダイアログを閉じるときの関数を渡しています。
ダイアログの表示は訪れたときの一回のみの想定なので、initialDialogClose()ではisInitialの更新をさせる想定です。
render() {
return (
{ // 音声有効化用のダイアログ
isInitial ? (
<Dialog
message={'このページではサウンドが再生されます'}
onClose={this.initialDialogClose}
/>
) : null}
<Sound />
);
}
これで表示されるダイアログのイメージは以下です。
2. そのダイアログを閉じさせ、その閉じる挙動に紐付けて音声ファイルをロードさせる
次にそのダイアログの閉じる挙動に紐付けて音声ファイルをロードさせる実装です。
今回は以下のようにSound.jsxにロード用の関数を用意します。
export const enableSound = () => {
sound.load();
};
あとはこの関数をApp.jsxで読み込み、先程のinitialDialogClose()で呼び出すように改修をします。
3. 2でロードした音声についてはユーザのアクションを必要とせず再生することができるようになる
これで先程ロードした音声ファイルについては、ユーザのアクションを使用せず再生(Audioクラスのplay())をすることができるようになります。
また今回は1ファイルのみのロードの説明でしたが、複数ファイルも同様に行うことができ、それぞれユーザのアクションを必要とせずに再生できるようになります。
(弊社のアプリでは複数の音声を鳴らせる実装となっています)
おわりに
ダイアログのクローズをユーザに要求するため完全に自動再生とは行きませんでしたが、このような実装をすることでワンアクション後に任意のタイミングで音声を再生できるようになりました。
なかなか調査や回避方法に苦労したため、同じく困っている方の役に立てばと思います。
DMMグループ Advent Calendar 2020の記事でした。
明日の11日目はjuve_534さんです。よろしくお願いします!