日々の記録

SNS は無限に時間を溶かすのでやらないことにした

ローカル通知の実装メモ(Android)

とりあえず前回プッシュ通知やってみるって言ったので、今回はローカル通知を実装した時のメモ。 プッシュ通知が来たときにぺろーんって通知が出したいよね。今回はListView内のアイテムをクリックしたら、ピコンっ!って通知が出るようにした。こんな感じね。

ちなみに2020年2月現在、Google playにアップロードできるAndroid API Levelが確か26以上だったかと思います。なので、以降のソースコードtargetSDKVersion 26以降を前提にしているのであしからず。

最低限の通知を作るには以下を構成します。

  1. ライブラリの追加
  2. 通知がタップされた時の動作定義
  3. ぺローンって出る通知の画面を作成
  4. ペローンって出る通知のチャネル作成/登録
  5. ペローンって通知を出す

Android 8(API Level 26) 以降って通知にチャネルって概念ができたのよね。今までは、アプリケーションの通知ってアプリ全体でOn/Offしか出来なかったんです。なので、LINEとかでAndroidの設定画面から通知をオフにしちゃうとLINEの通知全部届かなくなってました。でもAndroid 8(API Level 26)以降はチャネルという新しい枠組みができたので、「このトークの通知はオフ」「このトークの通知はオン」と言うような制御がAndroidのシステム側で出来るようになりました。1つのアプリ内でも様々な通知の種類があるので、例えば広告系のチャネル、とかアプリの更新のお知らせチャネルとか通知のチャネルを分けることによって、よりユーザーが通知のオン/オフを管理しやすくなってます。チャネルの作成/登録はAndroid 8 (API Level 26)から必須になっているので、この概念を理解する必要があります。

1.ライブラリの追加

さて、本題。まずは通知を作成するための標準ライブラリをgradleに追加しましょう。API 26以降ではこちらのandroidx.core:coreのライブラリを追加してあげてください。androidx.core:coreのバージョンは必要に応じて任意のバージョンにしてください。

app/build.gradle

    dependencies {
        ...
        implementation 'androidx.core:core:1.2.0'
    }

2.通知がタップされた時の動作定義

通知がタップされた際に、アプリのアクティビティを呼び出すためにIntentを定義しています。

            /**
             * Set an Action for Notification is tapped. In this case, when the notification is
             * tapped, the application will be launched.
             */

            Intent intent = new Intent(MainActivity.this, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this,
                    0, intent, 0);

setFlags()で通知がタップされた際の動作を定義しています。もしアプリが起動していない状態でタップされるとFLAG_ACTIVITY_NEW_TASKでアプリが起動します。アプリが起動中の状態で通知がタップされるとFLAG_ACTIVITY_CLEAR_TASKとなり、デバイス戻るボタンが押されたのと同じように1つ前に戻る動作となります。最後にPendingIntentのオブジェクトを通知にセットすることで、通知がタップされた際にこのIntentからアプリが起動するようになります。ということで、次は

3.ぺローンって出る通知の画面を作成

ペローンって出す通知そのものの画面を作成です。これはちょー簡単。こんな感じ。

            /**
             * Configure Notification contents how it show at notification bar.
             */
            String CHANNEL_ID = "0";
            NotificationCompat.Builder nfBuilder = new NotificationCompat.Builder(
                    MainActivity.this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.ic_sms_black_24dp)
                    .setContentTitle("Tapped ListView")
                    .setContentText("You tapped " + item + " in ListView...")
                    .setCategory(NotificationCompat.CATEGORY_MESSAGE)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);

先ほど作成しておいたPendingIntentsetContentIntent()にセットすると、通知をユーザーがタップした際にアクションが実行されます。 setCategory()はデバイスがサイレントモードの時の通知の動作を指定しています。 setAutoCancel()は通知がタップされた場合に通知が消えます。 NotificationCompat.Builderのチェーンメソッドの設定は、通知の以下の画面と紐づいています。

4.ペローンって出る通知のチャネル作成/登録

次に通知のチャネルを登録しておきます。ぶっちゃけチャネル名なんてどうでも良くて、適当な名前でチャネルを作れば良いんじゃないでしょうかね。

            /**
             * Create a channel for the notification and set importance for it.
             * User can configure whether the notification turns on or off by channels.
             */
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    "ListView notification", NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("This channel is for ListView notification.");
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);

CHANNEL_IDはチャネルの種類を内部的に識別するためのString type のIDです。チャネル名と一致させておくと良いかと思います。NotificationManager.IMPORTANCE_HIGHは、通知を受信した際に、ピコンっ!ってAndroidの画面上部に通知を表示させたいときに設定します。HIGH以上の優先度にしないとステータスバーにアイコンが表示されるだけで、Heads-up通知のような動作はしません。

Heads-up notification  |  Android Developers

The heads-up notification appears the moment your app issues the notification and it disappears after a moment, but remains visible in the notification drawer as usual.

Example conditions that might trigger heads-up notifications include the following:

The user's activity is in fullscreen mode (the app uses fullScreenIntent). The notification has high priority and uses ringtones or vibrations on devices running Android 7.1 (API level 25) and lower. The notification channel has high importance on devices running Android 8.0 (API level 26) and higher.

5.ペローンって通知を出す

最後は先ほど作成した通知画面を出力します。

            int NOTIFICATION_ID = 0;
            NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(MainActivity.this);
            notificationManagerCompat.notify(NOTIFICATION_ID, nfBuilder.build());

NotificationManagerCompatにチャネルと、先ほど作成した通知画面をセットして、notifyメソッドを呼び出すと通知が表示されます。

ちなみにロック画面にも通知がこんな感じで表示されるようになります。

あと余談ですが、Android標準のアイコンを使ってアプリを作りたい場合(僕なんかはものぐさなので、自分でアイコンとか絶対作りたくないので出来合いで済ませたい)、こんな感じでプロジェクトのresディレクトリに標準のアイコンを追加できます。

1.Move to File > New > Vector Asset

2.Click an icon at "Clip Art"

3.Select an icon which you want to use and Click "OK"

4.Click "Next" 5.Click "Finish"

res ディレクトリに追加したアイコンはR値経由でこんな感じで呼び出せば良いかと思います。

            NotificationCompat.Builder nfBuilder = new NotificationCompat.Builder(
                    MainActivity.this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.ic_android_black_24dp) // <--先ほど追加したアイコンはこれ
                    ...

通知のsmallアイコンがBugdroid君に変わりました。

f:id:techsapp:20200301003030p:plain
00 Bugdroid at Notificaiton
f:id:techsapp:20200301003326p:plain
01 Bugdroid at Notification