Dico

[Kotlin] FCM과 Badge - 1. Firebase Cloud Messaging

  • 민갤

Firebase Cloud Messaging 설정 방법은 firebase 문서 가이드에서 알 수 있다.

google-services.json 파일

Firebase 콘솔(console.firebase.google.com)에서

프로젝트를 생성하여 설정에 들어가 (톱니바퀴>프로젝트 설정)

'Android 앱에 Firebase 추가' 를 통해 FCM을 적용할 앱을 등록한다.


Firebase SDK 추가

Project 수준의 build.grade 파일에 Google-service 플러그인과 Google Maven 저장소 추가

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

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

Modul Gradle 파일(app/build.gradle)에 Firebase SDK 라이브러리 추가 및 하단에 플러그인 사용 설정.

설정이 끝나면 동기화한다.

apply plugin: 'com.android.application'

android {
  // ...
}

dependencies {
  // ...
  implementation 'com.google.firebase:firebase-core:16.0.6'	// 애널리틱스(기본)
  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 Messaging Service Class 생성

FirebaseMessagingService를 상속받는 클래스를 작성한다.


  • onMessageReceived()

메시지에는 데이터 메시지와 알림 메시지가 있다.

데이터 메시지는 주로 GCM에서 사용되며, 앱의 실행 여부(foreground or background)와 상관없이 처리된다.

알림 메시지는 앱이 실행되고 있을 때(foreground)에만 처리된다.

Firebase 콘솔은 항상 알림 메시지로 메시지를 보낸다.

    override fun onMessageReceived(remoteMessage: RemoteMessage?) {

        // Check if message contains a data payload.
        if (remoteMessage != null) {
            Log.d(TAG, "From: " + remoteMessage.from)

	// 데이터 메시지인 경우
            if (remoteMessage.data.isNotEmpty()) {
                sendNotification(remoteMessage.data)
                Log.d(TAG, "Message data payload: " + remoteMessage.data)
            }

            // 알림 메시지인 경우
            if (remoteMessage.notification != null) {
                val remoteMessageData = mapOf("title" to remoteMessage.notification?.title.toString(), 
                                                            "msg" to remoteMessage.notification?.body.toString())
                sendNotification(remoteMessageData)
                Log.d(TAG, "Message Notification Body: " + remoteMessage.notification?.body)
            }
        }
    }


  • 수신된 메시지를 알림하기
    private fun sendNotification(msgData: Map<String, String>) {
        // RequestCode, Id를 고유값으로 지정하여 알림이 개별 표시되도록 함
        val uniId: Int = (System.currentTimeMillis() / 7).toInt()

        // 일회용 PendingIntent
        // PendingIntent : Intent 의 실행 권한을 외부의 어플리케이션에게 위임한다.
        val intent = Intent(this, MainActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) // Activity Stack 을 경로만 남긴다. A-B-C-D-B => A-B
        val pendingIntent = PendingIntent.getActivity(this, uniId, intent, PendingIntent.FLAG_ONE_SHOT)

        // 알림 채널 이름
        val channelId = getString(R.string.firebase_notification_channel_id)	// Notice
        // 알림 소리
        val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)

        // 알림에 대한 UI 정보와 작업을 지정한다.
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_notify)                      // 아이콘
                .setContentTitle(msgData.getValue("title"))               // 제목
                .setContentText(msgData.getValue("msg"))              // 세부내용
                .setAutoCancel(true)
                .setSound(soundUri)
                .setContentIntent(pendingIntent)                          // 알림 실행 시 Intent

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(channelId, "Notice", NotificationManager.IMPORTANCE_DEFAULT)
            notificationManager.createNotificationChannel(channel)
        }

        // 알림 생성
        notificationManager.notify(uniId, notificationBuilder.build())
    }


  • onNewToken

토큰이 생성될 때마다 호출된다.

이 함수를 오버라이드하여 토큰이 변경될 때마다 특정 작업을 처리하도록 할 수 있다.

    override fun onNewToken(token: String?) {
        Log.d(TAG, "Refreshed Token: $token")

        if (token != null) {
            sendRegistrationToServer(token)
        }
    }

Manifest에 서비스 등록

앱이 실행되어 있지 않을 때 알림 수신, 데이터 메시지 수신 등을 수행할 수 있도록 서비스 확장

        <!-- Firebase Cloud Message -->
        <service android:name=".modul.MyFirebaseMessageService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>