오늘은 이어서 알림에 대해 공부했다.
사용자에게 짧은 소리로 특정 상황을 알릴 때, 이 소리를 알림음이라 한다.
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
클래스를 이용해 진동을 사용할 수 있다.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
}
open fun vibrate(vibe: VibrationEffect!): Unit
open static fun createOneShot(milliseconds: Long, amplitude: Int): VibrationEffect!
createOneShot() 함수로 만든 VibrationEffect 객체를 vibrate() 함수에 대입하면 첫번째 매개변수의 시간동안 진동이 울린다.
두번째 매개변수는 진동의 세기를 0~255 사이의 숫자로 표현한다.
VibraionEffect.DEFAULT_AMPLITUDE(기본 세기) 처럼 상수를 지정해도 된다.
화면 상단의 상태바에 앱 정보를 출력하는 것을 알림(notification)이라 한다.
<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 다운로드 시 진행 상황
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?)