システム開発部のTです。今回は、画面ごとに固有のバックミュージックを流すための実装を書いていきたいと思います。ここでは画面、アプリケーション、画面遷移のライフサイクルが重要となってきますので、よろしければ、以下のページも参照いただければ幸いです。 Flutterでアプリ開発・ライフサイクルについて 概要 例として、以下の3つの画面が存在しており、それぞれの画面で専用のBGMを流せるようにしようと思います。 また、各画面でアプリがバックグラウンド状態になったとき、別画面に遷移するときBGMを一時停止するという形を想定します。 Androidの場合、画面Aの状態で戻るボタン押下したときはアプリが終了するので、当然BGMも終了させるようにします。 上記の仕様を踏まえて、以降進めていきます。 ライブラリについて BGMを鳴らすため、以下のライブラリをpubspec.yamlのdependenciesに設定してください。 audioplayers また、BGMのリソースファイルをどこに置くかも合わせて定義しておきましょう。本件では、プロジェクト直下に「/assets/bgm/」フォルダを用意したところにファイルを置くので、pubspec.yamlの「flutter:」の「assets:」に「assets/bgm/」を定義しておきます。 これで準備はできました。 BGM用のリソースファイルの準備 本件では、BGM素材としてMP3を利用します。OGGやAACとかありますが、MP3のほうが両OSでサポートしているので、こちらを利用します。 プロジェクトトップにて「assets」フォルダを作って、更にその下に「bgm」フォルダを作ったなかにMP3ファイルを入れていきます。 上記では3つのMP3ファイルを入れていますね。 プレイヤークラスの実装 早速ですが、BgmPlayerというクラスを作成していきます。 上記の内容を簡単に説明します。 コンストラクタでMP3ファイル名と、ループ再生有無を受け取ります。呼び出しは以下の感じになります。 気をつける必要があるのは、「assets/bgm/」以下にファイルがある場合、「assets」は省略します。したがって、「assets」以降の「bgm/」からのパスを渡すことになります。 その後、AudioCacheのplayまたはloopを実行することで、MP3が再生されるしくみです。再生するだけであれば、そんなに難しいものではありません。 resumeBgm()は、バックグラウンドからフォアグラウンド状態に戻ったとき、または、遷移先の画面から戻ってきたときにコールするメソッドになります。これを行うことで、pauseBgm()で一時停止していたBGMが続けて再生されるようになります。 pauseBgm()は、フォアグラウンドからバックグラウンド状態になったとき、または、別画面に遷移するときに、一時的に停止させたい場合にコールします。その後、画面の状態が戻ったときにresumeBgm()をコールすることで、再生が継続されます。 stopBgm()については、再生している画面をNavigator.pop()で終了させる場合、以降で記載しているdisposeBgm()とともにコールします。 disposeBgm()は、画面終了時の後始末の意味合いでコールします。 以上が、BgmPlayerクラスの説明となります。以降では、このクラスを利用して、画面ごとの再生を可能にするための実装になります。 main.dartの実装 画面遷移に必要な定義をあらかじめ実装しておきます。 共通Stateクラスの定義 画面遷移や、アプリ、画面の状態などはStateクラスで行いますが、各画面で実装となると手間にもなるので、共通クラスを作って、そこに実装していきたいと思います。今回、BGMの再生、停止などは、この共通クラス上で行います。また、本件はアプリ、画面、画面遷移それぞれのライフサイクルを活用して実装しています。ライフサイクルについては、Flutterでアプリ開発・ライフサイクルについてを一読いただければと思います。 ちょっと長いコードになってしまいましたが、ご理解ください。わかりづらくしているところですが、いくつか抑えるポイントがありますので、以下に記載していきます。 戻る操作についての対応 ヘッダーの戻るボタン押下時、およびAndroidの戻るボタンを押下したときの対応も考慮する必要があります。通常、画面終了時にdispose()がコールされるため、そのタイミングでBGMの終了処理を入れておけば問題ありませんが、Androidの場合は戻るボタン押下時に画面の戻り先が存在しない場合はアプリが終了してしまいます。 アプリが終了するときも、dispose()はコールされるのですが、アプリ終了時にdisposeでBGMの終了処理を実装しても、なぜかBGMが止まらずに、再生が止まらない事象がございました。そのため、実際のPOPされる前に、BGMの終了処理を実装する必要があります。 POPされる前に処理をさせるための実装ですが、本件ではWillPopScopeを利用してPOP前にBGM終了処理を実装しました。それが、以下になります。 上記のonWillPop内で後始末処理が可能となります。また、async付きなので、await付きの同期的に処理することができます。そのため、disposeBgm()が終わったあとに、実際のPOP処理が実行されるので、アプリ終了時にBGMを止めることができます。 上記により、Androidのアプリ終了処理に対応できます。 isActiveの役割 本件では、画面が3つあることを前提としていますが、では以下のように画面遷移を行った場合・・・、 画面A → 画面B → 画面C 現在画面Cが画面に表示された状態だと思ってください。その状態のなか、画面AとBはどうなっているでしょうか。バックグラウンド状態?いやいや、普通にフォアグラウンド状態ですよね? 画面A(フォア) → 画面B(フォア) → 画面C(フォア)なんですね・・・。 単純に、画面Cが画面AとBの上に表示されているだけの話であり、アプリ的にはフォアグラウンドでしかありません。では、現在表示されている画面Cがアクティブ状態であることをどのように判定するか?結論から記述すると、判定する手段がないようですので、手動でフラグ操作の対応をしたものが、isActiveになります。 これが無いとどうなってしまうのか?画面A → 画面B → 画面Cと呼び出して、現在画面Cだとします。画面AもBもBGMが一時停止状態、画面CのみBGMが再生されている状態です。ここで、ホームボタンを押してバックグラウンドにしたとします。当然、画面CのBGMが止まります。今の状態で、アプリを再度フォアグラウンド状態にすると・・・、isActiveが無かった場合、画面A、B、Cが一斉にフォアグラウンド状態を検知し、盛大に3曲が再生されてしまうのでした・・・。 それを防ぐために、isActiveというフラグ操作を実装し、裏側に隠れている状態では、BGMを再生しないように制御する必要がありました。このフラグのおかげで・・・、 画面A(isActive=false) → 画面B(isActive=false) → 画面C(isActive=true) アプリをバックグラウンドに切り替え、再度フォアグラウンドにしても・・・、 isActive=trueの画面CのみがBGM再生されるようになる仕組みになります。 上記以外は難しいところは特になく、コメントの記載どおりになります。 各画面への実装 以降、各画面の実装になります。(以下は画面Aの実装例になりますが、画面B、Cも同様になります) Stateクラスの親クラスを、作成済みのBasePageStateに置き換えてください。コンストラクタ上にて、親クラスのコンストラクタに再生したいMP3のファイル名を設定してください。再生が不要の場合、親コンストラクタの呼び出し自体を無くせばOKです。 以下、PageBとPageCの画面コードも載せておきますね。BGMファイル名については、ご自身で準備いただいたものに置き換えてください。 動作確認 […]

Read more of this post