この Codelab は、Kotlin を使った高度な Android 開発コースの一部です。Codelab を順番に進めると、このコースを最大限に活用できますが、これは必須ではありません。コースの Codelab はすべて、Kotlin を使った高度な Android 開発の Codelab ランディング ページに記載されています。
はじめに
通知は、アプリの UI の外でユーザーに表示されるメッセージです。デバイスのロックが解除されている場合は画面上部に通知が表示されます。デバイスがロックされている場合は、セキュリティ設定に応じてロック画面に通知が表示されます。
一般的な通知は、タイトル、説明、アイコンで構成されます。通知には、クリック可能なアクション、クイック返信、拡張可能なコンテンツ、画像を含めることもできます。
通知はタイムリーな情報を配信でき、返信の送信やアラームのスヌーズなどのクイック操作を実行するためのボタンを含めることができます。通知をクリックすると、通知の内容に関連するアプリのビューに移動します。
通知は、アプリがバックグラウンドで実行されているときに、重要なタスクをユーザーにリマインドしたり、何かが発生したことをユーザーに知らせたり、ユーザーがすぐに必要とする重要な情報を伝えたりするのに役立ちます。通知は控えめに使用します。ユーザーへの配慮を示すだけでなく、アプリの通知が注目を集める可能性も高まります。
この Codelab では、Android アプリで通知を作成して使用する方法を学びます。
前提となる知識
以下について把握しておく必要があります。
- Kotlin で Android アプリを作成する方法。特に、Android SDK を使用します。
- アーキテクチャ コンポーネントとデータ バインディングを使用してアプリを設計する方法。
- BroadcastReceiver に関する基本的な知識
- AlarmManager に関する基礎知識
学習内容
- 通知の作成、スタイル設定、送信方法。
- 通知をキャンセルする方法
- 通知チャンネルを作成する方法。
- 通知にクイック アクションを追加する方法。
- アプリアイコンに通知バッジを表示する方法。
演習内容
- スターター アプリに通知を追加します。
- 以前に送信した通知をキャンセルします。
- さまざまな種類の通知用のチャネルを作成します。
- スターター アプリで通知をカスタマイズします。
- クイック アクションを追加して、通知をインタラクティブにします。
- 通知バッジをオフにします。
卵を調理するのは簡単ですが、時間を計り間違えると難しい作業になることがあります。この Codelab では、卵タイマー アプリを操作して、将来の卵のように完璧なものにします。まず、ユーザーが卵のスタイルごとに異なる調理時間を設定できる、動作する卵タイマー アプリを作成します。タイマーは選択した時間間隔からカウントダウンし、卵がゆで上がるとトースト メッセージを表示します。
機能的には問題ないように見えますが、完璧とは言えず、ユーザー フレンドリーとは言えません。まず、トースト メッセージは短時間しか表示されないため、見逃しやすいという問題があります。また、アプリがフォアグラウンドにない場合やデバイスがロックされている場合、トースト メッセージが消えると、タイマーのステータスを示す視覚的なインジケーターが表示されません。
理想的には、タイマーが終了したときに通知でユーザーに知らせるべきです。卵がすぐに調理できることをユーザーに知らせる必要があります。そうしないと、卵が調理しすぎになってしまいます。通知は視覚的なもので、音を含めることも、デバイスを振動させることもできます。これらはすべて、ユーザーの注意を引くための方法です。こうすることで、完璧な卵と、満足して満腹になったユーザーを実現できます。
サンプルアプリを入手するには、次のいずれかを行います。
GitHub からリポジトリのクローンを作成し、starter ブランチに切り替えます。
$ git clone https://github.com/googlecodelabs/android-kotlin-notifications
または、リポジトリを ZIP ファイルとしてダウンロードし、Android Studio で開くこともできます。
- Android Studio でアプリを開いて実行します。
卵の画像と、卵を調理するための事前定義された時間間隔のリストを含むプルダウン メニューが表示されます。[半熟] プルダウン メニューの三角形をクリックします。リストの最初のオプションはテスト用で、アラームを 10 秒に設定します。リストの横には、タイマーを開始するスイッチがあります。このスイッチを使用すると、いつでもゆで卵タイマーを開始および停止できます。スターター コードは完全に動作します。つまり、タイマーを設定して、カウントダウンが 0 になるのを確認できます。タイマーが終了すると、次のようなトースト メッセージが表示されます。
- ソースコードを検査します。スターター アプリは、
MainActivity
という 1 つのアクティビティで構成されています。receiver
、ui
、util
という名前の 3 つのサブパッケージがあります。
- /receiver -
receiver
パッケージには、AlarmReceiver
とSnoozeReceiver
という 2 つのブロードキャスト レシーバが含まれています。AlarmReceiver
はAlarmManager
によってトリガーされ、ユーザー定義のタイマーが切れたときに通知を送信します。SnoozeReceiver
は、ユーザーが通知をスヌーズするためにクリックしたときの処理を行います。 - /ui - アプリの UI 部分である
EggTimerFragment
が含まれています。EggTimerViewModel
は、タイマーの開始とキャンセル、その他のライフサイクル関連のアプリタスクを担当します。 - /util - このパッケージには 2 つのファイルがあります。
BindingUtils.kt
には、アプリの UI とViewModel
の間でデータ バインディングを有効にするバインディング アダプターがあります。NotificationUtils.kt
にはNotificationManager
の拡張メソッドがあります。
通知は、ユーザーの注意をアプリに引き付けるのに最適な方法です。アプリが実行されていない場合でも、フォアグラウンドで実行されている場合でも、通知は画面上部にポップアップ ウィンドウを表示し、音やバイブレーションを含めることができます。通知を作成するには、通知ビルダーを使用して、タイトル テキスト、コンテンツ テキスト、アイコンを指定する必要があります。ビルダーに必要なフィールドがすべて揃うと、システム サービスである NotificationManager
が、このコンテンツを通知として表示します。NotificationManager
は、通知の送信、コンテンツの更新、通知のキャンセルを担当します。次の手順では、NotificationManager
に拡張メソッドを追加します。これにより、NotificationManager
を使用する必要があるたびに、これらの拡張関数を使用して必要な機能を実現できます。
ステップ 1: 基本的な通知を作成する
このタスクでは、新しい通知を作成し、ユーザー向けのメッセージを設定して、通知を送信します。
NotificationUtils.kt
クラスを開き、TODO: Step 1.1
を見つけます。この Codelab とアプリコードには、一致する TODO があります。- 指定された
sendNotification()
関数を調べます。この拡張関数をNotificationManager
に拡張して、通知を送信します。
//NotificationUtils.kt
// TODO: Step 1.1 extension function to send messages (GIVEN)
/**
* Builds and delivers a notification.
*
* @param messageBody, notification text.
* @param context, activity context.
*/
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
- 通知ビルダーのインスタンスを取得し、アプリ コンテキストとチャンネル ID を渡します。チャンネル ID はチャンネルの文字列値です。
通知チャンネルは、通知をグループ化する方法です。類似したタイプの通知をグループ化することで、デベロッパーとユーザーはチャンネル内のすべての通知を制御できます。チャネルを作成すると、任意の数の通知を配信するために使用できます。
//NotificationUtils.kt
// TODO: Step 1.2 get an instance of NotificationCompat.Builder
val builder = NotificationCompat.Builder(
applicationContext,
applicationContext.getString(R.string.egg_notification_channel_id)
)
- 通知アイコンをアプリを表すものに設定し、タイトルと、ユーザーに伝えたいメッセージのコンテンツ テキストを設定します。この Codelab では、通知をさらにカスタマイズするためのオプションをいくつか紹介しますが、通知を送信するために設定する必要があるデータの最小量は次のとおりです。
//NotificationUtils.kt
// TODO: Step 1.3 set title, text and icon to builder
.setSmallIcon(R.drawable.cooked_egg)
.setContentTitle(applicationContext.getString(R.string.notification_title))
.setContentText(messageBody)
- 次に、通知の一意の ID とビルダーの
Notification
オブジェクトを使用してnotify()
を呼び出す必要があります。
この ID は現在の通知インスタンスを表し、この通知の更新またはキャンセルに必要です。アプリで一度にアクティブになる通知は 1 つだけなので、すべての通知に同じ ID を使用できます。この目的のために、NotificationUtils.kt
に NOTIFICATION_ID
という定数がすでに用意されています。同じクラスの拡張関数から呼び出しを行っているため、notify()
を直接呼び出すことができます。
//NotificationUtils.kt
// TODO: Step 1.4 call notify to send the notification
// Deliver the notification
notify(NOTIFICATION_ID, builder.build())
ui/EggTimerViewModel.kt
を開き、startTimer()
関数を見つけます。この関数は、ユーザーがタイマーを有効にしたときに、選択した時間間隔でアラームを作成します。- ユーザーがタイマーを開始すると、この関数で通知がトリガーされます。前に実装した
sendNotification()
関数を呼び出すには、NotificationManager
のインスタンスが必要です。NotificationManager
は、追加した拡張関数を含む、通知 API 用に公開されたすべての関数を提供するシステム サービスです。通知を送信、キャンセル、更新するたびに、システムからNotificationManager
のインスタンスをリクエストする必要があります。通知メッセージとコンテキストを指定してsendNotification()|
関数を呼び出します。
// EggTimerViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager
// and call sendNotification
val notificationManager = ContextCompat.getSystemService(
app,
NotificationManager::class.java
) as NotificationManager
notificationManager.sendNotification(app.getString(R.string.timer_running), app)
あと少しです。ただし、アプリを今実行してタイマーを設定しても、通知は届きません。
logcat
を開き、"No Channel found"
を検索します。egg_channel
が存在しないというエラー メッセージが表示されます。次の手順では、通知チャンネルについて詳しく説明し、この問題を解決します。
ステップ 2: 通知チャンネル
API レベル 26 以降では、すべての通知をチャンネルに割り当てる必要があります。アプリ ランチャー アイコンを長押しして [アプリ情報] を選択し、[通知] をタップすると、アプリに関連付けられている通知チャンネルのリストが表示されます。現時点では、アプリでチャンネルが作成されていないため、リストは空です。
チャンネルは通知の「タイプ」を表します。たとえば、卵がゆで上がったときに通知を送信するタイマーと、朝食に卵を食べることをリマインドする毎日の通知を送信する別のチャンネルを使用できます。チャンネル内のすべての通知がグループ化され、ユーザーはチャンネル全体の通知設定を構成できます。これにより、ユーザーは関心のある通知の種類に基づいて通知設定をカスタマイズできます。たとえば、朝食の通知は無効にしても、タイマーの通知は表示するように設定できます。
デベロッパーは、チャネル内のすべての通知に適用される初期設定、重要度、動作を設定します。初期設定を行った後、ユーザーはこれらの設定を上書きできます。
ステップ 1.1 で通知チャネルとして egg_notification_channel_id
を使用したので、このチャネルの通知設定と動作を実際に作成してカスタマイズする必要があります。
EggTimerFragment.kt
を開き、createChannel()
関数を見つけます。- 一意のチャンネル ID を
NotificationChannel
のコンストラクタに渡します。 - 通知チャネル名を渡します。この名前は、ユーザーの [設定] 画面にも表示されます。
- 最後のパラメータとして、通知チャネルの重要度レベルを渡します。重要度レベルについては、この Codelab で後ほど説明します。ここでは、
NotificationManag
er.IMPORTANCE_LOW
を使用してください。 notificationChannel
オブジェクトでenableLights
を true に設定します。この設定を有効にすると、通知が表示されたときにライトが点灯します。notificationChannel
オブジェクトでlightColor
を赤に設定して、通知が表示されたときに赤色のライトを表示します。notificationChannel
オブジェクトで、enableVibration
を true に設定してバイブレーションを有効にします。notificationChannel
オブジェクトで、チャンネルの説明を‘Time for breakf
ast' に設定します。getSystemService()
を呼び出して、NotificationManager
のインスタンスを取得します。-
NotificationManager
でcreateNotificationChannel()
を呼び出し、前の手順で作成したnotificationChannel
オブジェクトを渡します。
//EggTimerFragment.kt
private fun createChannel(channelId: String, channelName: String) {
// TODO: Step 1.6 START create a channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_LOW
)
// TODO: Step 2.6 disable badges for this channel
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
notificationChannel.enableVibration(true)
notificationChannel.description = "Time for breakfast"
val notificationManager = requireActivity().getSystemService(
NotificationManager::class.java
)
notificationManager.createNotificationChannel(notificationChannel)
}
// TODO: Step 1.6 END create channel
}
- 次に、チャンネルを作成するには、先ほど作成した
createChannel()
関数(ステップ 1.7)を呼び出す必要があります。この関数は、チャンネル ID とチャンネル名の 2 つのパラメータを受け取ります。プロジェクトですでに指定されている文字列リソースから、チャンネル ID とチャンネル名を検索する必要があります。
// EggTimerFragment.kt
// TODO: Step 1.7 call createChannel
createChannel(
getString(R.string.egg_notification_channel_id),
getString(R.string.egg_notification_channel_name)
)
- チャネル ID を通知ビルダーに渡す必要があります。この手順はステップ 1.2 で完了しています。チャネル ID に誤った値を設定すると、通知が失敗します。
NotificationUtils.kt
を開いて、以前に設定したチャンネル ID が正しいことを確認します。
// NotificationUtils.kt
val builder = NotificationCompat.Builder(
applicationContext,
// TODO: Step 1.8 verify the notification channel name
applicationContext.getString(R.string.egg_notification_channel_id)
)
- アプリを実行すると、タイマーを起動するたびにアプリから通知が送信されることがわかります。
- ステータスバーをプルダウンし、通知のタイトル、コンテンツ、アイコンが前の手順で設定したとおりになっていることを確認します。
- 新しく作成したチャンネルを確認するには、アプリを閉じてアプリのアイコンを見つけます。アプリアイコンを長押しして、[アプリ情報] を選択します。
- 設定の一覧から [通知] を選択します。[通知を表示] 設定のすぐ下に、[Egg] という名前の新しいチャンネルが表示されます。
アプリを実行すると、通知が表示されるようになりました。アプリ デベロッパーとユーザーの両方が、このチャネルで送信されるすべての通知の設定と動作をカスタマイズできます。通知の作成が完了しました。
ステップ 3: 通知をアプリに追加する
ここまでで通知 API の基本的な使用方法を示しましたが、タイマーの開始直後に通知を送信してもあまり意味がありません。ユーザーは、卵ができたときに通知を受け取ることを望んでいるでしょう。Codelab の次のパートでは、この問題を修正し、トースト メッセージを通知に変更します。
通知を送信し、ユーザーにどのように表示されるかを確認しました。これは優れた通知を作成するための最初のステップにすぎません。このステップでは、通知がより適切なタイミングで送信されるように変更します。
アプリが AlarmManager
を使用してアラームを設定する。AlarmManager
に関連するコードはスターター コードにすでに記述されており、トースト メッセージの表示に使用されています。AlarmManager
は、選択した時間帯を追跡し、時間が経過すると AlarmReceiver.kt
の onReceive()
関数をトリガーします。AlarmReceiver.kt
を開いて onReceive()
に移動すると、タイマーを設定するたびに表示されるトースト メッセージが表示されます。
AlarmReceiver.kt
(NotificationManager
のインスタンス)を開き、メッセージ テキストとコンテキスト パラメータを指定してsendNotification()
関数を呼び出します。
// AlarmReceiver.kt
// TODO: Step 1.9 add call to sendNotification
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.sendNotification(
context.getText(R.string.eggs_ready).toString(),
context
)
- タイマーが終了したときにアプリから通知が送信されるため、必要に応じてトーストを削除します。
// AlarmReceiver.kt
// TODO: Step 1.10 [Optional] remove toast
// Toast.makeText(
// context,
// context.getText(R.string.eggs_ready),
// Toast.LENGTH_SHORT
// ).show()
- アプリを実行します。タイマーを開始するたびと、タイマーが終了するたびに通知が表示されます。
これは理想的ではありません。ユーザーに送信する通知の数を減らしたい。ユーザーがタイマーを開始したときに送信される最初の通知は削除できます。
EggTimerFragment.kt
を開き、ステップ 1.5 の通知コードを削除します。
// EggTimeViewModel.kt
// TODO: Step 1.5 get an instance of NotificationManager
// and call sendNotification
// val notificationManager = ContextCompat.getSystemService(
// app,
// NotificationManager::class.java
// ) as NotificationManager
// notificationManager.sendNotification(app.getString(R.string.eggs_ready), app)
- アプリを再度実行します。
- タイマーを設定してバックグラウンドに移動し、時間が経過するまで待ちます。通知が表示されます。この通知ははるかに便利です。
ステップ 4: コンテンツ インテントを追加する
- アプリがまだ実行されていない場合は、再度実行します。
- この通知をクリックすると、何も起こりません。
通知を表示してユーザーに知らせることは重要ですが、ユーザーが通知をクリックしたときに、対応するアプリに戻ることを期待しています。この Codelab のパートでは、ユーザーをタイマー画面に戻すためのインテントを通知に追加します。
Intent
は、別のアプリ コンポーネントにアクションをリクエストするために使用できるメッセージング オブジェクトです。インテントは、アクティビティやサービスの開始、ブロードキャストの配信に使用できます。この場合、ユーザーが通知をタップしたときに MainActivity
を開くようシステムに指示するために、このインテントを使用します。アプリは 1 つのビューで構成されているため、ここでは多くのオプションはありません。ただし、大規模なアプリでは、通知をタップしたときに表示される画面が、通知の操作に合った画面になるようにして、シームレスなエクスペリエンスを実現する必要があります。
NotificationUtils.kt
を開き、sendNotification()
拡張関数を見つけます。applicationContext
と起動するアクティビティMainActivity::class.java
を使用してIntent
を作成します。
// NotificationUtils.kt
fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
// Create the content intent for the notification, which launches
// this activity
// TODO: Step 1.11 create intent
val contentIntent = Intent(applicationContext, MainActivity::class.java)
インテントは作成しましたが、通知はアプリの外部に表示されます。アプリの外部でインテントを機能させるには、新しい PendingIntent
を作成する必要があります。
PendingIntent
は、別のアプリまたはシステムに、アプリに代わってオペレーションを実行する権限を付与します。PendingIntent
自体は、システムによって管理されているトークンへの参照であり、取得に使用された元のデータを記述しています。つまり、所有アプリのプロセスが強制終了されても、PendingIntent
自体は、渡された他のプロセスから引き続き使用できます。この場合、タイマーアプリが実行中かどうかに関係なく、システムは保留中のインテントを使用して、ユーザーに代わってアプリを開きます。
applicationContext
、NOTIFICATION_ID
、前の手順で作成したcontentIntent
、PendingIntent
フラグを使用してPendingIntent
を作成します。PendingIntent
フラグは、新しいPendingIntent
を作成するか、既存のPendingIntent
を使用するかを指定します。既存の通知がある場合は新しい通知を作成しないため、フラグとしてPendingIntent.FLAG_UPDATE_CURRENT
を設定する必要があります。このようにして、指定したインテントに関連付けられている現在のPendingIntent
を変更します。
// NotificationUtils.kt
// TODO: Step 1.12 create PendingIntent
val contentPendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_ID,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
PendingIntent
を通知に渡します。これを行うには、NotificationBuilder
でsetContentIntent()
を呼び出します。通知をクリックすると、PendingIntent
がトリガーされ、MainActivity
が開きます。- また、
setAutoCancel()
をtrue
に設定して、ユーザーが通知をタップしたときに、アプリに移動すると同時に通知が自動的に消去されるようにします。
// NotificationUtils.kt
// TODO: Step 1.13 set content intent
.setContentIntent(contentPendingIntent)
.setAutoCancel(true)
- アプリを再度実行します。
- タイマーを設定し、アプリをバックグラウンドに移動して、通知が表示されるまで待ちます。
- 通知が表示されたら、ステータスバーを下にドラッグして通知をクリックし、アプリがフォアグラウンドに表示される様子を確認します。
ステップ 5: 通知をキャンセルする
通知機能付きのタイマーは動作しますが、小さな問題があります。タイマーを設定して通知を受け取り、再度タイマーを設定すると、新しいタイマーが実行されている間も、以前の通知がステータスバーに表示されたままになります。アプリがバックグラウンドにある場合、ユーザーが混乱する可能性があります。また、卵が半熟になる可能性があります。
この問題を解決するには、新しいタイマーを開始するときに以前の通知を消去する必要があります。まず、NotificationUtils.kt
に別の拡張関数を作成します。NotificationManager
には、cancelAll
()
というすべてのアクティブな通知をキャンセルする API があります。
NotificationsUtil.kt
を開きます。cancelAll()
を呼び出すNotificationManager
の拡張関数を追加します。
// NotificationUtils.kt
// TODO: Step 1.14 Cancel all notifications
/**
* Cancels all notifications.
*
*/
fun NotificationManager.cancelNotifications() {
cancelAll()
}
EggTimerViewModel.kt
を開き、startTimer()
関数に移動します。startTimer()
内で、システムからNotificationManager
のインスタンスを取得し、cancelNotifications()
を呼び出します。
// EggTimerViewModel.kt
//TODO Step 1.15 call cancel notification
val notificationManager =
ContextCompat.getSystemService(
app,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelNotifications()
- アプリを実行し、タイマーを開始します。
- 通知が表示されたら、タイマーを再度開始し、アプリがステータス バーから以前の通知を自動的に削除する様子を確認します。
通知フレームワークには、デベロッパーがカスタム アクションを設定し、必要に応じて通知のスタイルを設定するためのさまざまなカスタマイズ オプションが用意されています。このタスクでは、ゆで卵タイマーの通知をカスタマイズする方法を学習します。
ステップ 1: 通知のスタイルを設定する
ニーズや通知の内容に合わせて通知のスタイルを設定すると、通知が目立ち、アプリの拡張機能のように見えます。通知フレームワークには、いくつかの組み込みスタイルが用意されています。また、独自のスタイルを作成することもできます。
NotificationCompat
には、次の組み込みスタイルが用意されています。
BigTextStyle
。展開するとメールの内容が表示されるなど、大きなテキスト ブロックを表示できます。BigPictureStyle
。大きな画像添付ファイルを含む大判の通知を表示します。- 会話スタイルのテキスト コンテンツを表示する
InboxStyle
。 MediaStyle
(メディア再生のコントロールを表示します)。MessagingStyle
。複数のユーザー間の複数のメッセージを含む大判の通知が表示されます。
他のスタイルについて詳しくは、展開可能な通知を作成するのドキュメントをご覧ください。このステップでは、NotificationCompat.BigPictureStyle
を使用して、展開すると大きな卵の画像が表示される展開可能な通知を作成します。
NotificationUtils.kt
を開き、sendNotification()
関数を見つけます。- まず、
BitmapFactory
を使用してresources
から画像を読み込みます。
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
- 新しい
BigPictureStyle
を作成して、イメージを設定します。 bigLargeIcon()
をnull
に設定し、通知が展開されたときに大きなアイコンが表示されないようにします。
// NotificationUtils.kt
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.cooked_egg
)
val bigPicStyle = NotificationCompat.BigPictureStyle()
.bigPicture(eggImage)
.bigLargeIcon(null)
setStyle()
を使用してスタイルをbigPicStyle
に設定します。setLargeIcon()
で大きなアイコンをeggImage
に設定し、通知が折りたたまれたときに画像が小さなアイコンとして表示されるようにします。
// NotificationUtils.kt
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
- アプリを実行してタイマーを設定します。通知が最初に表示されるときは、通知ドロワーで折りたたまれた状態になっています。通知を展開すると、拡張された通知領域に大きな画像が表示されます。
ステップ 2: 通知のアクション
通知アクションは、通知に追加できるもう 1 つのカスタマイズです。現在、ユーザーが通知をクリックすると、アプリにリダイレクトされます。このデフォルトの操作に加え、通知からアプリ関連のタスクを実行する操作ボタンを追加することもできます。
通知には、ユーザーがすばやく応答できるようにするためのアクション ボタン(リマインダーのスヌーズやテキスト メッセージへの返信など)を最大で 3 つ設定できます。これらのアクション ボタンは、ユーザーが通知をタップしたときに実行されるアクションと同じであってはなりません。
アクション ボタンを追加するには、ビルダーの addAction()
関数に PendingIntent
を渡します。これは、setContentIntent()
を呼び出して通知のデフォルトのタップ アクションを設定する場合と同様です。ただし、アクティビティを起動する代わりに、バックグラウンドでジョブを実行する BroadcastReceiver
を開始するなどのさまざまな処理を実行でき、アクションはすでに開いているアプリを中断しません。
この Codelab では、SnoozeReceiver
という名前の BoadcastReceiver
がすでに提供されています。SnoozeReceiver
を使用して、ユーザーが通知アクションをクリックしたことを受け取ります。次の手順では、ユーザーがスヌーズ アクション ボタンをクリックしたときに、卵タイマーの通知を 60 秒間スヌーズするコードを追加します。スヌーズ アクションがクリックされると、SnoozeReceiver
はインテントを受け取り、60 秒後に新しい通知を送信する新しいアラームを作成します。
SnoozeReceiver.kt
を開きます。このクラスは、以前に使用したAlarmReceiver
と似ています。次の手順では、SnoozeReceiver
のonReceive()
関数をトリガーするコードを追加します。つまり、SnoozeReceiver
のコードは、1 分後に新しい通知を送信する新しいアラームを作成します。onReceive 関数の下部までスクロールし、システムから notificationManager のインスタンスを取得して、cancelAll を呼び出します。
// SnoozeReceiver.kt
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.cancelAll()
SnoozeReceiver
を使用するには、NotificationUtils.kt
を開きます。-
sendNotification()
関数のスタイルの直後に、SnoozeReceiver
の新しいIntent
snoozeIntent
を作成します。 - 次の手順でパラメータを必要とする
PendingIntent
のgetBroadcast()
メソッドを呼び出して、保留中のインテントを作成します。このPendingIntent
は、ユーザーがスヌーズ ボタンをタップしたときに 60 秒後に新しい通知を投稿する新しいアラームを設定するためにシステムによって使用されます。 - 最初のパラメータは、この
PendingIntent
がアクティビティを開始するアプリ コンテキストです。 - 2 番目のパラメータはリクエスト コードです。これは、この保留中のインテントのリクエスト コードです。この保留中のインテントを更新またはキャンセルする必要がある場合は、このコードを使用して保留中のインテントにアクセスする必要があります。
- 次に、起動するアクティビティのインテントである
snoozeIntent
オブジェクトを追加します。 - 最後に、インテントは 1 回のみ使用されるため、
#FLAG_ONE_SHOT
のフラグ値を追加します。クイック アクションと通知は最初のタップ後に消えるため、インテントは 1 回しか使用できません。
// NotificationUtils.kt
// TODO: Step 2.2 add snooze action
val snoozeIntent = Intent(applicationContext, SnoozeReceiver::class.java)
val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(
applicationContext,
REQUEST_CODE,
snoozeIntent,
FLAGS
)
- 次に、
notificationBuilder
でaddAction()
関数を呼び出します。この関数は、アイコンと、ユーザーにアクションを説明するテキストを想定しています。また、snoozeIntent
も追加する必要があります。このインテントは、アクションがクリックされたときに適切なboadcastReceiver
をトリガーするために使用されます。
// NotificationUtils.kt
// TODO: Step 2.3 add snooze action
.addAction(
R.drawable.egg_icon,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
- タイマー アプリを実行して、スヌーズ アクションをテストします。
- タイマーを実行し、アプリをバックグラウンドに移動します。タイマーが切れたら、通知を開きます。通知にスヌーズ アクション ボタンが表示され、タイマーを 1 分間スヌーズできるようになっています。
ステップ 3: 通知の重要度
重要度によって、通知の表示と音を決定します。重要度の高い通知ほど、ユーザーの邪魔になる可能性が高くなります。
重要度レベルは NotificationChannel
コンストラクタで指定する必要があります。タイマー アプリの重要度は、当初は低に設定されていました。重要度は IMPORTANCE_NONE(0)
から IMPORTANCE_HIGH(4)
までの 5 つのレベルの中から選択できます。通知チャネルに割り当てた重要度は、そのチャネルに送信されるすべての通知メッセージに適用されます。
チャンネルの重要度レベル
ユーザーへの表示の重要度 | 重要度(Android 8.0 以上) | 優先度(Android 7.1 以前) |
音を鳴らし、ヘッドアップ通知として表示(画面の上部にポップアップ表示) | ||
音を鳴らす | ||
音声なし | ||
無音、ステータスバーにも表示しない |
適切な優先度を選択する方法については、通知設計ガイドの「優先度」をご覧ください。アプリの通知の重要度を選択する際は注意が必要です。チャンネルの重要度は、ユーザーの時間と注意を考慮して選択する必要があります。重要でない通知が緊急であるかのように装われていると、不要なアラームが発生し、気が散ることがあります。ユーザーは通知の重要度を完全に制御できるため、迷惑な通知を作成すると、通知チャネルを完全にオフにされる可能性があります。
ステップ 1.6 で通知を初めて作成したとき、通知でユーザーを邪魔しないように、卵型タイマーは優先度の低い通知を送信するように設定されていました。ただし、卵が焦げる前にユーザーの注意を引くことをおすすめします。通知の重要度を変更するには、まずチャンネル設定から始めます。チャネルの重要度は、そのチャネルに送信されるすべての通知の割り込みレベルに影響します。重要度は、NotificationChannel
コンストラクタ内で指定する必要があります。
- アプリの通知チャネルの重要度を変更するには、
EggTimerFragment.kt
を開いてcreateChannel()
に移動します。重要度レベルをIMPORTANCE_LOW
からIMPORTANCE_HIGH
に変更します。
// EggTimerFragment.kt
val notificationChannel = NotificationChannel(
channelId,
channelName,
// TODO: Step 2.4 change importance
NotificationManager.IMPORTANCE_HIGH
)
Android 7.1(API レベル 25)以前を搭載しているデバイスをサポートするには、NotificationCompat
クラスの優先度定数を使用して、通知ごとに setPriority()
を呼び出す必要もあります。
NotificationUtils.kt
を開き、次のコードを通知ビルダー オブジェクトに追加します。
// NotificationUtils.kt
.addAction(
R.drawable.common_google_signin_btn_icon_dark,
applicationContext.getString(R.string.snooze),
snoozePendingIntent
)
// TODO: Step 2.5 set priority
.setPriority(NotificationCompat.PRIORITY_HIGH)
- アプリを実行する前に、デバイスまたはエミュレータでアプリアイコンを長押しし、[アンインストール] を選択して、以前のチャンネル設定をクリアします。アプリのアンインストールに失敗した場合、チャンネルの優先度の設定は変更されず、通知が投稿されたときに動作の変更は発生しません。
- アプリをもう一度実行して、タイマーを開始します。今回は、アプリがフォアグラウンドで実行されているかバックグラウンドで実行されているかに関係なく、通知が配信されると画面の上部にポップアップが表示されます。
ステップ 4: 通知バッジ
通知バッジは、アプリにアクティブな通知がある場合に、関連付けられたアプリのランチャー アイコンに表示される小さなドットです。アプリアイコンを長押しすると、通知が表示されます。
これらのドット(バッジ)はデフォルトで表示されるため、アプリ側で必要な処理はありません。ただし、通知によってはバッジが意味をなさない場合もあります。NotificationChannel
オブジェクトに対して setShowBadge(false)
を呼び出すことで、チャネルごとにバッジを無効にすることができます。タイマーは一度に 1 つのアクティブな通知しか表示しないため、アプリ アイコンのバッジはユーザーにとってあまりメリットがありません。次の手順では、バッジを無効にして、タイマーの通知のみを表示します。
- 卵タイマーのチャンネル作成コードに
setShowBadge(false)
を追加して、バッジを無効にします。
// EggTimerFragment.kt
).apply {
// TODO: Step 2.6 disable badges for this channel
setShowBadge(false)
}
- アプリを再度実行し、タイマーを開始して、アプリのアイコンを確認します。アプリアイコンにバッジは表示されません。
解答コードは、ダウンロードしたコードの master ブランチにあります。
- NotificationManager クラスを使用して、通知の作成、送信、更新、キャンセルを行います。
- createNotificationChannel メソッドで NotificationChannel オブジェクトを使用して、通知のチャネルを設定します。
- addAction() を使用して、通知にクイック アクションを追加します。
- setShowBadge() を使用して、バッジを有効または無効にします。
- Notification.Style から拡張されたスタイルを使用して通知のスタイルを設定する
- NotificationChannel.setImportance() で重要度レベルを設定します。
Udacity コース:
Android デベロッパー ドキュメント:
このコースの他の Codelab へのリンクについては、Kotlin を使った高度な Android 開発の Codelab のランディング ページをご覧ください。