システム開発部のTです。
以前にも「画面にBGMを奏でる」というタイトルで記事を出しましたが、
その続きの記事になります。

前回の記事のまま実装し、それをブラウザで動作させた場合、思うようにBGMが鳴らないかと思います。
原因として、以下のブラウザでの仕様によるものと思っていただければと思います。

Chromeの自動再生ポリシー
MACOSの自動再生ポリシーの変更

対応しない状態で動作させた場合の挙動

まず、対応しない状態でアプリをブラウザ上(Chrome上でデバッグ起動)させたとき、
最初の画面ではBGMが鳴らず、次画面遷移時に鳴り出す感じでした。
そのときにコンソール上には、以下のエラーメッセージが表示されます。

Error: NotAllowedError: play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD

要するに自動再生ポリシーに引っかかるためですね。
次画面で鳴る理由は、次画面遷移時にタップ操作するため、タップ操作後はBGMが鳴り出してくれます。
その後、次画面から呼び出し元の画面に戻ると、今度は呼び出し元の画面でもBGMが鳴り出します。

これを踏まえて、対応を検討します。

初回タップ用の画面を用意する

要するに、A画面の前にBGMを鳴らすことを示す初回タップ用の画面を用意し、
その画面を介してA画面へ進めばA画面から音が鳴るはずです。
つまり・・・

上記のような感じです。
ただし、ユーザーから音を鳴らすことを許可される必要があるため、最初の画面ではBGMのメディアをロード処理させたあと、A画面へのボタンタップさせる必要があります。そのため、無意味なことですが、最初の画面では無音のBGMを読み込ませる処理を実装する必要があります。

最初の画面のコーディングは以下のようになります。

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'BasePageState.dart';

class InitPage extends StatefulWidget {
  @override
  _InitPageState createState() {
    return _InitPageState();
  }
}

class _InitPageState extends BasePageState<InitPage> {  // <-- ここの親クラスを「BasePageState」にする

  _InitPageState(): super(fileName: "none_volume_bgm.mp3");  // <-- 無音のメディアファイルを設定

  @override
  Widget buildChildWidget(BuildContext context) {  // <-- 通常のbuildメソッドの代わりに実装
    return Material(
        child: Scaffold(
            appBar: AppBar(
              title: Text("最初の画面"),
              automaticallyImplyLeading: true,
            ),
            body: Container(
                child: Column(
                  children: [
                    Text("次の画面でBGMが鳴ります。"),
                    ElevatedButton(
                      child: Text("画面Aに進む"),
                      style: ElevatedButton.styleFrom(
                        primary: Colors.orange,
                        onPrimary: Colors.white,
                      ),
                      onPressed: () {
                        Navigator.pushNamed(context, "/pageA");
                      },
                    )
                  ],
                ),
              alignment: Alignment.center,
            )
        )
    );
  }
}

上記以外の処理については、前回の記事のままになります。

画面はこんな感じです。

動作確認

ここまでの実装後、ブラウザ上で動作確認してみましょう。
いかがでしょうか?
画面Aに進むと、画面Aに対応したBGMが鳴りだしたかと思います。
皆様もぜひ試していただき、華やかなWebページにしていきましょう!

緊急事態!iOSだと鳴らないよ!!!!!

iOSのブラウザ全般で思うような動作になりません・・・。
MacOS、Windowsその他のデスクトップPC、Androidの各種ブラウザでは動作するのですが・・・。

iOSだと、これでも鳴らなかったりします。
MacのSafariで鳴っても、iOSだとSafariはもちろん、Chromeでも再生されないのです。
(iOSの場合、ブラウザエンジンがすべて同じなので、Safariで鳴らないならChromeでも再生されない・・・)
iOSでの挙動を見てみると・・・、

こんな感じです。
ことごとく自動再生を拒否されていますね・・・。
唯一の手がかりとしては、C画面からB画面に戻るとき、B画面からA画面に戻るときに再生されます。
むむむ・・・。

想定ですが、A画面からB画面に遷移するときに、A画面の次画面遷移ボタンを押下していますが、そのタップを受けてBGM Aの再生許可が下りたのでは?と思っています。そのため、B画面からA画面に戻ったときに、A画面のdidPopNext()で実装しているBGM再生処理が動くことで、再生されたと思います。

やはりタップイベントありきの再生しかできないようですね・・・。

後半に続く

ということで、つづきは後半に持ち越しします。
iOS版のブラウザについては、タップイベントありきでの再生にしないと駄目なようです。
Android版、およびPC版については、本章でのやり方で再生されるのですが、iOS版は自動再生には厳しいようです。
(利用者、ユーザーにとっては優しい仕様ですが、開発者にとっては厳しい・・・)

後半は、iOS版ブラウザで画面ごとの再生をどう実装するかを書いていきたいと思います。



ギャップロを運営しているアップフロンティア株式会社では、一緒に働いてくれる仲間を随時、募集しています。 興味がある!一緒に働いてみたい!という方は下記よりご応募お待ちしております。
採用情報をみる