Android

알림 표시하기

까망사과 2022. 7. 26. 17:00

API

Notification / NotificationCompat

알림이 사용자에게 어떻게 표시될지를 나타내는 클래스다.

API 레벨 11(Honeycomb)에 알림을 생성하는 Notification.Builder가 추가되었다. 생성자는 다음과 같다.

  • Builder(context: Context!) API 레벨 11 ~ 25 (deprecated)
  • Builder(context: Context!, channelId: String!) API 레벨 26 ~

API 레벨 4(Donut) 정도로 낮은 버전까지 호환되도록 하려면 AndroidX의 NotificationCompat 클래스를 사용한다.

 

NotificationChannel / NotificationChannelCompat

유사한 알림이 속하는 집합인 채널을 나타내는 클래스다.

알림 채널 기능은 API 레벨 26(O)에 추가되었기 때문에 NotificationChannelCompat은 그 미만 버전에서는 아무런 동작도 하지 않는다.

 

NotificationChannel은 생성자를, NotificationChannelCompatBuilder 클래스를 통해 생성된다.

  • NotificationChannel(id: String!, name: CharSequence!, importance: Int) API 레벨 26 ~
    채널 ID 문자열, 사용자에게 표시되는 채널 이름 문자열, 채널의 중요도를 전달한다.
    중요도에 따라 사용자에게 보이는 다음 상수를 사용할 수 있다.
    • NotificationManager.IMPORTANCE_DEFAULT 
    • NotificationManager.IMPORTANCE_HIGH
    • NotificationManager.IMPORTANCE_LOW
    • NotificationManager.IMPORTANCE_MAX
    • NotificationManager.IMPORTANCE_MIN
    • NotificationManager.IMPORTANCE_NONE
    • NotificationManager.IMPORTANCE_UNSPECIFIED 
  • NotificationChannelCompat.Builder(id: String, importance: Int)

 

NotificationManager / NotificationManagerCompat

생성된 알림을 표시할 때 사용하는 클래스다.

NotificationManagerContext.getSystemService(Context.NOTIFICATION_SERVICE)를 호출하여 가져올 수 있다.

NotificationManagerCompat은 생성자의 접근 제한자가 private이기 때문에 from(Context)를 호출하여 생성해야 한다.

소스 코드 중 이에 해당하는 부분은 다음과 같다.

@NonNull
public static NotificationManagerCompat from(@NonNull Context context) {
    return new NotificationManagerCompat(context);
}

private NotificationManagerCompat(Context context) {
    mContext = context;
    mNotificationManager = (NotificationManager) mContext.getSystemService(
            Context.NOTIFICATION_SERVICE);
}

 

Context 파라미터의 getSystemService()를 호출하는 것을 알 수 있다.

 


알림 표시하기

알림 관리자 가져오기

getSystemService(Context.NOTIFICATION_SERVICE)가 반환한 객체를 NotificationManager로 캐스팅한다.

val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

 

채널 만들기

API 레벨 26 이상 버전인 경우 알림 채널을 사용해야 하므로 NotificationChannel을 생성한다.

생성자에 채널 ID, 채널 이름, 중요도를 전달한 뒤 여러 메서드로 채널에 대한 설정을 할 수 있다.

사용할 수 있는 메서드 중 일부는 다음과 같다.

  • setDescription(description: String!)
    사용자에게 표시되는 채널 설명문을 지정한다.
  • setShowBadge(showBadge: Boolean)
    앱 런처 아이콘 상단에 숫자 배지를 표시할지 여부를 지정한다.
  • setSound(sound: Uri!, audioAttributes: AudioAttributes!)
    알림음 URI와 오디오 속성을 지정한다.
  • enableLights(lights: Boolean)
    (디바이스에 해당 기능이 있을 경우) 해당 채널에 포함되는 알림에 대한 표시등 점등 여부를 지정한다.
  • setLightColor(argb: Int)
    알림 표시등의 색상을 지정한다.
  • enableVibration(vibration: Boolean)
    해당 채널에 포함되는 알림의 진동 여부를 지정한다.
  • setVibrationPattern(vibrationPattern: LongArray!)
    해당 채널에 포함되는 알림에 대한 진동 패턴을 지정한다.

 

설정을 마치고 이 객체를 NotificationManager.createNotificationChannel()에 전달해야 채널이 생성된다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "channel_id",
        "Channel Name",
        NotificationManager.IMPORTANCE_DEFAULT
    )
    
    channel.run {
        val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val audioAttributes = AudioAttributes
            .Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .setUsage(AudioAttributes.USAGE_ALARM)
            .build()
        
        setSound(uri, audioAttributes)
        description = "Description of the channel"
        setShowBadge(true)
        enableLights(true)
        lightColor = Color.CYAN
        enableVibration(true)
        vibrationPattern = longArrayOf(250, 250, 250, 250)
    }
    
    manager.createNotificationChannel(channel)
}

 

알림 생성하기

기본 설정

NotificationCompat.Builder를 생성한다.

빌드 버전이 API 레벨 26 미만이면 컨텍스트만 전달하는 생성자를 호출하고, 그 이상이면 채널 ID도 전달하는 생성자를 호출한다.

val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationCompat.Builder(this, "channel_id")
} else {
    NotificationCompat.Builder(this)
}

 

Builder의 여러 메서드로 알림에 대한 설정을 한다.

사용할 수 있는 메서드 중 일부는 다음과 같다.

  • setSmallIcon(icon: Int): NotificationCompat.Builder
    알림에 표시될 작은 아이콘을 지정한다.
  • setLargeIcon(icon: Bitmap?): NotificationCompat.Builder
    알림에 표시될 큰 아이콘을 지정한다. 보통 메시지 앱 등에서 사용자 아이콘을 표시하는 데 사용한다.
  • setShowWhen(show: Boolean): NotificationCompat.Builder
    타임스탬프 표시 여부를 지정한다.
  • setWhen(when: Long): NotificationCompat.Builder
    타임스탬프에 표시되는 시각을 지정한다. 현재 시각을 지정하려면 System.currentTimeMillis()를 사용한다.
  • setContentTitle(title: CharSequence?): NotificationCompat.Builder
    알림의 제목을 지정한다.
  • setContentText(text: CharSequence?): NotificationCompat.Builder
    알림의 본문을 지정한다.
builder
    .setSmallIcon(android.R.drawable.ic_notification_overlay)
    .setWhen(System.currentTimeMillis())
    .setContentTitle("Notification Title")
    .setContentText("Content text of the notification")

 

터치 이벤트 설정

알림을 터치할 시 동작을 설정하려면 다음의 메서드를 사용할 수 있다.

  • setAutoCancel(autoCancel: Boolean): NotificationCompat.Builder
    알림을 터치하면 자동으로 취소되는지 여부를 설정한다.
    단독으로 사용하면 작동하지 않고 터치 시 실행될 수 있는 PendingIntent가 있어야 한다.
  • setContentIntent(intent: PendingIntent?): NotificationCompat.Builder
    알림을 터치하면 실행되는 PendingIntent를 지정한다.
  • setOngoing(ongoing: Boolean): NotificationCompat.Builder
    사용자가 알림을 해제하지 못하도록 하는지 여부를 설정한다.
    true를 전달하면 스와이프해도 알림을 해제할 수 없다.
builder
    .setContentIntent(PendingIntent.getActivity(
        this, 100, Intent(), PendingIntent.FLAG_IMMUTABLE))
    .setAutoCancel(true)
    .setOngoing(false)

 

액션 추가하기

NotificationCompat.Builder.addAction()NotificationCompat.Action 객체를 전달하여 액션을 추가할 수 있다.

최대 3개까지만 추가할 수 있다.

Action의 생성자 또는 Action.Builder 클래스를 사용하여 Action 객체를 생성할 수 있다.

Action.Builderbuild()를 호출해야 한다.

  • Action(icon: Int, title: CharSequence?, intent: PendingIntent?)
    액션 버튼에 표시할 아이콘의 리소스 ID, 액션 버튼 텍스트, 터치 시 실행되는 보류 인텐트를 전달한다.
    PendingIntent 부분에 null을 전달하면 알림에 액션을 추가해도 액션 버튼이 표시되지 않는다.
  • Action(icon: IconCompat?, title: CharSequence?, intent: PendingIntent?)
    아이콘 리소스 ID 대신 IconCompat 객체를 전달한다.
  • Action.Builder(icon: Int, title: CharSequence?, intent: PendingIntent?)
  • Action.Builder(icon: IconCompat?, title: CharSequence?, intent: PendingIntent?)
  • Action.Builder(action: Action)
    Action 객체 자체를 전달한다.
builder.addAction(
    android.R.drawable.ic_notification_overlay,
    "Action Title",
    PendingIntent.getActivity(
        this, 100, Intent(this, MyActivity::class.java), PendingIntent.FLAG_IMMUTABLE)
)

 

알림 표시하기

NotificationCompat.Builder의 설정을 마치고 마지막으로 build()를 호출하면 Notification 객체가 반환된다.

알림 ID와 함께 NotificationManager.notify()에 전달하면 사용자에게 알림이 표시된다.

반대로 알림을 취소하려면 NotificationManager.cancel()에 취소하려는 알림의 ID를 전달하면 된다.

manager.notify(11, builder.build())

 

위 과정을 정리하면 다음과 같다.

val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "channel_id",
        "Channel Name",
        NotificationManager.IMPORTANCE_DEFAULT
    )
    
    channel.run {
        val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val audioAttributes = AudioAttributes
            .Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .setUsage(AudioAttributes.USAGE_ALARM)
            .build()
        
        setSound(uri, audioAttributes)
        description = "Description of the channel"
        setShowBadge(true)
        enableLights(true)
        lightColor = Color.CYAN
        enableVibration(true)
        vibrationPattern = longArrayOf(250, 250, 250, 250)
    }
    
    manager.createNotificationChannel(channel)
}

val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationCompat.Builder(this, "channel_id")
} else {
    NotificationCompat.Builder(this)
}

val notification = builder
    .setSmallIcon(android.R.drawable.ic_notification_overlay)
    .setWhen(System.currentTimeMillis())
    .setContentTitle("Notification Title")
    .setContentText("Content text of the notification")
    .setContentIntent(
        PendingIntent.getActivity(
            this, 100, Intent(), PendingIntent.FLAG_IMMUTABLE
        )
    )
    .setAutoCancel(true)
    .setOngoing(false)
    .addAction(
        android.R.drawable.ic_notification_overlay,
        "Action Title",
        PendingIntent.getActivity(
            this, 100, Intent(this, MyActivity::class.java), PendingIntent.FLAG_IMMUTABLE
        )
    )
    .build()
    
manager.notify(11, notification)

 

다음과 같이 Compat 클래스를 사용하면 위와 같은 내용이지만 코드가 한결 깔끔해 보인다.

NotificationChannel과는 다르게 NotificationChannelCompat.Builder의 생성자에는 채널 이름을 전달하지 않는다.

하지만 세터로 이름을 설정하지 않으면 채널을 생성할 때 IllegalArgumentException이 발생하니 주의하자.

val manager = NotificationManagerCompat.from(this)
val channel = NotificationChannelCompat.Builder(
    "channel_id", NotificationManagerCompat.IMPORTANCE_DEFAULT
)
    .setName("Channel Name")
    .setDescription("Description of the channel")
    .setLightsEnabled(true)
    .setLightColor(Color.CYAN)
    .setVibrationEnabled(true)
    .setVibrationPattern(longArrayOf(250, 250, 250, 250))
    .setSound(
        RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .build()
    )
    .build()
val notification = NotificationCompat.Builder(this, "channel_id")
    .setSmallIcon(android.R.drawable.ic_notification_overlay)
    .setWhen(System.currentTimeMillis())
    .setContentTitle("Notification Title")
    .setContentText("Content text of the notification")
    .setContentIntent(
        PendingIntent.getActivity(
            this, 100, Intent(), PendingIntent.FLAG_IMMUTABLE
        )
    )
    .setAutoCancel(true)
    .setOngoing(false)
    .addAction(
        android.R.drawable.ic_notification_overlay,
        "Action Title",
        PendingIntent.getActivity(
            this, 100, Intent(this, MyActivity::class.java), PendingIntent.FLAG_IMMUTABLE
        )
    )
    .build()

manager.createNotificationChannel(channel)
manager.notify(11, notification)

'Android' 카테고리의 다른 글

서비스 (1) : 포그라운드 및 백그라운드 서비스  (0) 2022.08.27
액션 바 사용하기  (0) 2022.08.09
진동 울리기  (0) 2022.07.21
벨소리 재생하기  (0) 2022.07.19
Chronometer와 RecyclerView로 스톱워치 만들기  (0) 2022.07.09