iT邦幫忙

2024 iThome 鐵人賽

DAY 26
0
Mobile Development

github裡永遠有一個還沒做的SideProject :用Kotlin來開發點沒用的酷東西系列 第 26

Day26: Android的Notification和建立Notification Channel

  • 分享至 

  • xImage
  •  

前言

今天我們來講一下如何通知系統來顯示訊息,讓你可以在通知欄就看到APP傳遞的消息。

Android的通知系統

先附上程式碼,如下

  • kotlin
package com.example.myapplication

import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat

class MainActivity : ComponentActivity() {
    // 用於權限請求的 ActivityResultLauncher
    private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 在 onCreate 中註冊 ActivityResultLauncher
        requestPermissionLauncher = registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { isGranted: Boolean ->
            if (isGranted) {
                // 使用者授權,顯示通知
                showNotification(this)
            } else {
                // 使用者拒絕授權
                println("通知權限被拒絕")
            }
        }
        setContent {
            NotificationApp()
        }
    }

    @Composable
    fun NotificationApp() {
        val context = LocalContext.current

        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Button(onClick = {
                // 先檢查權限是否已經被授權
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    if (ContextCompat.checkSelfPermission(
                            context, Manifest.permission.POST_NOTIFICATIONS
                        ) == PackageManager.PERMISSION_GRANTED
                    ) {
                        // 已經有權限,顯示通知
                        showNotification(context)
                    } else {
                        // 請求權限
                        requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
                    }
                } else {
                    // 對於 Android 13 以下版本,直接顯示通知
                    showNotification(context)
                }
            }) {
                Text(text = "顯示通知")
            }
        }
    }

    // 顯示通知的函數
    private fun showNotification(context: Context) {
        val channelId = "my_channel_id"
        val notificationId = 1

        // 檢查權限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
            ContextCompat.checkSelfPermission(
                context, Manifest.permission.POST_NOTIFICATIONS
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // 如果沒有通知權限,則不顯示通知
            println("通知權限未被授權,無法顯示通知")
            return
        }

        // 創建通知頻道(針對 Android 8.0 及以上)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val name = "My Channel"
            val descriptionText = "Channel for app notifications"
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(channelId, name, importance).apply {
                description = descriptionText
            }

            // 註冊頻道到系統
            val notificationManager: NotificationManager =
                context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }

        // 建立通知
        val builder = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle("新通知")
            .setContentText("這是通知的內容,顯示在狀態欄")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)

        // 顯示通知
        with(NotificationManagerCompat.from(context)) {
            notify(notificationId, builder.build())
        }
    }
}

@Preview(showBackground = true)
@Composable
fun NotificationAppPreview() {
    val mainActivity = MainActivity()
    mainActivity.NotificationApp()
}

1. 權限請求與檢查

在Android 13 (API 33)及以上版本中,顯示通知需要POST_NOTIFICATIONS權限,這是一個執行時權限。因此,我們需要在應用運行時向使用者請求這個權限。

MainActivityonCreate方法中,我們使用ActivityResultLauncher註冊了一個權限請求的

  • kotlin
// 用於權限請求的 ActivityResultLauncher
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 在 onCreate 中註冊 ActivityResultLauncher
    requestPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // 使用者授權,顯示通知
            showNotification(this)
        } else {
            // 使用者拒絕授權
            println("通知權限被拒絕")
        }
    }
    setContent {
        NotificationApp()
    }
}

2.NotificationApp

當我們點擊按鈕時,NotificationApp()會檢查權限狀態並根據結果顯示通知或請求權限。

  • kotlin
@Composable
fun NotificationApp() {
    val context = LocalContext.current

    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Button(onClick = {
            // 先檢查權限是否已經被授權
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                if (ContextCompat.checkSelfPermission(
                        context, Manifest.permission.POST_NOTIFICATIONS
                    ) == PackageManager.PERMISSION_GRANTED
                ) {
                    // 已經有權限,顯示通知
                    showNotification(context)
                } else {
                    // 請求權限
                    requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
                }
            } else {
                // 對於 Android 13 以下版本,直接顯示通知
                showNotification(context)
            }
        }) {
            Text(text = "顯示通知")
        }
    }
}

3. 建立通道

在Android 8.0 (API 26)及以上的版本中,系統引入了「通知頻道」(Notification Channel)的概念。通知頻道是一種用來分組管理通知的方式,使用者可以對不同頻道的通知行為進行個別控制,例如聲音、震動或顯示優先級等。每個通知必須屬於一個頻道,否則在 Android 8.0 及以上的裝置上無法顯示通知。

  • kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val name = "My Channel"
    val descriptionText = "Channel for app notifications"
    val importance = NotificationManager.IMPORTANCE_DEFAULT
    val channel = NotificationChannel(channelId, name, importance).apply {
        description = descriptionText
    }

    // 註冊頻道到系統
    val notificationManager: NotificationManager =
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.createNotificationChannel(channel)
}

上面的程式碼用來創建通知頻道,需要包含設置頻道的唯一ID、名稱、描述和重要性:

  • 頻道ID 必須是唯一的,用來標識這個頻道。
  • 頻道名稱是顯示給使用者看的名稱,用來告知這個頻道的用途。
  • 描述是用來提供更多的資訊,幫助使用者理解這個頻道的作用。
  • 重要性(Importance)決定了通知顯示的優先級,例如是否顯示在狀態欄上、是否播放音效或震動。
    而重要性又分成下面這幾種等級
    重要性等級(Importance Levels)
    在創建頻道時,你可以設定頻道的重要性等級,以控制通知的顯示行為。以下是 Android 提供的幾個重要性等級:
  • IMPORTANCE_NONE:不顯示任何通知。
  • IMPORTANCE_MIN:僅顯示在通知陰影(Notification Shade)中,不會有提示音或狀態欄圖標。
  • IMPORTANCE_LOW:顯示在通知陰影中,不會發出提示音或震動。
  • IMPORTANCE_DEFAULT(推薦):顯示在通知陰影中,並發出提示音。
  • IMPORTANCE_HIGH:顯示在通知陰影中,會發出提示音並可能會彈出來提醒使用者。

4. 顯示通知

使用NotificationCompat.Builder來構建通知,並使用NotificationManagerCompat來顯示。

  • kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val name = "My Channel"
    val descriptionText = "Channel for app notifications"
    val importance = NotificationManager.IMPORTANCE_DEFAULT
    val channel = NotificationChannel(channelId, name, importance).apply {
        description = descriptionText
    }

    // 註冊頻道到系統
    val notificationManager: NotificationManager =
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.createNotificationChannel(channel)
}

APP執行後的呈現結果如下
https://ithelp.ithome.com.tw/upload/images/20241010/201626490jgroHEFAe.png
https://ithelp.ithome.com.tw/upload/images/20241010/201626496rkjCrm7hU.png

後話

今天我們講了Android的Notification系統和如何建立Notification Channel,讓我們能再通知欄跳訊息給使用者,今天的內容就到這邊,讓我明天再見。


上一篇
Day25:Jetpack Compose的退出視窗
下一篇
Day27:在 Android 中使用 Lottie 動畫
系列文
github裡永遠有一個還沒做的SideProject :用Kotlin來開發點沒用的酷東西30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言