본문 바로가기
안드로이드 코틀린

[Kotlin][Android] FCM 메시지 받기

by teamnova 2022. 1. 11.

안녕하세요. 이번시간에는 FCM을 통해 메시지를 받는 방법에 대해서 포스팅을 작성하고자 합니다.

 

FCM이란?

Firebase 클라우드 메시징(FCM)은 무료로 메시지를 안정적으로 전송할 수 있는 교차 플랫폼 메시징 솔루션입니다. _(공홈)

특징으로는 각 플랫폼 환경별로 개발할 필요가 없이 Push 메시지를 전송할 수 있기 때문입니다.

또한 사용자는 낮은 배터리와 네트워크의 사용만으로도 메세지를 실시간으로 송수신 처리를 할 수 있다는 이점도 있습니다.

FCM 주요 기능

추가적인 FCM의 아키텍처를 확인하고 싶으시다면 아래 글을 확인해보세요.

https://firebase.google.com/docs/cloud-messaging/fcm-architecture?hl=ko 

 

FCM 아키텍처 개요  |  Firebase

Google은 흑인 공동체를 위한 인종적 평등을 추구하기 위해 노력하고 있습니다. 자세히 알아보기 의견 보내기 FCM 아키텍처 개요 FCM은 메시지를 빌드, 전송, 수신하는 다음 구성요소 집합을 사용합

firebase.google.com

 

대략적으로 FCM이 무엇인지 그리고 사용하면 뭐가 좋은지에 대해서 알아보았습니다.

그러면 바로 FCM 구현을 해보도록 하겠습니다.

 

FCM 기능을 사용하기 앞서 해당 앱을 Firebase 프로젝트에 연동해야 하는 과정이 필요합니다. 해당 과정은 다른 블로그에서도 많이 자료가 나와있으니 이번 포스팅에서는 생략하도록 하겠습니다.

 

파이어 베이스 프로젝트에 해당 앱을 연동하고 구글 JSON 파일도 App 폴더에 추가해줬다면 APP Build 단에 아래 의존성을 추가해줍시다.

 

dependencies {
    // Import the BoM for the Firebase platform
    implementation platform('com.google.firebase:firebase-bom:28.4.1')

    // Declare the dependencies for the Firebase Cloud Messaging and Analytics libraries
    // When using the BoM, you don't specify versions in Firebase library dependencies
    implementation 'com.google.firebase:firebase-messaging-ktx'
    implementation 'com.google.firebase:firebase-analytics-ktx'
}

 

그 다음에는 특정 기기에 토큰을 받아 오기 위해서는 아래 코드를 이용해 줍니다.

FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
        Log.w(TAG, "Fetching FCM registration token failed", task.exception)
        return@OnCompleteListener
    }

    // Get new FCM registration token
    val token = task.result

    // Log and toast
    val msg = getString(R.string.msg_token_fmt, token)
    Log.d(TAG, msg)
    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
})

이제 메시지를 수신할 수 있도록 서비스를 등록해주도록 합니다.

 

해당 과정은  FirebaseMessagingService 클래스를 확장하는 service를 추가해주고, 메니페스트에 해당 서비스를 등록해주는 절차로 진행됩니다.

 

저는 FirebaseMessagingService를 상속하는 클래스의 이름을 MyFirebaseMessagingService 으로 했으나 이름은 자유롭게 변경이 가능합니다.

 

class MyFirebaseMessagingService  : FirebaseMessagingService() {

    //메세지를 수신할 때 호출된다.(메세지를 받을때) remoteMessage는 수신한 메세지이다.
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        if (remoteMessage.data.isNotEmpty()) {
            Logger.d("Message data payload: ${remoteMessage.data}")
        }

        var notificationInfo: Map<String, String> = mapOf()
        remoteMessage.notification?.let {
            Logger.d("Message Notification Body: ${it.body}")
            notificationInfo = mapOf(
                "title" to it.title.toString(),
                "body" to it.body.toString()
            )
            sendNotification(notificationInfo)
        }
    }

    private fun scheduleJob() {
        Logger.d("scheduleJob() 실행")

        // [START dispatch_job]
        val work = OneTimeWorkRequest.Builder(MyWorker::class.java).build()
        WorkManager.getInstance(this).beginWith(work).enqueue()
        // [END dispatch_job]
    }

    private fun handleNow() {
        Logger.d("handleNow() 실행")
    }

    override fun onNewToken(token: String) {
        Logger.w(TAG, "Refreshed token: $token")
        sendRegistrationToServer(token)
    }

    private fun sendRegistrationToServer(token: String?) {
        Log.d(TAG, "sendRegistrationTokenToServer($token)")
    }


    private fun sendNotification(messageBody: Map<String, String>) {
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        val pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT)

        val channelId = getString(R.string.default_notification_channel_id)
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)

        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(messageBody["title"])
            .setContentText(messageBody["body"])
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager


        //안드로이드 오레오 알림채널이 필요하기 때문에 넣음.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(channelId,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT)
            notificationManager.createNotificationChannel(channel)
        }

        notificationManager.notify(0, notificationBuilder.build())
    }
}

해당 클래스를 메니페스트에도 추가를 해줍시다.

android:name=".MyFirebaseMessagingService" 에 들어가는 값은 MyFirebaseMessagingService클래스가 존재하는 경로를 적어주시면 됩니다. 만약에 MyFirebaseMessagingService가 service 패키지 안에 있다고 한다면 android:name에는 ".service.MyFirebaseMessagingService"가 됩니다.

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.example.fcm">

     <application
         ...
         <activity android:name=".MainActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />

                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>

         <!-- FCM service 추가 -->
         <service
             android:name=".MyFirebaseMessagingService"
             android:exported="false">
             <intent-filter>
                 <action android:name="com.google.firebase.MESSAGING_EVENT" />
             </intent-filter>
         </service>
     </application>

 </manifest>

추가로 res/values/strings.xml 파일에 아래와 같이 FCM 기본 채널 id를 추가해줘야 합니다.

 <resources>
     <string name="default_notification_channel_id" translatable="false">fcm_default_channel</string>
 </resources>

 

이제 알림 작성기를 통해 FCM 설정이 완료된 Android 클라이언트 앱에 메시지를 보내봅시다.

공홈에 나와 있는 절차

 

코드 중간에 나오는 Logger 라이브러리는 스틱코드를 참고하시면 가져다 쓸 수 있습니다.

https://stickode.tistory.com/275

https://stickode.com/detail.html?no=2559 

참고 

https://firebase.google.com/docs/cloud-messaging/android/receive?hl=ko

https://firebase.google.com/docs/cloud-messaging?hl=ko

https://firebase.google.com/docs/cloud-messaging/android/first-message?hl=ko