fresh digitable

めんどくさかったなってことを振り返ったり振り返らなかったりするための記録

Androidの通知で音を鳴らすときに注意したいこと

こんなことで困る人なんていないような気もするが、ネタとしては面白いと思ったのでまとめてみる。困っていることというのは、res/raw以下にある複数のファイルのうち任意の1つを消すと通知の着信音が変わってしまうということ。何を言っているか分からないと思うのでどうしたらそんなことになるのか一つずつ説明していく。

Androidの通知について

本題に入る前に通知の基本的なことを抑えておく。

developer.android.com

  • 通知は通知チャンネルを通してユーザーに届けられる。
  • 通知チャンネルはアプリが生成する。このとき、通知の着信音や振動、ライトのパターンなどを初期設定として渡せる。
  • 通知チャンネルは通知音や振動パターンの設定をユーザーが変えられる。
  • 通知チャンネルの設定はアプリから変更できない。
  • 通知チャンネルはプログラムで削除できるが、削除したことはアプリの設定画面に表示される。また、設定をリセットしたいと考えて一旦削除し、再び同じIDのチャンネルを作ろうとしたとしても、削除する前の通知チャンネルが復元されるだけで設定をリセットすることはできない。

ポイントは、通知チャンネルはアプリで生成した後はすべてユーザーの手にゆだねられるということで、ユーザーがOffにした通知をアプリから勝手にOnにするようなことはできない*1。また、間違って設定してしまってもアプリの側から修正することはできない。状態を是正したければアプリの設定からユーザーに依頼してデータを消してもらうしかない(アプリ情報>ストレージとキャッシュ>ストレージを消去)。

通知の着信音

通知チャンネルに通知が届いた際に、設定した着信音を鳴らすことができる*2。この音は次のAPIで、チャンネルを生成する際にファイルのURIを渡すことで指定できる: https://developer.android.com/reference/android/app/NotificationChannel#setSound(android.net.Uri,%20android.media.AudioAttributes)。また、ユーザーがアプリ設定の画面から音を設定することもできる。

このAPIはおそらくコンテンツプロバイダ経由でアクセスできるファイルのURIが渡されることを想定しているのではないかと思うのだが、実際にはアプリで抱えているファイルもファイルパスをURIで表現して渡せる。例えば、res/rawの下のファイルは次のようなURIで表現できるが、これを渡すことでアプリ独自の通知音を再生できるようになる。

android.resouce://<application ID>/raw/<resource name>

あるいは、

android.resource://<application ID>/<resource ID>

参考: stackoverflow.com

今回の問題の原因と対策

今回の敗因はリソースIDを使う方のURIでファイルを指定していたこと。リソースIDはビルドするたびに変わる可能性がある。今回は不要になったファイルを一つ消してビルドしたところ、そのファイルよりもアルファベット順で後にあるファイルのリソースIDが一つずつずれて、通知音が軒並み変わってしまった*3。この現象には開発中に気が付いたのでリリースされることはなかったが、やろうと思っていたことが一つできなくなってしまった。前述の通り、アプリから通知の設定を変えることはできないので、アプリ更新時にマイグレーションをすることはできない。

こんなことが起きるのは私の環境だけだろうか。ビルドするときにリソースIDを極力変えないみたいなフラグがあったりするのだろうか。デフォルトでそうなっていてほしいという気もする。ファイルを追加するときはリソースIDが変わらないのも不思議に思っている。

Androidの通知で音を鳴らしたいときは、リソースIDを使うURIで指定するのは避ける。また、できれば音ファイルをコンテンツプロバイダに登録して、そのURIを指定した方がよい。そうしておくと、ユーザーが誤って着信音の設定を変えてしまっても、ユーザー自身で元の着信音に戻すことができる。

*1:Offになっているという事はわかるので、ユーザーに「Onにしてね」といって促すことはできる

*2:通知に音を設定するのではなく、通知チャンネルに設定されている音が鳴る

*3:通知チャンネルを山ほど作るアプリを作っているわけです