여러 기기에 메시지 보내기

Firebase 클라우드 메시징은 메시지를 여러 기기로 타겟팅하는 방법 2가지를 제공합니다.

  • 주제 메시징: 특정 주제를 구독하는 여러 기기에 메시지를 보낼 수 있습니다.
  • 기기 그룹 메시징: 내가 정의하는 그룹에 속한 여러 기기에 메시지를 보낼 수 있습니다.

이 가이드에서는 앱 서버에서 FCM용 HTTP 또는 XMPP 프로토콜을 사용하여 주제 메시지를 보내는 방법 및 Android 앱에서 메시지를 수신하고 처리하는 방법을 중점적으로 설명하며 백그라운드 앱과 포그라운드 앱의 메시지 처리 방법을 모두 설명합니다. 설정에서 검증까지 이 작업에 필요한 모든 단계를 다룹니다.

SDK 설정

FCM에 대한 Android 클라이언트 앱 설정을 완료했거나 첫 번째 메시지 보내기 단계를 마친 경우 이 섹션에서 다루는 단계를 이미 완료했을 수 있습니다.

기본 요건

  • 다음을 실행하는 기기:
    • Android 4.1(API 수준 16, Jelly Bean) 이상
    • Google Play 서비스 15.0.0 이상
  • Android 스튜디오 최신 버전

Android 스튜디오 프로젝트가 준비되지 않은 경우 빠른 시작 샘플 중 하나를 다운로드하여 Firebase 기능을 시험해 볼 수 있습니다. 빠른 시작을 사용하는 경우 프로젝트의 모듈 폴더(일반적으로 app/)에 있는 build.gradle 파일의 애플리케이션 ID를 확인하세요. 다음 단계에서 이 패키지 이름이 필요합니다.

앱에 Firebase 추가

앱에 Firebase를 추가할 차례입니다. 이를 위해 Firebase 프로젝트 및 앱의 Firebase 구성 파일이 필요합니다.

Firebase 프로젝트를 만드는 방법은 다음과 같습니다.

  1. Firebase 콘솔로 이동합니다.

  2. 프로젝트 추가를 클릭한 다음 프로젝트 이름을 선택하거나 입력합니다.

    • 앱에 연결된 기존 Google 프로젝트가 있으면 프로젝트 이름 드롭다운 메뉴에서 프로젝트를 선택합니다.
    • 기존 Google 프로젝트가 없으면 새 프로젝트 이름을 입력합니다.
  3. (선택사항) 프로젝트 ID를 수정합니다.

    Firebase는 Firebase 프로젝트에 자동으로 고유한 ID를 할당합니다. 이 식별자는 공개적으로 표시되는 Firebase 서비스에 나타납니다. 예를 들면 다음과 같습니다.

    • 기본 실시간 데이터베이스 URL — your-project-id.firebaseio.com
    • 기본 Cloud Storage 버킷 이름 — your-project-id.appspot.com
    • 기본 호스팅 하위 도메인 — your-project-id.firebaseapp.com
  4. Firebase 콘솔에서 나머지 설정 단계를 따른 다음 프로젝트 만들기(또는 기존 Google 프로젝트를 사용 중인 경우 Firebase 추가)를 클릭합니다.

Firebase에서 Firebase 프로젝트용 리소스를 자동으로 프로비저닝합니다. 이 프로세스는 일반적으로 몇 분 정도 걸립니다. 과정이 완료되면 Firebase 콘솔에서 Firebase 프로젝트의 개요 페이지로 이동하게 됩니다.

이제 프로젝트가 준비되었으므로 Android 앱을 추가할 수 있습니다.

  1. Android 앱에 Firebase 추가를 클릭하고 설정 단계를 따릅니다. 기존 Google 프로젝트를 가져오면 이 단계가 자동으로 이루어지므로 구성 파일만 다운로드하면 됩니다.

  2. 메시지가 표시되면 앱의 패키지 이름을 입력합니다. 앱에서 사용하는 패키지 이름을 입력해야 합니다. 이 설정은 Firebase 프로젝트에 앱을 추가할 때만 가능합니다.

  3. 앱에 Firebase Android 구성 파일을 추가합니다.

    1. google-services.json 다운로드를 클릭하여 Firebase Android 구성 파일(google-services.json)을 가져옵니다.

      언제든지 다시 Firebase Android 구성 파일을 다운로드할 수 있습니다.

    2. 구성 파일을 루트 수준 build.gradle 파일과 같은 디렉토리로 이동합니다.

  4. 초기화 코드를 추가한 후 앱을 실행하여 Firebase를 성공적으로 설치했다는 확인을 Firebase 콘솔에 보냅니다.

SDK 추가

프로젝트 중 하나에 Firebase 라이브러리를 통합하려는 경우 몇 가지 기본적인 작업을 수행하여 Android 스튜디오 프로젝트를 준비해야 합니다. 앱에 Firebase를 추가하면서 이 단계를 이미 완료했을 수 있습니다.

우선 루트 수준 build.gradle 파일에 규칙을 추가하여 google-services 플러그인 및 Google의 Maven 저장소를 포함합니다.

buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:4.2.0' // google-services plugin
    }
}

allprojects {
    // ...
    repositories {
        google() // Google's Maven repository
        // ...
    }
}

이제 모듈의 Gradle 파일(일반적으로 app/build.gradle) 하단에 apply plugin 줄을 추가하여 Gradle 플러그인을 사용 설정합니다.

apply plugin: 'com.android.application'

android {
  // ...
}

dependencies {
  // ...
  implementation 'com.google.firebase:firebase-core:16.0.7'
  implementation 'com.google.firebase:firebase-messaging:17.3.4'
  // Getting a "Could not find" error? Make sure you have
  // added the Google maven respository to your root build.gradle
}

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'

또한 사용할 Firebase SDK에 대한 종속 항목을 추가해야 합니다. 우선 Firebase용 Google 애널리틱스 기능을 제공하는 com.google.firebase:firebase-core부터 시작하는 것이 좋습니다. 사용 가능한 라이브러리 목록을 참조하세요.

클라이언트 앱에서 주제 구독

클라이언트 앱에서 기존 주제를 구독하거나 새 주제를 만들 수 있습니다. 클라이언트 앱에서 Firebase 프로젝트에 아직 없는 새 주제 이름을 구독하면 FCM에서 이 이름으로 새 주제가 만들어지고, 이후에 다른 클라이언트에서 그 주제를 구독할 수 있습니다.

주제를 구독하려면 클라이언트 앱에서 FCM 주제 이름과 함께 Firebase 클라우드 메시징 subscribeToTopic()을 호출합니다. 이 메소드는 완료 리스너가 구독 성공 여부를 확인하는 데 사용할 수 있는 Task를 반환합니다.

자바
Android

FirebaseMessaging.getInstance().subscribeToTopic("weather")
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                String msg = getString(R.string.msg_subscribed);
                if (!task.isSuccessful()) {
                    msg = getString(R.string.msg_subscribe_failed);
                }
                Log.d(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

Kotlin
Android

FirebaseMessaging.getInstance().subscribeToTopic("weather")
        .addOnCompleteListener { task ->
            var msg = getString(R.string.msg_subscribed)
            if (!task.isSuccessful) {
                msg = getString(R.string.msg_subscribe_failed)
            }
            Log.d(TAG, msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        }

구독을 취소하려면 클라이언트 앱에서 주제 이름과 함께 Firebase 클라우드 메시징 unsubscribeFromTopic()을 호출합니다.

주제 메시지 수신 및 처리

FCM은 다른 다운스트림 메시지와 동일한 방식으로 주제 메시지를 전송합니다.

메시지를 수신하려면 FirebaseMessagingService를 확장하는 서비스를 사용합니다. 서비스에서 onMessageReceivedonDeletedMessages 콜백을 재정의해야 합니다. 모든 메시지는 수신된 지 20초(Android Marshmallow의 경우 10초) 이내에 처리되어야 합니다. onMessageReceived 호출 전에 발생하는 OS 지연에 따라 이 시간이 더 짧아질 수도 있습니다. 이 시간이 지나면 Android O의 백그라운드 실행 제한과 같은 여러 OS 동작으로 인해 작업을 완료하는 데 지장이 있을 수 있습니다. 자세한 내용은 메시지 우선순위에 대한 개요를 참조하세요.

onMessageReceived는 다음 경우를 제외하고 대부분의 메시지 유형에 제공됩니다.

  • 앱이 백그라운드 상태일 때 전송된 알림: 이 경우 알림이 기기의 작업 표시줄로 전송됩니다. 사용자가 알림을 탭하면 기본적으로 앱 런처가 열립니다.

  • 알림과 데이터 페이로드가 둘 다 포함된 메시지(백그라운드에서 수신된 경우): 이 경우 알림은 기기의 작업 표시줄로 전송되고 데이터 페이로드는 런처 활동의 인텐트 부가 정보로 전송됩니다.

요약하면 다음과 같습니다.

앱 상태 알림 데이터 모두
포그라운드 onMessageReceived onMessageReceived onMessageReceived
백그라운드 작업 표시줄 onMessageReceived 알림: 작업 표시줄
데이터: 인텐트 부가 정보
메시지 유형의 자세한 내용은 알림 및 데이터 메시지를 참조하세요.

앱 매니페스트 수정

FirebaseMessagingService를 사용하려면 앱 매니페스트에 다음을 추가해야 합니다.

<service android:name=".java.MyFirebaseMessagingService">
    <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 객체를 기준으로 작업을 수행하고 메시지 데이터를 가져올 수 있습니다.

자바
Android

@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 Firebase Job Dispatcher.
            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.
}

Kotlin
Android

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.
    remoteMessage?.data?.isNotEmpty()?.let {
        Log.d(TAG, "Message data payload: " + remoteMessage.data)

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
            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.
}

onDeletedMessages 재정의

경우에 따라 FCM에서 메시지를 전달하지 못할 수 있습니다. 특정 기기가 연결될 때 앱에서 대기 중인 메시지가 너무 많거나(100개 초과) 기기가 한 달 이상 FCM에 연결되지 않았기 때문일 수 있습니다. 이러한 경우 FirebaseMessagingService.onDeletedMessages()에 콜백이 수신될 수 있습니다. 이 콜백을 수신한 앱 인스턴스는 앱 서버와 전체 동기화를 수행해야 합니다. 해당 기기의 앱으로 메시지를 보낸 지 4주 이상 경과한 경우 FCM은 onDeletedMessages()를 호출하지 않습니다.

백그라운드 앱에서 알림 메시지 처리

앱이 백그라운드 상태이면 Android에서 알림 메시지를 작업 표시줄로 전달합니다. 사용자가 알림을 탭하면 기본적으로 앱 런처가 열립니다.

여기에는 알림과 데이터 페이로드가 모두 들어 있는 메시지 및 알림 콘솔에서 보낸 모든 메시지가 포함됩니다. 이러한 경우 알림은 기기의 작업 표시줄로 전송되고 데이터 페이로드는 런처 활동의 인텐트 부가 정보로 전송됩니다.

앱으로 전달된 메시지의 통계를 파악하려면, 전송되어 iOS 및 Android 기기에서 열린 메시지 수와 Android 앱의 '노출수'(사용자에게 표시된 알림) 데이터가 기록된 FCM 보고 대시보드를 확인합니다.

백그라운드 제한 앱(Android P 이상)

2019년 1월부터 FCM은 사용자가 백그라운드 제한을 적용한 앱에 메시지를 전달하지 않습니다(예: 설정 -> 앱 및 알림 -> [앱 이름] -> 배터리). 앱이 백그라운드 제한에서 삭제되면 이전과 같이 앱에 새로운 메시지가 전달됩니다. 메시지 손실 및 기타 백그라운드 제한의 영향을 받지 않기 위해 Android vitals에 나열된 잘못된 행동을 하지 않도록 주의하세요. 이러한 행동을 할 경우 Android 기기에서 사용자의 앱을 백그라운드 제한에 포함하도록 권장할 수 있습니다. isBackgroundRestricted()를 사용하여 앱에 백그라운드 제한이 적용되었는지 확인할 수 있습니다.

보내기 요청 작성

Firebase 클라우드 메시징 주제로 메시지를 보내는 것은 개별 기기나 사용자 그룹으로 메시지를 보내는 것과 매우 비슷합니다. 앱 서버는 to 키를 /topics/yourTopic 등의 값으로 설정합니다. 개발자는 다음 정규 표현식과 일치하는 모든 주제 이름을 선택할 수 있습니다. "/topics/[a-zA-Z0-9-_.~%]+"

여러 주제를 조합하여 보내려면 앱 서버에서 to 키 대신 condition 키를 대상 주제를 지정하는 부울 조건으로 설정해야 합니다. 예를 들어 TopicA와 함께 TopicB 또는 TopicC를 구독한 기기로 메시지를 보내는 방법은 다음과 같습니다.

'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)

FCM이 먼저 괄호의 모든 조건을 확인한 다음 왼쪽에서 오른쪽으로 표현식을 확인합니다. 위 표현식에서는 주제 1개를 구독한 사용자는 메시지를 수신하지 않습니다. 또한 TopicA를 구독하지 않은 사용자도 메시지를 수신하지 않습니다. 다음과 같이 조합되어야 메시지를 수신합니다.

  • TopicA 및 TopicB
  • TopicA 및 TopicC

조건식에 최대 5개의 주제를 포함할 수 있으며 괄호가 지원됩니다. 지원되는 연산자는 &&, ||, !입니다. !의 사용법은 다음과 같습니다.

!('TopicA' in topics)

이 식을 사용하면 어떠한 주제도 구독하지 않는 앱 인스턴스를 포함하여 TopicA를 구독하지 않는 모든 앱 인스턴스가 메시지를 수신합니다.

앱 서버 키에 대한 자세한 내용은 HTTP 또는 XMPP 중 선택한 연결 서버 프로토콜에 맞는 참조 정보를 확인하세요. 이 페이지의 예에서는 HTTP 및 XMPP에서 주제로 메시지를 보내는 방법을 모두 보여줍니다.

주제 HTTP POST 요청

주제 1개로 보내는 방법은 다음과 같습니다.

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

'dogs' 또는 'cats' 주제를 구독한 기기로 보내는 방법은 다음과 같습니다.

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

주제 HTTP 응답

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

주제 XMPP 메시지

주제 1개로 보내는 방법은 다음과 같습니다.

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

'dogs' 또는 'cats' 주제를 구독한 기기로 보내는 방법은 다음과 같습니다.

<message id="">
  <gcm xmlns="google:mobile:data">
{
  "condition": "'dogs' in topics || 'cats' in topics",
  "data": {
    "message": "This is a Firebase Cloud Messaging Topic Message!",
   }
}

  </gcm>
</message>

주제 XMPP 응답

//Success example:
{
  "message_id": "1023456"
}

//failure example:
{
  "error": "TopicsMessageRateExceeded"
}

FCM 연결 서버가 주제 전송 요청에 성공 또는 실패 응답을 반환하는 데 최대 30초의 지연이 발생할 수 있습니다. 요청에서 이 지연 시간에 맞게 앱 서버 제한 시간 값을 설정해야 합니다.

메시지 옵션의 전체 목록은 HTTP 또는 XMPP 중 선택한 연결 서버 프로토콜에 맞는 참조 정보를 확인하세요.

다음 단계

다음에 대한 의견 보내기...

도움이 필요하시나요? 지원 페이지를 방문하세요.