【Kotlin/Android Studio】通知の実装方法!アプリ内からリクエスト(ローカル通知)

この記事からわかること

  • Android Studio/Kotlin通知機能実装方法
  • アプリ内から通知リクエスト送信するには?
  • ローカル通知とは?
  • チャンネルとは?
  • ヘッドアップ通知を表示する

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

参考文献:公式リファレンス:通知を作成する
参考文献:公式リファレンス:通知の概要

環境

Androidアプリの通知機能

【Kotlin/Android Studio】通知の実装方法!アプリ内からリクエスト(ローカル通知)

ローカル通知

ローカル通知とはオフラインで実行される通知機能のことを指します。デバイス内からプッシュ通知リクエストを送信し、デバイス内で処理されて通知が届くような仕組みになっています。

ローカル通知は事前準備などは必要なく、Kotlinのコードを記述するだけで実装することができます。

通知リクエストを送信するタイミングはアプリ内からしか操作できません。リマインダーやアラーム機能など自分でセットして使用するプッシュ通知などはこのローカル通知を使用して実装されています。

リモート通知

リモート通知とはオンラインで実行される通知機能のことを指します。ローカル通知とは異なり、プッシュ通知リクエストをオンライン上から送信し、デバイス内で処理されて通知が届くような仕組みになっています。

Firebaseの「Cloud Messaging」などを利用してリモート通知を送信することができます。以下はiOSですが実装方法です。

通知機能を実装する方法

流れ

  1. パーミッションの追加
  2. 通知許可ダイアログの表示
  3. 通知チャンネルの作成
  4. 通知の作成
  5. 通知の発行

パーミッションの追加

公式リファレンス:通知に関する実行時の権限

アプリで通知を利用したい場合は「AndroidManifest.xml」内にパーミッションを宣言する必要があります。今回は通知を利用したいのでPOST_NOTIFICATIONSを追加しておきます。


<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

通知許可ダイアログの表示

Manifest.permissionにはレベルが振られており、POST_NOTIFICATIONSはマニフェストファイルだけでなくアプリ実行時に許可を得る必要のあるdangerousレベルになっているので通知許可ダイアログも実装していきます。


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // 許可ダイアログを表示
    launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
}

private val launcher =
      registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
          // ダイアログの結果で処理を分岐
          if (result) {
              Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT)
                  .show()
          } else {
              Toast.makeText(this, "否認されました", Toast.LENGTH_SHORT)
                  .show()
          }
      }

実装方法の詳細は以下の記事を参考にしてください。

通知チャンネルの作成

通知の実装自体の肝となるのはここからになります。まずは必要となるIDをそれぞれ準備しておきます。


val CHANNEL_ID = "CHANNEL_ID"
val NOTIFY_ID = 1

Androidで通知機能を実装するためにはチャンネルを作成する必要があります。


// 1:通知チャンネルの作成
private fun createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = "チャンネル名"
        val descriptionText = "チャンネルの説明"
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
            description = descriptionText
        }
        // チャンネルをシステムに登録
        val notificationManager: NotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

通知の作成

チャンネルを作成したら通知本体を作成して発行するまでを実装していきます。「2:通知タップ時でアプリを起動する」の指定は自由ですが通知をタップした時にアプリが起動する方が自然なのでタップ時に起動させたいActivityを指定しています。


// 通知の作成と送信
private fun sendNotify() {
    // 2:通知タップ時でアプリを起動する
    val intent = Intent(this, MainActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent,  PendingIntent.FLAG_IMMUTABLE)

    // 3:通知オブジェクトの作成
    var builder = NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setContentTitle("通知のタイトル")
        .setContentText("通知の本文")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)

    // 4:通知の発行
    // 次で実装
}

通知の発行

最後に通知の送信処理です。notifyメソッドの引数に通知IDと先ほど作成したbuilderオブジェクトをbuildして渡します。


// 4:通知の発行
with(NotificationManagerCompat.from(this)) {
    notify(NOTIFY_ID, builder.build())
}

最後にonCreate内でそれぞれを呼び出してボタンのイベントに紐づければ完成です。


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // 許可ダイアログを表示
    launcher.launch(Manifest.permission.POST_NOTIFICATIONS)

    // チャンネルの生成
    createNotificationChannel()

    // 通知を発行ボタン
    val buttonNotification: Button = findViewById(R.id.button)
    buttonNotification.setOnClickListener {
        // 通知の作成と送信
        sendNotify()
    }
}

ボタンを押して通知が届くと上部のステータスバーの左側にアイコンが表示されるようになります。

【Kotlin/Android Studio】通知の実装方法!アプリ内からリクエスト(ローカル通知)

ステータスバーを下にスワイプすると通知ドロワーを確認することが可能です。

【Kotlin/Android Studio】通知の実装方法!アプリ内からリクエスト(ローカル通知)

コード全体


import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import android.Manifest
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts


class MainActivity : AppCompatActivity() {
    val CHANNEL_ID = "CHANNEL_ID"
    val NOTIFY_ID = 1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 許可ダイアログを表示
        launcher.launch(Manifest.permission.POST_NOTIFICATIONS)

        // チャンネルの生成
        createNotificationChannel()

        // 通知を発行ボタン
        val buttonNotification: Button = findViewById(R.id.button)
        buttonNotification.setOnClickListener {
            // 通知の作成と送信
            sendNotify()
        }
    }

    // 1:通知チャンネルの作成
    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val name = "チャンネル名"
            val descriptionText = "チャンネルの説明"
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
                description = descriptionText
            }
            // チャンネルをシステムに登録
            val notificationManager: NotificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }
    }

    // 通知の作成と送信
    private fun sendNotify() {
        // 2:通知タップ時でアプリを起動する
        val intent = Intent(this, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }
        val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent,  PendingIntent.FLAG_IMMUTABLE)

        // 3:通知オブジェクトの作成
        var builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("通知のタイトル")
            .setContentText("通知の本文")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)

        // 4:通知の発行
        with(NotificationManagerCompat.from(this)) {
            notify(NOTIFY_ID, builder.build())
        }
    }

    private val launcher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
            // ダイアログの結果で処理を分岐
            if (result) {
                Toast.makeText(this, "許可されました", Toast.LENGTH_SHORT)
                    .show()
            } else {
                Toast.makeText(this, "否認されました", Toast.LENGTH_SHORT)
                    .show()
            }
        }
}

チャンネルとは?

参考文献:公式リファレンス:通知チャネルを作成して管理する

Androidの通知はAndroid 8.0(APIレベル2)以降からチャンネルという単位でグループ分けされています。チャンネル名やチャンネルの説明、チャンネルの重要度などを開発者側が設定でき、ユーザー側はアプリに登録されている通知チャンネルの有効/無効を切り替えて受け取る通知を選択することができるようになっています。

ユーザーはデバイスの「設定アプリ」>「アプリ」>「通知」を開くと以下のように登録されているチャンネルが表示されるので必要な通知チャンネルのみに制限することが可能になっています。

【Kotlin/Android Studio】通知の実装方法!アプリ内からリクエスト(ローカル通知)

チャンネルと通知の重要度

チャンネルの重要度は緊急〜低までの4つから指定でき、それぞれのレベルによって通知の挙動も変化します。

 val importance = NotificationManager.IMPORTANCE_DEFAULT
ユーザーへの表示の重要度 重要度
緊急
音が鳴り、ヘッドアップ通知として表示
IMPORTANCE_HIGH

音が鳴る
IMPORTANCE_DEFAULT

音は鳴らない
IMPORTANCE_LOW

音は鳴らず、ステータスバーにも表示されない
IMPORTANCE_MIN

ヘッドアップ通知を表示する

【Kotlin/Android Studio】通知の実装方法!アプリ内からリクエスト(ローカル通知)

アプリが起動している場合でも通知を上部に表示するヘッドアップ通知を実装したい場合は以下の条件にマッチする必要があります。

条件

バイブレーションを許可する

<uses-permission android:name="android.permission.VIBRATE"/>

チャンネルの重要度を緊急にする

val importance = NotificationManager.IMPORTANCE_HIGH

通知の重要度を緊急にする

.setPriority(NotificationCompat.PRIORITY_HIGH)

表示されない場合の解決方法

設定をしたのに表示されない時はアプリの通知設定がデバイスにキャッシュされている可能性があります。アプリをアンインストールして再度インストールすると正常にヘッドアップ通知が表示されるようになりました。

任意の指定した未来の時間に通知を発行する方法

通知はアプリ内から発行して即座に届くより、数時間後や数日後に届くリマインダーのような使い方をすることのほうが多いと思います。以下の記事で「20XX年のX月XX日のXX時XX分に通知を発行する」方法を紹介しているので参考にしてください。

iOSでの実装はこちら

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index