Firebase 알림의 동작은 수신하는 앱의 포그라운드/백그라운드 상태에 따라 달라집니다. 포그라운드 상태인 앱에서 알림 메시지 또는 데이터 메시지를 수신하려면 onMessageReceived
콜백을 처리하는 코드를 작성해야 합니다.
알림과 데이터 메시지의 차이점에 대한 설명은 메시지 유형을 참조하세요.
메시지 처리
메시지를 수신하려면 FirebaseMessagingService
를 확장하는 서비스를 사용합니다.
서비스에서 onMessageReceived
및 onDeletedMessages
콜백을 재정의해야 합니다.
onMessageReceived
는 다음 경우를 제외하고 대부분의 메시지 유형에 제공됩니다.
-
앱이 백그라운드에서 실행되고 있을 때 전송된 알림 메시지: 이 경우 알림이 기기의 작업 표시줄로 전송됩니다. 사용자가 알림을 탭하면 기본적으로 앱 런처가 열립니다.
-
알림과 데이터 페이로드가 둘 다 포함된 메시지(백그라운드에서 수신된 경우): 이 경우 알림은 기기의 작업 표시줄로 전송되고 데이터 페이로드는 런처 활동의 인텐트 부가 정보로 전송됩니다.
요약하면 다음과 같습니다.
앱 상태 | 알림 | 데이터 | 모두 |
---|---|---|---|
포그라운드 | onMessageReceived |
onMessageReceived |
onMessageReceived |
배경 | 작업 표시줄 | onMessageReceived |
알림: 작업 표시줄 데이터: 인텐트 부가 정보 |
onMessageReceived
콜백에는 알림을 간단히 게시할 수 있는 제한 시간이 제공되지만 타이머는 앱이 네트워크에 액세스하거나 추가 작업을 수행하도록 설계되지 않았습니다. 따라서 앱이 더 복잡한 작업을 수행하는 경우 앱이 작업을 완료할 수 있도록 추가 작업을 해야 합니다.
앱에서 메시지를 처리하는 데 10초 가까이 걸릴 것으로 예상되면 WorkManager 작업을 예약하거나 아래의 WakeLock 안내를 따르세요. 경우에 따라 메시지를 처리하는 데 걸리는 시간은 onMessageReceived
호출 전에 발생하는 지연에 따라 10초보다 짧아질 수도 있습니다. 여기에는 OS 지연, 앱 시작 시간, 다른 작업에 의해 차단되는 기본 스레드 또는 긴 시간이 소요되는 이전 onMessageReceived
호출이 포함됩니다. 이 타이머가 만료되면 앱에 프로세스 종료 또는 백그라운드 실행 제한이 적용될 수 있습니다. 네트워크 트랜잭션과 앱 시작의 지연 시간은 클 수 있으므로, 네트워크 액세스나 집약적인 데이터 로드 요구사항과 같은 비동기 종속 항목이 있는 경우 메시지 처리가 오래 실행되도록 계획하세요.
앱 매니페스트 수정
FirebaseMessagingService
를 사용하려면 앱 매니페스트에 다음을 추가해야 합니다.
<service android:name=".java.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
또한 알림의 모양을 맞춤설정하는 기본값을 설정하는 것이 좋습니다. 커스텀 기본 아이콘 및 색상을 지정하여 알림 페이로드에 해당 값이 설정되지 않았을 때 항상 지정된 값이 적용되게 할 수 있습니다.
application
태그 안에 다음 줄을 추가하여 커스텀 기본 아이콘 및 색상을 설정합니다.
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages. See README(https://goo.gl/l4GJaQ) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_stat_ic_notification" /> <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming notification message. See README(https://goo.gl/6BKBk7) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/colorAccent" />
Android는 다음 경우에 커스텀 기본 아이콘을 표시합니다.
- 알림 작성기에서 보낸 모든 알림 메시지
- 알림 페이로드에 아이콘이 명시적으로 설정되지 않은 모든 알림 메시지
Android는 다음 경우에 커스텀 기본 색상을 사용합니다.
- 알림 작성기에서 보낸 모든 알림 메시지
- 알림 페이로드에 색상이 명시적으로 설정되지 않은 모든 알림 메시지
커스텀 기본 아이콘이 설정되지 않았고 알림 페이로드에도 아이콘이 설정되지 않았으면 Android에서 애플리케이션 아이콘을 흰색으로 렌더링해 표시합니다.
onMessageReceived
재정의
FirebaseMessagingService.onMessageReceived
메서드를 재정의하면 수신된 RemoteMessage 객체를 기준으로 작업을 수행하고 메시지 데이터를 가져올 수 있습니다.
Kotlin
override fun onMessageReceived(remoteMessage: RemoteMessage) { // TODO(developer): Handle FCM messages here. // Not getting messages here? See why this may be: https://goo.gl/39bRNJ Log.d(TAG, "From: ${remoteMessage.from}") // Check if message contains a data payload. if (remoteMessage.data.isNotEmpty()) { Log.d(TAG, "Message data payload: ${remoteMessage.data}") // Check if data needs to be processed by long running job if (needsToBeScheduled()) { // For long-running tasks (10 seconds or more) use WorkManager. scheduleJob() } else { // Handle message within 10 seconds handleNow() } } // Check if message contains a notification payload. remoteMessage.notification?.let { Log.d(TAG, "Message Notification Body: ${it.body}") } // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. }
Java
@Override public void onMessageReceived(RemoteMessage remoteMessage) { // TODO(developer): Handle FCM messages here. // Not getting messages here? See why this may be: https://goo.gl/39bRNJ Log.d(TAG, "From: " + remoteMessage.getFrom()); // Check if message contains a data payload. if (remoteMessage.getData().size() > 0) { Log.d(TAG, "Message data payload: " + remoteMessage.getData()); if (/* Check if data needs to be processed by long running job */ true) { // For long-running tasks (10 seconds or more) use WorkManager. scheduleJob(); } else { // Handle message within 10 seconds handleNow(); } } // Check if message contains a notification payload. if (remoteMessage.getNotification() != null) { Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody()); } // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. }
FCM 메시지를 처리하는 동안 기기를 켜진 상태로 유지
앱이 FCM 메시지를 처리하는 동안 기기를 켜진 상태로 유지해야 하는 경우 이 시간 동안 WakeLock을 유지하거나 WorkManager 작업을 만들어야 합니다. WakeLock은 onMessageReceived
기본 제한 시간을 초과할 수 있는 짧은 처리 활동에 적합합니다. 서버에 여러 개의 직렬 RPC를 전송하는 것과 같은 확장된 워크플로의 경우 WakeLock보다는 WorkManager 작업을 사용하는 것이 더 적합합니다. 이 섹션에서는 WakeLock을 사용하는 방법을 중점적으로 다룹니다. WakeLock은 앱이 실행되는 동안 기기가 절전 모드로 전환되지 않도록 방지하므로 배터리 사용량이 증가할 수 있습니다. 따라서 WakeLock 사용은 다음과 같은 메시지를 처리하는 동안 앱이 일시중지되지 않아야 하는 경우에만 예약해야 합니다.
- 시간에 민감한 사용자 알림
- 기기 외부에서 중단되어서는 안 되는 항목과의 상호작용(예: 네트워크 전송 또는 페어링된 시계와 같은 다른 기기와의 통신)
먼저 앱이 WakeLock 권한을 요청하는지 확인해야 합니다(FCM SDK에는 기본적으로 이 권한이 포함되어 있으므로 일반적으로 추가할 필요가 없음).
<uses-permission android:name="android.permission.WAKE_LOCK" />
그러면 앱이 FirebaseMessagingService.onMessageReceived()
콜백 시작 시 WakeLock을 획득하고 콜백 종료 시 이를 해제해야 합니다.
앱의 커스텀 FirebaseMessagingService
:
@Override public void onMessageReceived(final RemoteMessage message) { // If this is a message that is time sensitive or shouldn't be interrupted WakeLock wakeLock = getSystemService(PowerManager.class).newWakeLock(PARTIAL_WAKE_LOCK, "myApp:messageReceived"); try { wakeLock.acquire(TIMEOUT_MS); // handle message ... finally { wakeLock.release(); } }
onDeletedMessages
재정의
경우에 따라 FCM에서 메시지를 전송하지 못할 수 있습니다. 특정 기기가 연결될 때 앱에서 대기 중인 메시지가 너무 많거나(100개 초과) 기기가 한 달 넘게 FCM에 연결되지 않으면 이 문제가 발생합니다. 이러한 경우 FirebaseMessagingService.onDeletedMessages()
에 대한 콜백이 수신될 수 있습니다. 이 콜백을 수신한 앱 인스턴스는 앱 서버와 전체 동기화를 수행해야 합니다. 해당 기기의 앱으로 메시지를 보낸 지 4주 이상 경과한 경우 FCM은 onDeletedMessages()
를 호출하지 않습니다.
백그라운드 앱에서 알림 메시지 처리
앱이 백그라운드 상태이면 Android에서 알림 메시지를 작업 표시줄로 전송합니다. 사용자가 알림을 탭하면 기본적으로 앱 런처가 열립니다.
여기에는 알림과 데이터 페이로드가 둘 다 포함된 메시지 및 알림 콘솔에서 보낸 모든 메시지가 포함됩니다. 이러한 경우 알림은 기기의 작업 표시줄로 전송되고 데이터 페이로드는 런처 활동의 인텐트 부가 정보로 전송됩니다.
앱으로 전송된 메시지의 통계를 파악하려면, Apple 및 Android 기기에서 열린 전송 메시지 수와 Android 앱의 '노출수'(사용자에게 표시된 알림) 데이터가 기록된 FCM 보고 대시보드를 확인합니다.
직접 부팅 모드에서 FCM 메시지 수신
기기가 잠금 해제되기 전에 앱에 FCM 메시지를 보내려는 개발자는 기기가 직접 부팅 모드일 때 Android 앱에서 메시지를 수신하도록 사용 설정할 수 있습니다. 예를 들어 잠긴 기기에서도 앱 사용자가 경보 알림을 받도록 할 수 있습니다.
이 사용 사례를 빌드할 때 일반적인 직접 부팅 모드 권장사항 및 제한사항을 확인하세요. 직접 부팅이 사용 설정된 메시지의 공개 상태를 고려해야 합니다. 기기에 액세스할 수 있는 모든 사용자는 사용자 인증 정보를 입력하지 않고도 이러한 메시지를 볼 수 있습니다.
기본 요건
- 기기가 직접 부팅 모드로 설정되어야 합니다.
- 기기에 최신 버전의 Google Play 서비스(19.0.54 이상)가 설치되어 있어야 합니다.
- 앱에서 FCM 메시지를 수신하기 위해 FCM SDK(
com.google.firebase:firebase-messaging
)를 사용해야 합니다.
앱에서 직접 부팅 모드 메시지 처리 사용 설정
앱 수준 Gradle 파일에서 FCM 직접 부팅 지원 라이브러리에 종속 항목을 추가합니다.
implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
앱 매니페스트에
android:directBootAware="true"
속성을 추가하여 앱의FirebaseMessagingService
가 직접 부팅을 인식하도록 합니다.<service android:name=".java.MyFirebaseMessagingService" android:exported="false" android:directBootAware="true"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
이 FirebaseMessagingService
가 직접 부팅 모드에서 실행되는지 확인하는 것이 중요합니다. 다음 요구사항을 확인하세요.
- 직접 부팅 모드에서 실행되는 동안 서비스가 사용자 인증 정보로 보호되는 스토리지에 액세스하면 안 됩니다.
- 직접 부팅 모드에서 실행되는 동안 서비스가 직접 부팅 인식으로 표시되지 않는
Activities
,BroadcastReceivers
또는 기타Services
와 같은 구성요소를 사용하려고 시도해서는 안 됩니다. - 서비스에서 사용하는 모든 라이브러리도 직접 부팅 모드에서 실행되는 동안 사용자 인증 정보로 보호되는 스토리지에 액세스하거나 directBootAware가 아닌 구성요소를 호출해서는 안 됩니다. 즉, 서비스에서 호출되는 앱에서 사용하는 라이브러리는 직접 부팅을 인식해야 하며, 그렇지 않은 경우 앱에서 라이브러리가 직접 부팅 모드에서 실행되는지 확인하고 해당 모드에서 호출하지 않아야 합니다. 예를 들어 Firebase SDK는 직접 부팅에서 작동하지만(직접 부팅 모드에서 비정상 종료되지 않고 앱에 포함될 수 있음) 대부분의 Firebase API는 직접 부팅 모드에서 호출되는 것을 지원하지 않습니다.
- 앱에서 커스텀
Application
을 사용하는 경우Application
도 직접 부팅을 인식해야 합니다(직접 부팅 모드에서 사용자 인증 정보로 보호되는 스토리지에 액세스할 수 없음).
직접 부팅 모드에서 기기로 메시지를 보내는 방법에 대한 안내는 직접 부팅이 사용 설정된 메시지 보내기를 참조하세요.