플랫폼 개발팀 기술 블로그

[FCM] #3. Firebase 메시지 전송 본문

Article

[FCM] #3. Firebase 메시지 전송

피랑이 2019. 2. 14. 17:43

[FCM] #1. 소개 및 메시지

[FCM] #2. Firebase 프로젝트 생성 및 Android 앱 FCM 설정

[FCM] #3. Firebase 메시지 전송

[FCM] #4. Android 메시지 처리




일반적인 FCM(Firebase Cloud Message) 발송은 앱 서버에서 FCM 서버로 메시지 요청을 보내고, FCM 서버에서는 다시 클라이언트 기기 앱에 메시지를 보낸다. 


#2에서는 FCM 서버에서 클라이언트 기기로 수신되도록 세팅을 하였다. 

이번 #3에서는 앱 서버에서 FCM 서버로 메시지 요청을 보내는 방법에 대해서 알아본다. 


FCM 서버로 전송하는 방법으로는 크게 3가지 구분된다. 


1. Firebase Admin SDK 이용

2. HTTP V1 API 이용

3. 기존 HTTP API 이용


각 전송 방법 별로 가능한 수신 분류에 대해 정리하였다. 

 

단일 기기

멀티캐스트

(여러 기기)

기기 그룹 

주제 구독 

 Firebase Admin SDK

O

X

X

 HTTP V1 API

O

X

O

 기존 HTTP API

O

O

O

추가로 #2에서 Android Studio에서 기기 그룹이나 주제 구독에 대한 처리를 하지 않았으므로 단일 기기로만 발송테스트를 진행한다. 


Firebase Admin SDK로 발송 

Firebase Admin SDK를 사용하면 자체 백엔드 서비스를 Firebase 클라우드 메시징(FCM)과 통합할 수 있습니다. 
Admin FCM API는 Firebase 서버 인증을 처리하는 동시에 메시지 보내기와 주제 구독 관리를 지원합니다.

위 소개글에 보면 주로 백엔드 관리툴에서 테스트 형태로 사용할 수 있다는 의미인거 같다.  사실 3가지 방법 중 가장 심플한 방법으로 백엔드 관리툴에 붙여도 된다. 

환경설정 및 초기화

Admin SDK를 사용하려면, 아래 3가지 방법 중 하나를 사용해야 한다. 
- projectId Firebase 앱 옵션을 명시적으로 지정합니다.

서비스 계정 사용자 인증 정보로 SDK를 초기화합니다.

- GCLOUD_PROJECT 환경 변수를 설정합니다.

우리는 서비스 계정 사용자 인증 정보로 SDK 초기화 사용한다. 


먼저 사용해야할 비공개 키를 발급받는다.


Firebase 콘솔에서 설정>서비스계정에 들어가면 새 비공개 키 생성 이라는 버튼이 보인다. 


문구에서도 나와 있듯이 공개 저장소에는 넣지 말자.

추가로 json 파일은 내용을 열어서 확인해 보면 좋다. 

프로젝트 관련 비밀키 및 환경 정보들이 들이있다. 


각자 자바 프로젝트 생성하자.

다운로드를 받은 json 파일을 넣자. 

본인은 기본 클래스패스인 resource에 넣었다. 


종속성도 처리하자. 본인은 maven을 사용하므로 pom.xml에 종속성을 추가하였다. 


  com.google.firebase
  firebase-admin
  6.4.0

이제 SDK 초기화 코드를 넣어 보자.

InputStream serviceAccount = null;
FirebaseOptions options = null;
try {
    ClassPathResource resource = new ClassPathResource("fcmmsg.json");
    serviceAccount = resource.getInputStream();
    options = new FirebaseOptions.Builder()
        .setCredentials(GoogleCredentials.fromStream(serviceAccount))
        .build();
    FirebaseApp.initializeApp(options, "fcmmgs");
} catch (FileNotFoundException e) {
    logger.error("Firebase ServiceAccountKey FileNotFoundException" + e.getMessage());
} catch (IOException e) {
    logger.error("FirebaseOptions IOException" + e.getMessage());
}

이것으로 Admin SDK 설정 및 초기화가 완료 되었다. 

추가 정보는 https://firebase.google.com/docs/admin/setup?authuser=0#initialize_the_sdk 여기를 참조하자. 

전송

개별 기기로 전송하는 부분을 추가한다.  
Notification notification = new Notification("타이틀","내용");

Message message = Message.builder()
.putData("score", "850")
.putData("time", "2:45")
.setToken("기기토큰정보")
.setNotification(notification)
.build();

String response = null;
try {
    response = FirebaseMessaging.getInstance(FirebaseApp.getInstance("fcmmsg")).send(message );
} catch (FirebaseMessagingException e) {
    logger.error("Firebase FirebaseMessagingException" + e.getMessage());
    e.printStackTrace();
}

추가 정보는 https://firebase.google.com/docs/cloud-messaging/admin/send-messages?authuser=0 여기를 참조하자.


에뮬레이터로 확인해 보면 메시지가 온 것을 확인할 수 있다. 

HTTP V1 API 발송

기존 HTTP API 보다 액세스 토큰을 통한 보안 향상, 확장성 강화, 메시지 맞춤설정 등 장점이 많다.
HTTP API는 발송하는 서버키 값이 고정인데 반해 HTTP V1은 발송하는 서버키 값을 엑세스 토큰으로 받아서 사용하는 부분이 다르다. 
하지만 멀티캐스트 메시징을 지원하지 않아 아직까지는 기존 HTTP API를 많이 사용한다. 

환경설정 및 초기화

본인은 http 플로그인을 okhttp를 사용하기 위에 종속성을 추가하였다. 


 com.squareup.okhttp3
 okhttp
 3.9.1

HTTP V1 API를 사용하기 위해 초기화 코드를 넣는다. 

GoogleCredential googleCredential = null;
InputStream serviceAccount = null;
String SCOPES = "https://www.googleapis.com/auth/firebase.messaging";
try {
    ClassPathResource resource = new ClassPathResource("fcmmsg.json");
    serviceAccount = resource.getInputStream();
    googleCredential = GoogleCredential
            .fromStream(serviceAccount)
            .createScoped(Arrays.asList(SCOPES));
} catch (IOException e) {
    e.printStackTrace();
}
알림 메시지 구조
아래 정보는 알림메시지 샘플데이터다. 
기존 HTTP 알림메시지와는 조금 다르다. 
{
  "message": {
    "token": "bk3RNwTe3H0:CI2k_...",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    }
  }
}
//com.google.gson 사용
JsonObject jsonObj = new JsonObject();
jsonObj.addProperty("token", "토큰정보");
JsonObject notification = new JsonObject();
notification.addProperty("body", "\uD83D\uDE03바디V1");
notification.addProperty("title", "\uD83D\uDE03타이틀V1");
jsonObj.add("notification", notification);
JsonObject message = new JsonObject();
message.add("message", jsonObj);

전송

요청할 URL은 아래와 같다. 
https://fcm.googleapis.com/v1/projects/프로젝트ID/messages:send
Firebase 콘솔로 들어가서 프로젝트 ID는 설정>일반 메뉴에서 볼 수 있다. 


전송 코드를 추가한다. 

추가 정보는 https://firebase.google.com/docs/cloud-messaging/migrate-v1?authuser=0 여기를 참조하자.


final MediaType mediaType = MediaType.parse("application/json");
OkHttpClient httpClient = new OkHttpClient();
try {

    Request request = new Request.Builder().url("https://fcm.googleapis.com/v1/projects/fcmmsg/messages:send")
        .addHeader("Content-Type", "application/json; UTF-8")
        .addHeader("Authorization", "Bearer " + googleCredential.getAccessToken())
        .post(RequestBody.create(mediaType, message.toString())).build();
    Response response = httpClient.newCall(request).execute();
    logger.info("Successfully sent message: " + response);
} catch (IOException e) {
    logger.error("Error in sending message to FCM server " + e);
}

에뮬레이터로 확인해 보면 메시지가 온 것을 확인할 수 있다. 

기존 HTTP API 발송

아직 많이 사용하고 있는 방식이다. 

메시지 가공 및 발송


//메시지 가공
JsonObject jsonObj = new JsonObject();
//token
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree("등록토큰");
jsonObj.add("to", jsonElement);
//Notification
JsonObject notification = new JsonObject();
notification.addProperty("title", "\uD83D\uDE03타이틀HTTP");
notification.addProperty("body", "\uD83D\uDE03바디HTTP");
jsonObj.add("notification", notification);

/*발송*/
final MediaType mediaType = MediaType.parse("application/json");
OkHttpClient httpClient = new OkHttpClient();
try {
    Request request = new Request.Builder().url("https://fcm.googleapis.com/fcm/send")
        .addHeader("Content-Type", "application/json; UTF-8")
        .addHeader("Authorization", "key=" + "서버키값")
        .post(RequestBody.create(mediaType, jsonObj.toString())).build();
    Response response = httpClient.newCall(request).execute();
    String res = response.body().string();
    logger.info("notification response " + res);
} catch (IOException e) {
    logger.info("Error in sending message to FCM server " + e);
}
등록토큰은 기기 토큰 값을 넣어준다.

서버키값은 Firebase 콘솔에 가서 설정>클라우드 메시징에 가면 정보가 있다. 

알림메시지 구조

to는 기기 토큰, 기기 그룹 토큰, 주제가 들어갈수 있다. 

멀티 캐스트로 발송하려면 to를 사용하지 않고 registration_ids를 사용한다. 

{
  "to": "",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available."
  },
  "data": {
    "story_id": "story_12345"
  }
}

에뮬레이터로 확인해 보면 메시지가 온 것을 확인할 수 있다. 

마치며

여러기기에 메시지를 전송하는 멀티캐스트는 기존 HTTP API만 가능하다. 
보안이나 확장성이 강화된 HTTP V1 API가 있지만
아직까지는 기기 그룹이나 주제 구독 보다는 멀티캐스트를 많이 사용하므로 기존 HTTP API가 주로 사용된다.  


다음 주제는 안드로이드 메시지 처리에 대해서 알아본다. 


Comments