FCM == Firebase Cloud Messaging
무료로 안정적으로 메시지를 전송하는 교차 플랫폼 메시징 솔루션
1.FCM SDK 설정
2.클라이언트 앱 개발
3.앱 서버 개발
서버의 역할은 1에서 신뢰할 수 있는 환경으로 파이어베이스로 데이터를 전달해주는 것 2부터는 FCM이 알아서 디바이스로 보내줄 것
안드로이드의 역할은 전송받는 데이터를 잘 받는 것
기존의 google-services관련 의존성과 함께
implementation 'com.google.firebase:firebase-messaging-ktx'
를 추가해준다.
https://firebase.google.com/docs/android/setup?hl=ko
인터넷 및 FirebaseMessagingService를확장하는 서비스를 추가해야 한다.
백그라운드로 앱이 내려갔을 때 수신받기 위해 서비스가 필요하기 때문이다.
<uses-permission android:name="android.permission.INTERNET" />
...
<service
android:name=".java.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko
create될 때 파이어베이스 토큰이 있으면 가져오려고 한다. 이 토큰은 앱이 가지고 있는 토큰이다.
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()
})
서비스에서 토큰 재발급시 전송할 토큰에 대한 서비스 구현
class MyFirebaseMessageService : FirebaseMessagingService() {
// 새로운 토큰이 생성될 때 마다 해당 콜백이 호출된다.
override fun onNewToken(token: String) {
super.onNewToken(token)
Log.d(TAG, "onNewToken: $token")
// 새로운 토큰 수신 시 서버로 전송
MainActivity.uploadToken(token)
}
// Foreground에서 Push Service를 받기 위해 Notification 설정
override fun onMessageReceived(remoteMessage: RemoteMessage) {
}
}
FirebaseMessagingService의 onNewToken을 구현한다
실행 시 위 처럼 토큰을 발급받아온다.
firebase 메시지에서
메시지를 만들기
발급받은 토큰을 여기에 입력을 하고 테스트를 하면
서비스의 onMessageReceived에서 발급받은 remotemessage 로그를 볼 수 있다.
onMessageReceived: com.google.firebase.messaging.RemoteMessage@f200a5f
재미있는 점은 앱이 백그라운드 상태에 있을 때 똑같이 테스트를 해보면
notification이 와있다. 백그라운드일 때 시스템에서 자동으로 푸쉬 메시지를 보내주는 것이다.
override fun onMessageReceived(remoteMessage: RemoteMessage) {
Log.d(TAG, "onMessageReceived: $remoteMessage")
remoteMessage.notification?.apply {
val intent = Intent(this@MyFirebaseMessageService, MainActivity::class.java).apply{
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(this@MyFirebaseMessageService, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val builder = NotificationCompat.Builder(this@MyFirebaseMessageService, MainActivity.channel_id)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle(title)
.setContentText(body)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(101, builder.build())
}
}
받은 remoteMessage를 가지고 title과 body 속성을 가져와서 notification안에 넣어서 푸쉬알림을 만들어줄 수 있다.
액티비티에서는 이 notification을 받을 채널을 만들어줘야 하므로 채널을 생성한다.
@RequiresApi(Build.VERSION_CODES.O)
// Notification 수신을 위한 체널 추가
private fun createNotificationChannel(id: String, name: String) {
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(id, name, importance)
val notificationManager: NotificationManager
= getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
서버에서는 firebase로부터 비공개 키를 받아오고 안드로이드로 부터 앱의 토큰을 받아온다. 이 비공개 키로 파이어베이스가 서버에서 오는 데이터를 믿을 수 있다. 서버는 데이터와 앱의 토큰을 파이어베이스로 보내서 파이어베이스가 앱으로 전송해준다.
https://firebase.google.com/docs/cloud-messaging/android/receive?hl=ko&authuser=0