들어가기 전
이번 sopt 앱잼에서 FCM 알림을 담당하게 되면서, 알림 권한과 알림 커스텀에 대해 공부하게되었다.
1.안드로이드 13 알림권한 설정
이전까지는 안드로이드에서 알림을 표시할 때 권한이 없어도 개발자가 알아서 알림을 만들고 띄울 수 있었다.
하지만 이를 악용하는 사례(무분별한 광고알림)들이 많아지자 Android 8.0 (Oreo) 에서는 Notification Channel 을 도입시켰고,
Android 13 (Tiramisu) 부터는 런타임 알림 권한 (POST_NOTIFICATIONS)이 추가되었다.
이제 안드로이드에서도 사용자에게 알림 권한을 요청하고, 사용자의 알림 허가를 받은 뒤에 알림을 표시할 수 있게된 것이다.
사용자의 알림 권한을 확인하고 권한을 요청하는 방법은 아래와 같다.
1. Manifest 에서 권한을 선언한다.
<manifest ...>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application ...>
...
</application>
</manifest>
2. 사용자의 알림 권한 허용 여부를 확인하고, 권한을 요청하면 된다.
private fun askNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
) {
Snackbar.make(binding.root, R.string.allowing_notification, Snackbar.LENGTH_SHORT)
.show()
} else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
Snackbar.make(binding.root, R.string.if_allow_notification, Snackbar.LENGTH_SHORT)
.show()
val intent =
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.parse("package:" + this.packageName))
startActivity(intent)
this.finish()
} else {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
}
사용자는 권한 팝업에서 이러한 동작들을 할 수 있다
1. 허용을 한다.
2. 허용 안함을 누른다
3. 어떤 버튼도 안누르고 팝업을 스와이프로 없앤다.
1. 사용자가 허용을 선택한다.
- 사용자가 허용을 선택하면, 알림을 보내고 모든 알림 채널이 허용된다.
- 포그라운드 서비스와 관련된 알림을 게시하고, 알림은 알림창에 표시된다.
2. 사용자가 허용안함을 선택한다.
- 사용자가 허용 안함 옵션을 선택하면 앱에서 알림을 보낼 수 없다.
- 몇 가지 특정 역할을 제외하고는 모든 알림 채널이 차단된다. (사용자가 시스템 설정에서 해당 앱의 모든 알림을 수동으로 사용중지 하는 경우와 비슷한 동작을 한다.)
3. 사용자가 권한 팝업을 스와이프하여 없앤다.
- 사용자가 스와이프로 없애면, 허용 또는 허용 안함을 선택하지 않으면 => 알림 권한의 상태가 변경되지 않는다.
만약 앱 내에서 알림 on/off switch를 만들고 싶다면?
처음 현재 알림 권한 허용여부를 파악 한 뒤 switch의 checked를 세팅한다.
사용자가 switch를 스와이프할 때 클릭리스너로 현재 알림 권한 상황과 switch의 on/off의 일치를 파악한 뒤 앱 설정 화면으로 보내준다.
그 이유는 처음 팝업에서 알림 권한을 거부한 사용자를 다시 허용하게 만드는 것은 코드를 통해서 할 수 없기 때문이다.
다시 허용을 하기 위해서는 사용자가 직접 앱의 설정에 들어가서 권한 허용을 해줘야한다.
이러한 이유로 나는 아래와 같은 코드로 switch on/off 를 설정하였다.
아래는 switch 리스너 코드이다.
private fun changeSwitchNotification() {
binding.switchNotification.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked != (ContextCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED)
) {
val intent =
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.parse("package:" + requireActivity().packageName))
notificationSettingsLauncher.launch(intent)
}
}
}
이처럼 사용자에게 알림을 보내기 위한 권한을 설정하고 관리할 수 있다.
2. 알림 커스텀
내게 필요했던 기능들은 다음과 같다.
1. 알림을 받은 뒤 알림을 누르면 '문답화면' 즉 특정화면으로 넘어가도록 하기.
2. 알림 아이콘은 엄빠 앱의 아이콘, 알림의 형태 (헤드업 or default 지정) 지정하기.
서버로부터 받은 알림을 띄우기 위해 생성했던 createNotification() 함수는 다음과 같다.
private fun createNotification(message: RemoteMessage) {
val intent = Intent(this, QuestionAnswerActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
for (key in message.data.keys) {
intent.putExtra(key, message.data[key])
}
val pendingIntent = PendingIntent.getActivity(
this, (System.currentTimeMillis() / 7).toInt(), intent,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_MUTABLE
)
val notificationChannel = NotificationChannel(
CHANNEL_ID,
"TestChannelName",
NotificationManager.IMPORTANCE_DEFAULT // IMPORTANCE_HIGH 면 헤드업 알림이 가능.
)
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_umbba_logo)
.setContentTitle(message.notification?.title.toString())
.setContentText(message.notification?.body.toString())
.setContentIntent(pendingIntent)
val notificationManager: NotificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(notificationChannel)
notificationManager.notify(
1, // 해당 알림의 고유 ID
builder // 표시할 알림
.build()
)
}
이 코드에서 message는 서버로부터 받은 title과 content가 담긴 변수이다.
앞서 말한 첫번째 기능을 구현하기 위해 intent와 pendingIntent 를 생성한다.
그리고 Intent (this, 여기!) this 뒤에 알림 클릭시 보내고싶은 화면을 넣어준다.
여기서 pendingIntent란 intent는 안드로이드 어플리케이션 컴포넌트(AAC)를 실행하기 위해 안드로이드 시스템에게 알려주는 역할이지만 PendingIntent는 intent가 정의된 어플리케이션이 아닌 다른 어플리케이션에서 Intent를 실행하도록 하는 것이다.
이렇게 하면 첫번째 기능을 구현할 수 있다.
두번째는 알림을 커스텀하는 것이다.
알림은 중요도에 따라서 나타나는 모양을 다르게 할 수 있다. 중요도는 아래 사진과 같다.
이런 헤드업 알림을 구현하고싶다면 NotificationManager.IMPORTANCE_HIGH로 설정하면된다.
우리 앱에서는 NotificationManager.IMPORTANCE_DEFAULT로 설정했고, 이는 알림이 오면 상태바에 앱 아이콘이 뜨는 식으로 알림이 온다.
앱의 아이콘과 Title, text는 NotificationCompat.Builder의 속성으로 지정할 수 있다. 아래 사진처럼 여러 속성이 있고, 각 속성에 맞춰서 커스텀을 할 수 있다.
이렇게 하면 알림도 커스텀이 가능하다!
마치며
후담으로 사용자의 알림 설정을 on/off 할 때마다 설정창으로 보내주는게 일반적인 방법은 아닌거같다는 피드백을 들었다.
피드백을 바탕으로 여러 어플들은 알림 설정을 어떻게 관리하고있는지 파악하고, 관련한 포스팅을 남기도록 하겠다.
'Android > 공부' 카테고리의 다른 글
[Android] Dependency Injection이란? + Hilt (1) | 2023.08.07 |
---|---|
[Android] Clean Architecture + MVVM 패턴 (1) | 2023.08.06 |
[Android] Intent 정리하기 (0) | 2023.04.26 |
[Android] Retrofit2 싱글톤패턴 적용하기 (0) | 2022.11.26 |
[Android] Recyclerview item Click / Click Listener 등록하는 법 (0) | 2022.11.01 |