반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

코딩하기 좋은날

안드로이드 FCM 송/수신 (Kotlin, PHP, Firebase) 본문

Android

안드로이드 FCM 송/수신 (Kotlin, PHP, Firebase)

huiung 2020. 9. 6. 01:40
반응형

원격으로 알림을 보낼 때 많이 쓰이는 FCM에 대해서 한번 알아 보겠습니다.

 

안드로이드 스튜디오의 Tools -> firebase 를 클릭하면 아래와 같은 창이 나옵니다.

 

1번과 2번을 각각 눌러서 dependency를 추가하고 프로젝트를 등록하고 google-services.json 파일이 추가되면 FCM을 수신 받을 수 있는 상태가 됩니다. 

아 그리고 firebase-analytics는 자동으로 추가가 되지 않는데 이걸 추가안하면 FCM이 바로바로 오지 않는 것 같습니다. 실제로 FCM의 최적화를 위해 추가시키라는 글이 웹상에서 나오는 걸로 알고 있는데 추가시켜주면 보내자마자 바로 수신이 됩니다! 

 

기본적으로 이렇게만 세팅을 해주면 FCM은 다음과 같은 상황에서 수신이 가능합니다.

 

1. 앱이 완전히 꺼져있는 상태

2. 앱이 백그라운드에 존재하는 상태

 

따라서 앱이 포그라운드에 있을 때 FCM 수신을 위해서는 FirebaseMessagingService를 상속하는 클래스를 생성해야 합니다. 위 사진의 3번 항목에 자세히 나와 있습니다. 여러가지 함수들이 존재하는데

우선은 메시지를 수신 했을 때 이를 처리하는 onMessageReceived 함수가 있습니다. Message를 수신하여 원하는 내용을 얻어 낸뒤 Notification을 보내 주는 형태로 사용하면 될 것 같습니다.

 

그 아래에는 onNewToken 이라는 함수가 있습니다. 원격에서 FCM을 보내기 위해서는 이 Token값이 필요한데 이러한 Token 값은 앱이 새로 설치되거나 하는 상황에서 생성이 되게 됩니다. 이때 해당 함수가 호출되고 예를들어 토큰 값이 새로 생성되거나 변경 될 때 이 함수내부에서 서버로 토큰값을 전송해준다거나 로컬에서 이를 저장하는 작업을 할 수 있습니다.

 

아래는 제가 사용한 코드입니다.

 

package com.example.lol_notification_project.service

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.media.RingtoneManager
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import com.example.lol_notification_project.R
import com.example.lol_notification_project.view.MainActivity
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class MyFirebaseMessagingService : FirebaseMessagingService() {

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        Log.d("mytag", "From: ${remoteMessage.from}")
        remoteMessage.notification?.let {
            Log.d("mytag", "Message Notification Body: ${it.body}")
            it.title?.let { it1 -> it.body?.let { it2 -> sendNotification(it1, it2) } }
        }


    }

    override fun onNewToken(token: String) {
        Log.d("mytag", "Refreshed token: $token")
        super.onNewToken(token)

    }

    private fun sendNotification(title:String ,messageBody: 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 = "my_channel"
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.icon)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)

        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,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT)
            notificationManager.createNotificationChannel(channel)
        }

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
    }

}

아래는 서버에서 토큰 값을 이용하여 FCM 송신을 테스트 해보는 PHP 코드입니다. 로컬에서 실행 시키니 알림이 바로 오는 것을 확인했습니다. 이전에 만든 롤알리미 앱에 활용을 한다면 각 토큰(유저)가 추적을 원하는 소환사들을 전송 받아 DB에 저장 해놓고 주기적으로 Api 호출을 하며 해당 유저가 게임을 하고 있다면 해당 유저의 토큰값을 이용해 알림을 발송해주는 식으로 사용 할 수 있을 것 같습니다.

<html>
<head>
</head>

<body>
    
    <?php
    //fcm 전송 함수 token 값 array
    
    $title = '알림';
    $message = '게임시작!';
    $tokens = '토큰 값';
        
    $googlekey = '서버 key 값';
        $url = 'https://fcm.googleapis.com/fcm/send';
        $msg = array(
                'title' => $title,
                'body' => $message,
                'message' => $message                
        );


    $fields = array(
                'registration_ids' => array($tokens),
                'notification' => array ("title" => $title, "body" => $message),
                'data' => $msg
    );

    $headers = array(
                'Authorization:key='.$googlekey,
                'Content-Type: application/json'
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
    $result = curl_exec($ch);    
    if($result === FALSE) {
        echo "Curl failed:" .curl_error($ch);        
    }
    else {
        echo "success:" .curl_error($ch);        
    }
    curl_close($ch);    

    ?>
    </body>
</html>
반응형