【Kotlin】Notificationを出す

Android13では同意が必要(追記)

Android13、TargetSDKが33の場合には、ユーザー同意が必要になっていました。

ユーザー同意を得ないとNotificationは機能しません。

ユーザ同意を得るためのコードが以下の通りです。

    // ランタイムパーミッションの結果.
    private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            if (it) {
                // 権限が許可されたので、該当の権限が必要な操作が可能.
                println("ok")
            } else {
                // 権限が拒否されたので、該当の権限が必要な操作が不可.
                println("permit denied")
            }
        }

    private fun checkNotificationPermission() {
        // OS バージョン確認.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            // Android 13 未満は通知権限不要.
            return
        }
        // 通知権限が許可されているか確認.
        if (ContextCompat.checkSelfPermission(
                this, Manifest.permission.POST_NOTIFICATIONS)
            == PackageManager.PERMISSION_GRANTED) {
            // 権限許可済.
            return
        }
        // 通知権限を必要とする理由をアプリが提示する必要があるか確認.
        if (shouldShowRequestPermissionRationale(
                Manifest.permission.POST_NOTIFICATIONS)) {
            // 必要がある場合は、その理由を説明するためのUIを明示的に表示する.
            return
        }
        // 通知権限をリクエストする.
        requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
    }

通知を出すためのコード

Notification(通知)を出して通知ドロワーに通知する機能を作ってみた。

以下のようにAndroid12の端末で動かせたのでご参考までに共有します。

通知を出すと、音量をオフにしていても「ピコーン!」と音がするので、何かお知らせする時には便利だ。

コードを紹介していきます。

API26以上の場合、NotificationChannelを作成する必要がある。

    private val channelId = "hoge"    
    private fun createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val name = "a"
            val descriptionText = "b"
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(channelId, name, importance).apply {
                description = descriptionText
            }
            // Register the channel with the system
            val notificationManager: NotificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }
    }

チャネルのIDや名前はなぜ設定する必要があるのか分からないが、適当に設定しても通知は出せたので気にしないことにする。

次に通知を出すところ。

    private fun showNotification(){

        createNotificationChannel()

        // タップ時に起動する画面を設定
        val intent = Intent(this, MainActivity::class.java)

        //既存のアクティビティを起動する
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)

        //既存のアクティビティを消して、新しくアクティビティを作成する
//        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)

        val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

        val builder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(android.R.drawable.btn_star)
            .setContentTitle("落下しましたよ!!!")
            .setContentText("スマホが落下したようです!!!")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)

        val notificationManagerCompat = NotificationManagerCompat.from(this)
        notificationManagerCompat.notify(R.string.app_name, builder.build())
    }

通知を出すだけなら、インテントの設定は必要ない。

私の場合は、通知のタップをした時に起動中の画面に遷移したかったので、以下の設定をした。

  • インテントを作成
  • 起動中のActivity画面に遷移するようにフラグでSINGLE_TOPを指定
  • pendingIntentにインテントをセット
  • pendingintentをビルダーに設定

通知を出すだけなら簡単では?と思っていたが意外と難しかった。

つまづいた点は以下の通り。

  • 通知チャネルを作成しておらず通知が出ない
  • チャネルIDに何を設定して良いか分からない。
  • 通知をタップしたときに、Acitivityが再起動してしまう。
  • 通知をタップしたときに、起動中のAcitivityに遷移する方法が分からない。

1日がかりでStackOverflowを調べて解決した。

ABOUTこの記事をかいた人

個人アプリ開発者。Python、Swift、Unityのことを発信します。月間2.5万PVブログ運営。 Twitter:@yamagablog