프로젝트에서 클라이언트 앱에 띄울 알림 기능을 구현해야 해서 FCM 을 처음 사용해보았다.
원하는 기능은 클라이언트 앱에서 특정 이벤트가 발생했을 때 특정 사용자에게 알림을 보내는건데, Firebase Console (GUI)에서 이것저것 해보았지만 해당 기능을 구현하기엔 부족했다.
콘솔 GUI에서 알림을 보내는 기능은 전체 사용자나 특정 그룹 대상으로 공지나 이벤트 등을 알려야 할 때 유용할 것 같다.
공식 문서도 참고해보고 구글링으로 참고를 해보았는데, 공식문서는 뭔가 친절하지는 않고 구글링에서는 내가 구현하는 기능 예시를 찾기 어려웠다.
결과적으로는 공식 문서와 Firebase Github 예시 코드를 참고해서 원하는 기능을 구현할 수 있었다.
어떻게 Spring 서버에서 안드로이드로 알림을 보내는 기능을 구현했는지 정리하고자 글을 써본다.
이 글은 서버에서 보낸 알림 메시지를 안드로이드에서 처리하는 방법에 대한 내용이다.
FCM 메시지 종류
메시지는 알림 메시지, 데이터 메시지의 2가지 종류가 있다.
알림과 데이터 페이로드가 모두 포함된 메시지는 알림 메시지로 분류된다.
다음은 알림 메시지, 데이터 메시지의 예시 형태다.
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}
}
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
},
"data" : {
"Nick" : "Mario",
"Room" : "PortugalVSDenmark"
}
}
}
메시지를 클릭했을 때 보여줄 정보는 사용자에 따라 다르기 때문에 데이터 페이로드를 포함해서 알림 메시지를 사용했다.
데이터는 key, value가 모두 String인 맵으로, key와 value를 지정해서 메시지에 넣어준다.
서버에서 FCM PUSH 메시지를 생성해서 보내기 위해서는 Firebase Console에 프로젝트가 있어야 한다.
클라이언트인 안드로이드에서도 필요하므로 앞으로의 과정을 위해 프로젝트를 생성해주자.
<service
android:name=".api.MessagingService"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
implementation 'com.google.firebase:firebase-messaging-ktx:23.0.0'
implementation 'com.google.firebase:firebase-bom:29.1.0'
implementation 'com.google.firebase:firebase-core:20.1.0'
다음은 FirebaseMessagingService 서비스를 상속받는 서비스에서 구현하는 내용이다.
override fun onNewToken(token: String) {
super.onNewToken(token)
Log.d(TAG, "FCM token created: $token")
// save updated fcm token to server
LoginActivity().saveFCMToken{ result ->
if(result == 200) Log.d("[SAVE FCM TOKEN]", "success")
else Log.d("[SAVE FCM TOKEN]", "failed")
}
}
// get current registered token
fun getToken(): String?{
var token: String? = null
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
token = task.result
Log.d(TAG, "FCM token: $token")
})
return token
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val from = remoteMessage.from!!
val title = remoteMessage.notification?.title
val body = remoteMessage.notification?.body
val requestId = Integer.parseInt(remoteMessage.data["requestId"])
Log.d(TAG, "message received: $remoteMessage")
Log.d(TAG, "from: $from, title: $title, body: $body, data: $requestId")
sendNotification(title!!, body!!, requestId)
}
private fun sendNotification(title: String, text: String, requestId: Int){
val intent = Intent(this, CardRequestActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP and Intent.FLAG_ACTIVITY_NEW_TASK
}
val pendingIntent = PendingIntent.getActivity(this, 0, intent, FLAG_MUTABLE)
val channelId = getString(R.string.notification_channel_id)
val channelName = getString(R.string.default_notification_channel_name)
val defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setAutoCancel(true)
.setSound(defaultSound)
.setContentText(text)
.setContentTitle(title)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.bling)
// create notification channel
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)
notificationManager.createNotificationChannel(channel)
notificationManager.notify(0, notificationBuilder.build())
}
}
메시지를 받으면 messagId를 응답으로 받게 되고,
어느 Firebase projectId에서 왔는지 (from), 알림 제목 (title), 알림 내용 (body), 데이터 내용 (data 맵의 key로 value 가져올 수 있다.)을 확인할 수 있다.
알림 띄워주는 부분에서 알림을 띄워주면 메시지에 있는 token을 가지는 디바이스로 알림이 간다.
[React Native] JSX 구문 (0) | 2021.08.30 |
---|---|
[React Native] React Native Template TypeScript 에러 해결 방법 (0) | 2021.08.29 |
[React Native] React Native with TypeScript : Hello World (0) | 2021.08.24 |
[React Native] React Native로 Android 앱 개발 시작하기 (Windows) (0) | 2021.08.24 |
[React Native] 개발 환경 구축 in Windows (Scoop, Node.js, VSCode, Android Studio) (0) | 2021.08.23 |