Gradle 추가
implementation "androidx.core:core-ktx:1.7.0"
core-ktx는 개발 중에 추가하는 경우가 많으므로 중복추가 되지 않도록 확인
Manifest 설정
Manifest에 Receiver를 등록해야 한다.
안드로이든느 부팅이 끝나면 BOOT_COMPLETED라는 intent를 브로드캐스트 한다.
PendingIntent를 통해서 Notification을 통해서 사용자에게 메시지를 전달하게 되는데, 재부팅 시 해당 설정이 사라진다.
재부팅 후에도 PendingIntent가 남아있으려면 Manifest에 등록이 필요하다.
<receiver android:name="com.jinuemong.SwallowMonthJM.AlarmBroadCastReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
application 설정 내부에 위와같이 BroadCastReceiver를 선언한다.
AlarmBroadCastReceiver는 내가 선언한 BroadCastReceiver로 아래와 같이 클래스를 선언한다.
BroadCastReceiver 선언
class AlarmBroadCastReceiver : BroadcastReceiver()
해당 클래스는 반드시 onReceive 함수를 오버라이드 해야한다.
onReceive 함수 내부에서 알림을 보내기 위한 NotificationManger를 선언하고 실행한다.
class AlarmBroadCastReceiver : BroadcastReceiver() {
@SuppressLint("UnsafeProtectedBroadcastReceiver", "CommitPrefEdits")
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(p0: Context?, p1: Intent?) {
// 알람을 받는 곳
if (p0!=null && p1!=null) {
when(p1.extras?.get("code")){
MainActivity.REQUEST_CODE_1->{ // 일 리셋
Toast.makeText(p0, "init current Data", Toast.LENGTH_SHORT).show()
Log.d("initCurrentData", LocalDateTime.now().toString())
val code = MainActivity.REQUEST_CODE_1
// 인텐트 생성
val intent = Intent(p0, LoginActivity::class.java)
val pendingIntent = PendingIntent.getActivity(p0, 0, intent, PendingIntent.FLAG_IMMUTABLE)
// 알림 생성 - 메시지 전달
val builder = NotificationCompat.Builder(p0, "my_channel")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("[Swallow Notification]")
.setContentText("update data today!")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
// 알림 실행
NotificationManagerCompat.from(p0).apply {
notify(code, builder.build())
}
//채널 등록
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"my_channel", "Notification",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "Notification"
}
val notificationManager =
p0.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
MainActivity.REQUEST_CODE_2->{ //월 리셋
Toast.makeText(p0, "initMonthData", Toast.LENGTH_SHORT).show()
Log.d("initMonthData", LocalDateTime.now().toString())
val code = MainActivity.REQUEST_CODE_2
// 인텐트 생성
val intent = Intent(p0, LoginActivity::class.java)
val sr = p0.getSharedPreferences("fragment",Context.MODE_PRIVATE)
sr.edit().putString("fragment","recently").apply()
val pendingIntent = PendingIntent.getActivity(p0, 0, intent, PendingIntent.FLAG_IMMUTABLE)
// 알림 생성 - 메시지 전달
val builder = NotificationCompat.Builder(p0, "my_channel_2")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("[Swallow Notification_2]")
.setContentText("update month data!")
.setContentIntent(pendingIntent)
.setAutoCancel(true) //클릭 시 삭제
// 알림 실행
NotificationManagerCompat.from(p0).apply {
notify(code, builder.build())
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"my_channel_2", "Notification_2",
NotificationManager.IMPORTANCE_DEFAULT // 알림음 있음
).apply {
description = "Notification_2"
}
val notificationManager =
p0.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}
}
}
}
onReceive에서는 context와 Intent를 전달 받는다.
context를 통해서 리시버를 실행시킨 곳에서 extras 데이터를 전달받을 수 있으며, 이를 통해서 코드를 구분한다.
전달 받은 코드가 REQUEST_CODE_1인 경우에는 day Data를 리셋하는 메시지를 전달,
전달 받은 코드가 REQUEST_CODE_2인 경우에는 month Data를 리셋하는 메시지를 전달한다.
https://jinudmjournal.tistory.com/97
이전에 작성한 포스팅인 WorkManager에서 아래와 같은 코드가 있었다.
// 실행
if (Calendar.getInstance().get(Calendar.DAY_OF_MONTH)==1){
applicationContext.sendBroadcast(monthBroadIntent())
}else{
applicationContext.sendBroadcast(dayBroadIntent())
}
이는 앱의 day or month 데이터가 갱신되었다는 메시지를 전달하는 코드이다.
아래의 코드로 동작하며 상황에 따라 다른 REQUEST_CODE를 전달받는다.
//앱 실행 알림
private fun dayBroadIntent() :Intent {
return Intent(applicationContext,AlarmBroadCastReceiver::class.java)
.let {intent->
intent.putExtra("code", REQUEST_CODE_1)
}
}
private fun monthBroadIntent() : Intent{
return Intent(applicationContext,AlarmBroadCastReceiver::class.java)
.let { intent ->
intent.putExtra("code", REQUEST_CODE_2)
}
}
이를 통해서 AlarmBroadCastReceiver의 onReceive() 함수가 실행되는 것이다.
첫번째 인자를 받는 경우로 코드를 살펴보면,
1. 인텐트를 생성
늦은 시작 Intent인 pendingIntent를 선언한다.
// 인텐트 생성
val intent = Intent(p0, LoginActivity::class.java)
val pendingIntent = PendingIntent.getActivity(p0, 0, intent, PendingIntent.FLAG_IMMUTABLE)
2. 알림 생성
사용자에게 보낼 알림을 생성한다.
메시지의 내부를 담당하는 builder를 선언하며, 아이콘, 제목, 메시지 내용을 설정해준다.
이 후에 pendingIntent를 실행 인텐트로 넣어주고, AutoCancel를 통해서 클릭 시 삭제가 가능하게 한다.
// 알림 생성 - 메시지 전달
val builder = NotificationCompat.Builder(p0, "my_channel")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("[Swallow Notification]")
.setContentText("update data today!")
.setContentIntent(pendingIntent)
.setAutoCancel(true)
3. 알림 실행
생성한 알림을 실행한다.
// 알림 실행
NotificationManagerCompat.from(p0).apply {
notify(code, builder.build())
}
4. 채널 등록
NotificationChannel을 통해서 channel을 등록한다.
SDK 버전을 검사해서 Notification 기능이 동작할 수 있는지 확인하고,
NotificationManager를 통해서 생성한 알림을 등록한다.
//채널 등록
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"my_channel", "Notification",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "Notification"
}
val notificationManager =
p0.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
원하는 기능인 매일 자정에 새로운 기능이 업데이트 되었다는 알림을 받을 수 있었다.