-
Notifications
You must be signed in to change notification settings - Fork 0
일정 알림을 놓치지 않고 받는 법
앱에서 일정 알림을 주기 위해서 선택한 방법은 AlarmManager
를 사용하는 것이다.
백그라운드에서 사용자가 원하는 정확한 시간을 알려주기 위해서 고민한 방법은 FCM
과 AlarmManager
이다.
AlarmManager를 고민한 이유는 구글 공식문서에서 백그라운드 태스크 중에 정확한 시간에 특정한 작업을 하는 경우에 가장 권장하는 방법을 AlarmManager로 제안하고 있다.
FCM 또한 서버에서 일정에 대한 정보를 가지고 있다가 사용자에게 알림을 보내줄 수 있어 가능할 것 이라고 생각했다.
AlarmManager와 FCM을 비교해본 결과 AlarmManager가 조금 더 일정 알림에 좋다는 결론이 나왔다.
첫 번째 선택 기준은 오프라인에서 사용자에게 일정 알림 기능을 보내줄 수 있냐는 것이다. AlarmManager의 경우 오프라인에서도 정해진 시간에 특정 동작을 하도록 동작하지만 FCM의 경우 오프라인 상태에서는 메시지를 받지 못하는 문제가 있다.
두 번째 선택 기준은 정확도이다. AlarmManager의 경우 Doze 모드나 배터리 최적화라는 여러 가지지 문제로 인해 완벽히 정확한 시간과 무조건적인 실행을 보장하지 않을 수 있다는 이슈가 있다. FCM의 경우도 네트워크 문제와 같은 여러가지 이슈가 있어서 무조건 적인 전송과 정확한 시간에 전송이 되는 것을 보장하지 못한다고 한다. 하지만, AlarmManager의 경우 Doze 모드에서도 실행될 수 있도록 기능을 제공해주고 있다!!
이러한 이유로 최종적으로 AlarmManager를 통해 일정 알림을 제공하는 것으로 결론이 났다.
AlarmManager의 특징 중 하나가 휴대폰이 껐다가 켜지면 기존에 설정된 알람들이 모두 해제가 된다. 이를 해결하기 위해 Broadcast Receiver에서 휴대폰이 켜졌을 때의 액션을 관찰하도록 변경했다. 휴대폰이 켜졌을 때는 ACTION_BOOTED_COMPLETED
액션을 가진 인텐트를 전송하고 이를 Broadcast Receiver에서 받아서 관찰이 되면 일정을 모두 등록하도록 구현하였다.
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
Intent.ACTION_BOOT_COMPLETED -> {
alarmHelper.registerRepeatAlarm()
notificationHelper.createNotificationChannels()
}
AlarmHelper.INTENT_ACTION_ALARM_EVENT -> {
notificationHelper.createNotification(
channelId = NotificationHelper.CHANNEL_ID_EVENT_NOTIFICATION,
requestCode = INTENT_REQUEST_ID_EVENT_NOTIFICATION,
title = intent.getStringExtra(AlarmHelper.INTENT_EXTRA_TITLE),
content = intent.getStringExtra(AlarmHelper.INTENT_EXTRA_CONTENT).orEmpty(),
id = intent.getIntExtra(AlarmHelper.INTENT_EXTRA_EVENT_ID, 0)
)
}
}
확인 결과 부팅 후에도 잘 알림이 울리는 것을 확인했다.
부팅할 때 알람을 등록할 경우 또 다른 문제가 발생한다. 앱에서 반복 일정을 지원하기 때문에
1년동안 매일 반복 되는 3개의 일정만 있어도 부팅 시에 1000개 이상의 알람을 새로 등록해야한다.
부팅 시에 백그라운드에서 그 많은 일정을 불러와서 등록하게 된다면 분명 문제가 생길 것이라고 생각하였고, 어떻게 너무 많은 일정을 한 번에 부르지 않고도 사용자가 놓치는 알림이 없도록 할까에 대해 많은 고민을 하였다.
이 부분에 대해 많이 고민해보고 멘토링 과정을 거친 후에 알람 매니저에서 2개 유형의 알람을 등록하는 방법을 사용해보기로 하였다.
위의 그림은 앱에서 등록하는 2개의 유형의 알람을 이해하기 쉽게 그린 것이다.
알람2
는 기존에 등록하단 알람의 유형으로 사용자가 알람을 추가할 때 일정 알림을 등록한 경우에 그 시간에 정확하게 울리며 Broadcast Receiver
에서는 알람 2 유형의 액션을 관찰하게 되면 notification을 만들어서 사용자에게 일정 알림을 띄워준다. 위의 그림에서 볼 수 있는 사용자가 지정한 알림 시간이에요!!!
는 실제 Broadcast Receiver에서 받는 액션을 이해하기 쉽게 설명한 것이다.
알람1
은 사용자가 로그인하거나 재부팅되었을 때 등록되는 알람으로 하루 간격으로 알람이 반복적으로 울리며 Broadcast Receiver
에서 알람 1 유형의 액션을 관찰하게 되면 로컬 데이터베이스에서 오늘 기준으로 8일 뒤까지의 일정을 받아와서 그 중 일정 알림이 등록된 일정이 있는 경우 각각 그 시간에 맞도록 알람2
를 등록해준다. 8일 뒤까지의 일정을 받아오는 이유는 사용자가 일정 알림을 지정할 수 있는 시간이 일정 시작 시간 정각, 10분 전, 1시간 전, 1일 전, 일주일 전이기 때문에 안전하게 8일 뒤의 일정까지의 일정을 등록한다면 모든 일정을 놓치지 않고 알릴 수 있다는 이유에서 이다.
아래는 Broadcast Receiver에서 액션에 따라 다르게 동작하는 코드이다.
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
//재부팅될 경우
Intent.ACTION_BOOT_COMPLETED -> {
alarmHelper.registerRepeatAlarm()
notificationHelper.createNotificationChannels()
}
//알람 유형 1이 울릴 경우
AlarmHelper.INTENT_ACTION_ALARM_UPDATE -> {
alarmHelper.setAlarms()
}
//알람 유형 2가 울릴 경우
AlarmHelper.INTENT_ACTION_ALARM_EVENT -> {
notificationHelper.createNotification(
channelId = NotificationHelper.CHANNEL_ID_EVENT_NOTIFICATION,
requestCode = INTENT_REQUEST_ID_EVENT_NOTIFICATION,
title = intent.getStringExtra(AlarmHelper.INTENT_EXTRA_TITLE),
content = intent.getStringExtra(AlarmHelper.INTENT_EXTRA_CONTENT).orEmpty(),
id = intent.getIntExtra(AlarmHelper.INTENT_EXTRA_EVENT_ID, 0)
)
}
}
}
하루마다 등록된 일정들의 알람을 다시 등록하게 되면 기존에 등록된 알람들과 중복되어 문제가 있을 것이라는 걱정도 있을 것이다. 하지만, 등록되는 모든 알람은 Pending Intent에서 고유한 아이디를 가지고 있고 Flag로 PendingIntent.FLAG_CANCEL_CURRENT
를 가지고 있기 때문에 다시 등록된 알람은 새 알람으로 대체되게 된다.
결론적으로 앱에서는 휴대폰이 다시 켜져도 사용자가 놓치지 않는 알림을 제공할 수 있게 되었다!!!
- Week1 - Day01
- Week1 - Day02
- Week1 - Day03
- Week1 - Day04
- Week2 - Day01
- Week2 - Day02
- Week2 - Day03
- Week2 - Day04
- Week3 - Day01
- Week3 - Day02
- Week3 - Day03
- Week3 - Day04
- Week4 - Day01
- Week4 - Day02
- Week4 - Day03
- Week4 - Day04
- Week4 - Day05
- Week5 - Day01
- Week5 - Day02
- Week5 - Day03
- Week5 - Day04
- Week6 - Day01
- Week6 - Day02