관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] 안드로이드 AlarmManager 와 WorkManager 사용하여 10분전 알림 만들기 본문

안드로이드/코틀린 & 아키텍처 & Recent

[안드로이드] 안드로이드 AlarmManager 와 WorkManager 사용하여 10분전 알림 만들기

막무가내막내 2020. 9. 2. 13:43
728x90

 

[2021-04-14 업데이트]

 

github.com/mtjin/NoMoneyTrip

 

mtjin/NoMoneyTrip

SKT 2020 스마트 관광앱 공모전 '무전여행' 앱. Contribute to mtjin/NoMoneyTrip development by creating an account on GitHub.

github.com

안녕하세요 AlarmManager 와 WorkManager 를 최근 프로젝트에서 사용해보았는데 간략하게 정리해보는 포스팅을 하려고합니다. ㅎㅎ

먼저 위 프로젝트에서 해당 코드들을 볼 수 있습니다.


[참고]

https://developer.android.com/guide/background?hl=ko

 

백그라운드 처리 가이드  |  Android 개발자  |  Android Developers

백그라운드 데이터 처리는 사용자의 기대에 부응하고 사용자에게 도움이 되는 Android 애플리케이션을 개발하는 데 있어 중요한 부분입니다. 이 가이드에서는 백그라운드 작업 카테고리를 정의��

developer.android.com

https://namget.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-AlarmManager-With-Notification-Example-%EC%95%8C%EB%9E%8C%EB%A7%A4%EB%8B%88%EC%A0%80%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-%ED%91%B8%EC%89%AC%EC%83%9D%EC%84%B1-%EC%98%88%EC%A0%9C

 

[안드로이드] AlarmManager With Notification Example (알람매니저를 이용하여 푸쉬생성 예제)

 안녕하세요 YTS 입니다. 오늘은 알람매니저(AlarmManager)를 이용하여 푸쉬(Notification)를 생성하는 예저를 다루어볼까합니다. 추가적으로 JobScheduler를 이용하여 백그라운드에서도 반응하도록 예제

namget.tistory.com

 

 

 

백그라운드 작업 처리시 안드로이드 개발자 문서에 적혀있듯이 다음과 같은 트리로 개발하면 됩니다.

즉시 실행해야한다 ? -> 코루틴, WorkManager

정확한 시간에 실행해야한다? -> AlaramManager

지연된 작업(Deferred)으로 실행해야한다? -> WorkManager


먼저 둘의 큰 차이점은 AlarmManager 는 정확한 시간을 지킨다는 것이고 WorkManager 는 Deffered 하다는 것인데 둘의 특성이 둘 다 필요해서 함께 사용해봤습니다. (주로 AlarmManager 는 말그대로 알람에, WorkManager 는 반드시 실행되거나 오래걸리는작업 등을 백그라운드에서 작업하기 위해 사용합니다. 예를 들면 이미지 업로드 등)

 

[ Dependency ]

// Work Manager
    implementation "androidx.work:work-runtime-ktx:2.4.0"

 

[ 권한 ]

<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

 

[ Manifest service 등록 ]

<service
            android:name=".service.fcm.MyFirebaseMessagingService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <receiver android:name=".service.notification.NotificationBroadcastReceiver" />

 

[ 알람매니저를 사용한 노티피케이션 등록 부분 ]

RTC_WAKEUP - 지정된 시간에 기기의 절전 모드를 해제하여 대기 중인 인텐트를 실행합니다

setsetAndAllowWhileIdle() - 도즈모드에서도 알림이 울릴 수 있게한다. 

한 가지 주의할 점은 안드로이드의 배터리정책에 의해 9분간에 하나의 알림만 울릴 수 있다는 제한 사항이 있습니다.

val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val alarmIntent =
            Intent(context, NotificationBroadcastReceiver::class.java).let { intent ->
                intent.putExtra(EXTRA_NOTIFICATION_TITLE, title)
                intent.putExtra(EXTRA_NOTIFICATION_MESSAGE, message)
                PendingIntent.getBroadcast(context, 0, intent, 0)
            }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmMgr.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                원래타임스탬프 - TimeUnit.MINUTES.toMillis(10),// 10분전알림
                alarmIntent
            )
        } else {
            alarmMgr.setExact(
                AlarmManager.RTC_WAKEUP,
                원래타임스탬프 - TimeUnit.MINUTES.toMillis(10),// 10분전알림
                alarmIntent
            )
        }

추가로 API 버전에 따라 다음 권한요청이 필요할 수 있습니다.

 

 

 

 

 

 

[ NotificationBroadcastReceiver ] - AlarmManager 부분

위 코드의 알람매니저 노티피케이션 전송을  수신할BroadcastReceiver 입니다. 받은 후 WorkManager 를 통해 알람을 등록합니다.

https://docs.microsoft.com/ko-kr/xamarin/android/platform/android-job-scheduler

package com.mtjin.nomoneytrip.fcm

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.work.BackoffPolicy
import androidx.work.Data
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.mtjin.nomoneytrip.utils.EXTRA_NOTIFICATION_MESSAGE
import com.mtjin.nomoneytrip.utils.EXTRA_NOTIFICATION_TITLE
import java.util.concurrent.TimeUnit

class NotificationBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent?) {
        intent?.let {
            val title = it.getStringExtra(EXTRA_NOTIFICATION_TITLE).toString()
            val message = it.getStringExtra(EXTRA_NOTIFICATION_MESSAGE).toString()
            // Create Notification Data
            val notificationData = Data.Builder()
                .putString(EXTRA_NOTIFICATION_TITLE, title)
                .putString(EXTRA_NOTIFICATION_MESSAGE, message)
                .build()
            
            // WorkManager 사용
            val workRequest =
                OneTimeWorkRequestBuilder<ScheduledWorker>()
                    .setInputData(notificationData)
                    .setBackoffCriteria(BackoffPolicy.LINEAR, 30000, TimeUnit.MILLISECONDS)
                    .build()

            val workManager = WorkManager.getInstance(context)
            workManager.enqueue(workRequest)
        }
    }
}

 

 

 

 

[ ScheduledWorker ]  - WorkManager 부분

Worker 를 상속하여 WorkManager 를 만들어줍니다. 파라미터를 전달받을 수 도 있고 백그라운드로 작업이 진행됩니다.

package com.mtjin.nomoneytrip.fcm

import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.mtjin.nomoneytrip.utils.EXTRA_NOTIFICATION_MESSAGE
import com.mtjin.nomoneytrip.utils.EXTRA_NOTIFICATION_TITLE
import com.mtjin.nomoneytrip.utils.NotificationUtil

class ScheduledWorker(appContext: Context, workerParams: WorkerParameters) :
    Worker(appContext, workerParams) {

    override fun doWork(): Result {

        // Get Notification Data
        val title = inputData.getString(EXTRA_NOTIFICATION_TITLE).toString()
        val message = inputData.getString(EXTRA_NOTIFICATION_MESSAGE).toString()
        // FCM 전송
        NotificationUtil(applicationContext).showNotification(
            title,
            message
        )

        return Result.success()

    }
}

 

WorkManager 관련 설명은 다음 링크에서 추가로 보실 수 있습니다. (이 포스팅에서는 생략을 했습니다.)

youngest-programming.tistory.com/361

 

[코틀린] Jetpack WorkManager 백그라운드 작업처리 정리

[먼저 이 모든 코드는 제가 실제 적용한 프로젝트 코드가 아닌 예제로 만든 것임을 알려드립니다. 그래서 오타가 있을 수도 있습니다. ] [참고] https://developer.android.com/guide/background?hl=ko 백그라운��

youngest-programming.tistory.com

 

 

 

 

 

댓글과 공감은 큰 힘이 됩니다. 감사합니다 !!

 

 

[개인 기록 샘플]

Remote쪽에서 예약전날 알림과 예약종료날 리뷰알림 관련 코드입니다.

리모트 쪽에서 이 함수를 통해 바로 WorkManager로는 예약종료날 리뷰알림을 AlarmManager + WorkManager 로는 예약전날 알림을 구현합니다.

override fun sendNotification(reservation: Reservation, product: Product) {
        val title = product.title
        val message = convertTimeToFcmMessage(
            date = reservation.startDateTimestamp,
            time = product.checkIn
        )
        val startScheduledTime = reservation.startDateTimestamp
        val endScheduledTime = reservation.endDateTimestamp
        val timeDiff = endScheduledTime + TimeUnit.HOURS.toMillis(18) - System.currentTimeMillis()
        val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val startAlarmIntent =
            Intent(context, NotificationBroadcastReceiver::class.java).let { intent ->
                intent.putExtra(EXTRA_NOTIFICATION_TITLE, title)
                intent.putExtra(EXTRA_NOTIFICATION_MESSAGE, message)
                intent.putExtra(EXTRA_NOTIFICATION_MESSAGE, message)
                PendingIntent.getBroadcast(context, 0, intent, 0)
            }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmMgr.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                startScheduledTime - TimeUnit.HOURS.toMillis(11),// 전날알림(13시)
                startAlarmIntent
            )
        } else {
            alarmMgr.setExact(
                AlarmManager.RTC_WAKEUP,
                startScheduledTime - TimeUnit.HOURS.toMillis(11),// 전날알림(13시)
                startAlarmIntent
            )
        }
        //종료날 리뷰요청
        val notificationData = Data.Builder()
            .putString(EXTRA_NOTIFICATION_TITLE, title)
            .putString(EXTRA_NOTIFICATION_MESSAGE, "여행은 어떠셨나요? 리뷰를 남겨주세요 :)")
            .build()
        val workRequest =
            OneTimeWorkRequestBuilder<ScheduledWorker>()
                .setInputData(notificationData)
                .setInitialDelay(timeDiff, TimeUnit.MILLISECONDS) // 18시 알림
                .setBackoffCriteria(BackoffPolicy.LINEAR, 30000, TimeUnit.MILLISECONDS)
                .build()
        val workManager = WorkManager.getInstance(context)
        workManager.enqueue(workRequest)
    }

 

728x90
Comments