본문 바로가기
깡샘 코틀린

21-4 파이어베이스 클라우드 메시징

by 농농씨 2023. 7. 15.

클라우드 메시징의 원리

파이어베이스 클라우드 메시징(Firebase cloud messagind, FCM)은 서버에서 특정 상항이나 데이터가 발생할 때 앱에 알림을 전달하는 기능이다. 예를 들어 은행 계좌에서 이체가 발생할 때를 가정해 보자. 계좌 이체는 서버에서 발생하므로 사용자 폰에 설치된 앱에 이 소식을 알려줘야 한다. 이처럼 서버에서 어떤 상황이 발생할 때 클라이언트(앱)에 데이터를 전달하는 것을 서버 푸시(server push)라고 한다.

 

서버에서 어떤 데이터를 앱에 전달하려면 네트워크로 연결해야 한다. 그런데 서버에서 데이터가 언제 넘어올지 알 수 없으므로 앱에서는 서비스 컴포넌트로 네트워크에 계속 연결돼야 한다. 문제는 백그라운드 제약 때문에 앱이 포그라운드 상황이 아니라면 서버와 연결을 지속할 수 없다는 데 있다. 그리고 만약 한 달에 한두 번만 데이터를 서버에서 앱으로 전달하더라도(이체가 한 달에 한두 번 발생한다고 가정) 앱과 서버가 한 달 내내 연결돼 있어야 하는 효율성 문제가 발생한다.

 

이처럼 서버에서 데이터를 앱에 전달할 때 백그라운드 제약과 효율성을 고려하면 파이어베이스 클라우드 메시징을 생각할 수 있다. 클라우드 메시징서버의 데이터를 앱에 직접 전달하지 않고 FCM 서버를 거쳐 앱에 전달하는 방식이다. 클라우드 메시징을 이용하면 (장점)1️⃣서버와 앱이 네트워크 연결을 지속해서 유지하지 않아도 되며 2️⃣앱이 포그라운드 상황이 아니어도 데이터를 받을 수 있다.

 

클라우드 메시징에서 데이터가 앱에 전달되는 과정은 크게 2단계로 나누어 볼 수 있는데, 1️⃣하나는 FCM 앱을 식별하는 토큰을 얻는 단계이고 2️⃣다른 하나는 서버의 데이터를 앱에 전달하는 단계이다.

 

1단계: 토큰 발급

FCM 서버에 전달된 데이터를 특정 기기의 앱에 전달하려면 클라우드 메시징을 이용하는 앱을 구분하는 식별값이 필요하다. 이 식별값을 토큰(token)이라고 하며 안드로이드 시스템이 FCM 서버에 자동으로 의뢰해서 발급받는다. 토큰을 발급받는 절차를 그림으로 나타내면 다음과 같다.

  1. 클라우드 메시징을 이용하는 앱이 폰에 설치되면 안드로이드 시스템이 자동으로 FCM 서버에 토큰 발급을 요청한다.
  2. FCM 서버에서 앱을 식별하는 토큰을 발급해 에 전달한다.
  3. 앱에 전달된 토큰은 FCM 서버에서 메시지가 발생할 때 사용되므로 서버에 전달한다.
  4. 서버에서 전달받은 토큰을 데이터베이스에 저장한다.

안드로이드 시스템은 토큰을 전달할 목적으로 앱의 서비스를 구동하므로 앱에서는 서비스 컴포넌트로 토큰을 가져와야 한다. 그리고 FCM 서버에서 발급한 토큰으로 앱을 식별하므로 토큰을 서버에 전송하는 로직도 작성해야 한다.

 

2단계: 서버에서 앱으로 데이터 전송

이번에는 서버에서 특정 상황이 발생할 때 데이터를 앱에 전달하는 흐름을 살펴보자.

  1. 서버에서 특정 상황이 발생하면 데이터베이스에 저장해뒀던 토큰을 추출하여 앱을 식별한다.
  2. 서버에서 사용자에게 전달할 메시지와 앱을 식별할 토큰을 FCM 서버에 전달한다.
  3. FCM 서버에서 토큰을 분석해 해당 사용자의 폰에 메시지를 전달한다.

FCM 서버에서 보낸 메시지를 안드로이드 시스템에서 받으면 앱을 실행해 메시지를 전달한다. 이때 앱의 서비스 컴포넌트를 실행해서 전달하므로 앱에는 메시지를 받는 서비스 컴포넌트를 작성해야 한다.

 

 

클라우드 메시징 설정하기

클라우드 메시징을 이용하려면 파이어베이스 콘솔에서 프로젝트를 만들고 앱을 등록해야 한다. 그리고 콘솔에서 제공하는 google-services.json 파일을 모듈의 루트 디렉터리에 복사해야 한다. 즉, 파이어베이스와 앱을 연동해야 하는데 이 과정은 이미 20장에서 살펴봤다.

 

그래들 설정

클라우드 메시징 역시 구글 서비스에서 제공하므로 프로젝트 수준의 그래들 파일에 다음처럼 등록해야 한다. 이는 다른 파이어베이스 서비스와 같다.

// 구글 서비스 등록(프로젝트 수준 그래들)
buildscript {
    (... 생략 ...)
    id 'com.google.gms.google-services' version '4.3.14' apply false
}

그리고 모듈 수준의 그래들 파일에는 플러그인과 클라우드 메시징 관련 라이브러리를 등록해야 한다.

// FCM 관련 라이브러리 등록(모듈 수준 그래들)
plugins {
    (... 생략 ...)
    id 'com.google.gms.google-services' // 플러그인 등록
}
(... 생략 ...)
dependencies {
    (... 생략 ...)
    implementation platform('com.google.firebase:firebase-bom:30.4.1')
    implementation 'com.google.firebase:firebase-messaging-ktx:23.0.8' 
    implementation 'com.google.firebase-analytics-ktx:21.1.1' // 클라우드 메시징 관련 라이브러리들 등록~
}

 

매니페스트 설정

서버에서 FCM 서버에 전달하는 정보는 앱을 식별하는 토큰과 알림, 데이터로 구분된다.

// 매니페스트 설정
{
    notification: { // 알림
        title:'noti title', // 알림은 title과 body 키에 값을 등록해야 함
        body: 'noti body..'
    },
    data: { // 데이터
        title:'data title', // 데이터는 키와 값 모두 개발자가 임의로 구성 가능
        valud: '20'
    }, 
    token:token // 앱을 식별하는 토큰
}

data키와 값 모두 개발자가 임의로 구성할 수 있지만 notificationtitle과 body 키에 값을 등록해야 한다. 이처럼 데이터와 별도로 알림 정보를 두는 이유는 대부분 앱에서 FCM 메시지를 받을 때 사용자에게 알림으로 상황을 알려주므로 알림 구성 정보를 일반 데이터와 구분하기 위해서이다.

물론 앱이 FCM 메시지를 받을 때 꼭 알림을 발생시키거나 notification 정보를 활용해야 하는 것은 아니다. 하지만 notification 정보가 있으면 코드에서 알림을 발생시키지 않아도 자동으로 발생하게 할 수 있다. 그러려면 매니페스트 파일에 다음과 같은 메타 데이터를 설정해 둬야 한다.

// 알림 자동 발생을 위한 메타 데이터 설정
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />    
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@drawable/colorAccent" />    
<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:resource="@drawable/channel" />

 

 

서비스 컴포넌트 작성하기

앱에서 FCM 토큰과 메시지를 받는 서비스를 작성해야 한다. FCM 서비스는 intent-filter의 action 문자열을 com.google.firebase.MESSAGING_EVENT로 선언한다.

// 서비스 등록
<service
    android:name=".fcm.MyFirebaseMessageService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
        // FCM 서비스의 intent-filter의 action 문자열 선언
    </intent-filter>
</service>

그리고 서비스 컴포넌트 클래스는 FirebaseMessagingService를 상속받아서 작성한다. 

// 서비스 코드
class MyFirebaseMessageService : FirebaseMessagingService() {
// 서비스 컴포넌트 클래스를 FirebaseMessagingService를 상속받아서 작성함
    override fun onNewToken(p0: String) { 
    // 서비스에 onNewToken() 함수를 재정의해 놓으면 
    // FCM 서버로부터 토큰이 전달될 때 자동으로 호출되며 매개변숫값이 토큰이다.
        super.onNewToken(p0)
        Log.d("kkang", "fcm token...........$p0")
    }
    override fun onMessageReceived(p0: RemoteMessage) { 
    // 서비스에 onMessageReceived() 함수를 재정의해 놓으면
    // FCM 서버에서 메시지가 전달될 때 자동으로 호출되며 매개변수 객체의 data 프로퍼티로 메시지를 얻을 수 있음
        super.onMessageReceived(p0)
        Log.d("kkang", "fcm message............${p0.data}")
    }
}

서비스에 onNewToken() 함수를 재정의해 놓으면 FCM 서버로부터 토큰이 전달될 때 자동으로 호출되며 매개변숫값이 토큰이다. 그리고 onMessageReceived() 함수를 재정의해 놓으면 FCM 서버에서 메시지가 전달될 때 자동으로 호출되며 매개변수 객체의 data 프로퍼티로 메시지를 얻을 수 있다.

 

공부근황

더보기

이제부터 타이핑은 다 쳐놨고 책공부랑 글수정을 해야하는데... 언제하지... 이럴거면 최신개정판으로 타이핑칠걸 그랬나 생각중이다

실습은... 수요일에 별일 없으면 그때까지 끝낼수있을까나 꺅 벌써 7월 중순이 끝나가고있어! 토익이 껴들 새가 있나..?