240110 TIL #291 Android #14 알림

김춘복·2024년 1월 10일
0

TIL : Today I Learned

목록 보기
291/494

Today I Learned

오늘은 이어서 알림에 대해 공부했다.


알림

소리 알림

사용자에게 짧은 소리로 특정 상황을 알릴 때, 이 소리를 알림음이라 한다.
ex) 문자, 카톡 알림 소리

  • 안드로이드 시스템에선 알림(NOTIFICATION), 알람(ALARM), 벨소리(RINGTONE) 등의 소리를 제공한다.

  • 이 소리는 RingtonManager로 얻을 수 있다.

// 소리 식별값 얻기
val notification: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
// 위의 객체 받아서 Ringtone 객체 얻기
val ringtone = RingtoneManager.getRingtone(applicationContext, notification)
// Ringtone 객체의 함수로 소리 재생
ringtone.play()
  • 앱 자체의 음원을 사용하려면 res/raw 디렉터리를 이용하면 된다.
    MediaPlayer객체로 경로를 지정해 재생 가능하다.
val player: MediaPlayer = MediaPlayer.create(this, R.raw.fallbackring)
player.start()

진동 알림

  • 진동 알림을 사용하려면 먼저 매니페스트 파일에 퍼미션을 얻어야 한다.
<uses-permission android:name="android.permission.VIBRATE"/>
  • Vibrator 클래스를 이용해 진동을 사용할 수 있다.
    하지만 API 레벨 31버전 이후 VIBRATOR_MANAGER_SERVICE로 식별되는 VibratorManager 시스템 서비스를 얻고 이 서비스에서 Vibrator를 이용해야 한다.
val vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    val vibratorManager = this.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
    vibratorManager.defaultVibrator
} else {
    getSystemService(VIBRATOR_SERVICE) as Vibrator
}
  • API 레벨 26부터는 진동 정보를 VibrationEffect 객체로 지정할 수 있는 함수를 제공한다. 진동이 울리는 시간과 진동의 세기까지 제어할 수 있다.

open fun vibrate(vibe: VibrationEffect!): Unit

open static fun createOneShot(milliseconds: Long, amplitude: Int): VibrationEffect!
  • createOneShot() 함수로 만든 VibrationEffect 객체를 vibrate() 함수에 대입하면 첫번째 매개변수의 시간동안 진동이 울린다.

  • 두번째 매개변수는 진동의 세기를 0~255 사이의 숫자로 표현한다.
    VibraionEffect.DEFAULT_AMPLITUDE(기본 세기) 처럼 상수를 지정해도 된다.


알림 띄우기

알림 채널

화면 상단의 상태바에 앱 정보를 출력하는 것을 알림(notification)이라 한다.

  • API 레벨 33 버전부터는 매니페스트에 퍼미션을 요청해야 한다.
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
  • 상태바는 시스템에서 관리하는 곳이라 앱이 직접 제어할 수 없다.

  • 알림 객체 생성 순서

    NotificationChannel 로 알림정보를 만들어 NotificationCompat.Builder를 만들 때 넣어주고, 이 빌더로 Notification 객체를 만들어 NotificationManager의 notify() 함수에 대입해 알림을 만든다.

  • 채널
    API 레벨 26버전부터 앱의 알림을 채널로 구분해 유저가 환경설정에서 어떤 앱의 알림을 받을지 말지 설정할 수 있게되었다.

// 알림 채널 생성자
NotificationChannel(id: String!, name: CharSequence!, importance: Int)
  • id는 채널의 식별값, name은 채널 이름, importance는 알림의 중요도로 아래의 상수로 지정한다.

    NotificationManager.IMPORTANCE_HIGH : 긴급. 알림음 O 헤드업으로 표시
    NotificationManager.IMPORTANCE_DEFAULT : 높은 중요도. 알림음 O
    NotificationManager.IMPORTANCE_LOW : 중간 중요도. 알림음 X
    NotificationManager.IMPORTANCE_MIN : 낮은 중요도. 상태바에도 X

  • 채널의 각종 정보는 함수나 프로퍼티로 설정 가능하다.
    ex) enableVibration(), setShowBadge(), setSound()

  • 알림 빌더 작성

val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val builder: NotificationCompat.Builder

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channelId = "one-channel"
    val channelNAme = "My Channel One"
    val channel = NotificationChannel(
        channelId,
        channelNAme,
        NotificationManager.IMPORTANCE_HIGH
    )

    // 채널에 다양한 정보 설정
    channel.description = "채널 설명"
    channel.setShowBadge(true) // 홈화면에 확인하지 않은 알림 개수가 배지 아이콘에 표시
    val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
    val audioAttributes = AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .setUsage(AudioAttributes.USAGE_ALARM)
        .build()
    channel.setSound(uri, audioAttributes)
    channel.enableLights(true)
    channel.lightColor = Color.RED
    channel.enableVibration(true)
    channel.vibrationPattern = longArrayOf(100, 200, 100, 200)

    // 채널을 NotificationManager에 등록
    manager.createNotificationChannel(channel)

    // 채널로 빌더 생성
    builder = NotificationCompat.Builder(this, channelId)
} else {
    builder = NotificationCompat.Builder(this)
}

알림 객체

빌더를 만들었으면 이 빌더로 Notification 객체를 만들어야 한다.

  • 이 객체에 출력할 이미지, 문자열 등의 정보를 담는다.

  • 상태바를 내리면 스몰아이콘, 발생시각, 제목, 내용이 보이는데 이러한 정보를 Notification 객체에 설정해야 한다.

  • 알림 객체 설정 및 발생

// 정보 설정
builder.setSmallIcon(android.R.drawable.ic_notification_overlay)
builder.setWhen(System.currentTimeMillis())
builder.setContentTitle("Content Title")
builder.setContentText("Content Massage")
// 알림 발생
manager.notify(11, builder.build())
  • 첫번째 매개변수는 알림의 식별값으로 쓰이며, builder.build()가 Notification 객체를 생성해 알림이 울린다.

  • 식별값은 알림을 취소할 때, manager.cancel(11) 처럼 사용된다.

  • 알림을 터치하거나 스와이프하면 자동으로 취소되는데 이를 무효화 하려면 빌더의 세터함수로 지정할 수 있다.

// 알림 터치시 이벤트는 발생해도 알림은 안사라짐
builder.setAutoCancel(false)
// 유저가 스와이프해도 알림 안사라짐
builder.setOngoing(true)

알림 구성

알림 터치 이벤트

  • 대부분의 앱은 알림 터치시 앱의 액티비티 화면을 실행하는데, 이렇게 하려면 알림의 터치 이벤트를 구현해야한다.

  • 하지만 알림은 앱이 아니라 시스템이 관할하기 때문에 onTouchEvent() 함수로는 처리할 수 없다.

  • 따라서 Notification 객체에 알림터치시 실행 정보를 담아두고 시스템이 이를 처리하는 구조로 이루어진다.

  • 인텐트(intent)
    알림 터치시 앱의 액티비티나 브로드캐스트 리시버를 실행해야 되는데 이를 실행하려면 인텐트를 이용한다. 앱의 컴포넌트를 실행하는데 필요한 정보이다.

  • Notification 객체에 인텐트를 담을 때 PendingIntent 클래스를 이용한다.

val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 10, intent, PendingIntent.FLAG_IMMUTABLE)
builder.setContentIntent(pendingIntent)

액션

알림은 터치이벤트 이외에서 액션을 최대 3개까지 추가할 수 있다.
ex) 알람취소, 전화 수신, 공유, 편집, 삭제 등

  • 알림 터치 이벤트와 마찬가지로 PendingIntent로 구성해 등록해야 한다.

  • 액션 등록은 Action 객체와 이를 매개변수로 하는 addAction() 함수로 할 수 있다.


원격 입력

remoteInput 원격입력은 알림에서 사용자 입력을 직접 받는 기법이다.
ex) 카톡 알림에서 바로 메세지 입력

  • 호환성을 위해 import androidx.core.app.RemoteInput을 임포트해 사용하면 된다.

  • RemoteInput에 사용자 입력을 받는 정보를 설정 후 액션에 추가하는 구조이다.

// 입력 식별값
val KEY_TEXT_REPLY = "key_text_reply"
// 입력란에 출력되는 힌트 문자열
var replyLabel: String = "답장"
var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run { 
    setLabel(replyLabel)
    build()
}
  • RemoteInput도 액션이므로 액션의 터치 이벤트 처리를 위한 PendingIntent를 준비해 알림에 액션을 등록하면서 RemoteInput 정보를 함께 설정하면 된다.

  • 브로드캐스트 리시버에서 유저가 입력한 글을 받을때는 아래의 코드를 이용한다.

val replyTxt = RemoteInput.getResultsFromIntent(intent)?.getCharSequence("key_text_reply")

프로그레스

앱에서 어떤 작업이 이루어지는데 시간이 걸리면 알림을 통해 진행 상황을 프로그레스에 바로 알려준다.
ex) 서버에서 파일 업로드 or 다운로드 시 진행 상황

  • 프로그레스 바는 화면을 준비하지 않고 빌더에 setProgress() 함수만 추가하면 된다.
open fun setProgress(max: Int, progress: Int, indeterminate: Boolean): Notification.Builder
  • max : 프로그래스 바의 최댓값
    progress : 진행 값. 처음에 현재값 설정 후 스레드 같은 프로그램으로 진행 상황 수정하면 된다.
    indeterminate : true면 왼쪽에서 오른쪽으로 계속 흘러가듯이 표현된다.

  • 10초간 프로그레스바 증진하는 예시

builder.setProgress(100, 0, false)
manager.notify(12, builder.build())
thread {
    for (i in 1..100){
        builder.setProgress(100, i, false)
        manager.notify(12, builder.build())
        SystemClock.sleep(100)
    }
}

알림 스타일

기본적으로 문자열이지만 여러 스타일을 제공한다.

  • 큰 이미지 스타일
    화면 캡처 같이 큰 이미지가 알림 화면에 필요할 때
    NotificationCompat.BigPictureStyle()

  • 긴 텍스트 스타일
    이메일 같이 일부 내용같은 긴 문자열도 보여줘야할 때
    NotificationCompat.BigTextStyle()

  • 상자 스타일
    하나의 알림에 문자열 여러개 나열 시 사용
    NotificationCompat.InboxStyle()

  • 메시지 스타일
    여러 사람이 주고받은 메시지를 구분해서 출력할 때 Message 객체로 표현
    NotificationCompat.MessagingStyle()

Message(text: CharSequence, timestamp: Long, sender: Person?)
  • Person 객체는 Builder로 생성하며 setName()과 setIcon() 함수로 이름과 프로필 사진을 등록할 수 있다.
profile
꾸준히 성장하기 위해 매일 log를 남깁니다!

0개의 댓글