달달한 스토리

728x90
반응형

취업을 하고 나서 여러 가지를 배우며 블로그에 정리를 하고 있다.

 

깊게 배우지 못하고, 얕게 배우지만,

 

이 마저도 정리하기 위해 글을 쓴다.

 

부족한 설명은 이해해주길 바란다.

 

FCM이란

 

앱을 사용하는 이용자에게

 

포그라운드나 백그라운드 상태에서

 

(포그라운드 : 앱이 실행중인 상태)

(백그라운드 : 앱이 꺼진상태)

 

원하는 메시지를 전달하기 위한 방법이다.

 

예전에는 GCM이라고 구글에서 제공하는 클라우드 메세징이 있었다는데,

 

이 FCM으로 대체되었다고 한다.

 

FCM에는 두 가지 형태가 있는 데

 

하나는 Notification이고, 하나는 data이다. 

 

두가지 차이점은 아래와 같다.

 

* 전자는 앱이 실행 중(포그라운드) 일 때만 푸시 알림이 오고,
* 후자는 실행 중이거나 백그라운드(앱이 실행 중이지 않을 때) 알림이 온다.
* 보통은 Data를 쓰지 않을 이유가 없기 때문에 특별한 상황이 아닌 이상 Data를 사용하자.

 

그렇다.. 곧 Data를 쓰는 것이 낫겠다.

 

그럼 어디 한번 FCM을 간단히 사용해보자.


사용법

 

파이어 베이스 사이트에서 프로젝트를 만든 뒤에 

 

안드로이드 스튜디오에 돌아와서

 

우선 상단 탭에 Tools ->에서 파이어 베이스를 클릭한다.

 

클라우드 메세징을 클릭하고,

 

Set up Cloud Messaging을 클릭하고, 나와있는 순서대로 

 

진행하면 된다.

 

진행 후에 코드를 기록하겠다.

 

우선 

 

build.gradle이다.

 

파이어 베이스에서 기본 설정으로 넣은 것들도 포함되어 있다.

 

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = "1.4.32"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.1.3"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.5'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

build.gradle(app)이다.

 

apply plugin: 'com.google.gms.google-services'

dependencies {
    implementation platform('com.google.firebase:firebase-bom:26.8.0')
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'com.google.firebase:firebase-messaging-ktx'
    implementation 'com.google.firebase:firebase-analytics-ktx'
    }
    
    

 

위에 라이브러리는 아마 파이어베이스 연동 시에 전부 적어놓았을 것이다.

 

혹시 몰라서 적어둔다.

 

매니페스트도 아래와 같이 작성해준다.

 

<uses-permission android:name="android.permission.INTERNET"/>


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

    </application>

 

아까 안내에 따라 적었을 것이다.

 

그러면 MyFirebaseMessagingService 코틀린 파일을 만들어 보자.

 

class MyFirebaseMessagingService : FirebaseMessagingService() {

    /** 장단점
     * 메세지를 보내면 20초 정도 후에 알람이 도착한다
     * */

    /** FireBase Cloud Messaging(FCM)*/

    /** 알아야 할 사실
     * 푸시 알림으로 보낼 수 있는 메세지는 2가지 유형이 있는데,
     *
     * 하나는 Notification이고, 하나는 Data이다.
     * 전자는 앱이 실행중(포그라운드)일 때만 푸시 알림이 오고,
     * 후자는 실행중이거나 백그라운드(앱이 실행중이지 않을때) 알림이 온다.
     * 보통은 Data를 쓰지 않을 이유가 없기 때문에 특별한 상황이 아닌 이상 Data를 사용하자.
     * */


    //메세지를 수신할 때 호출된다.(메세지를 받을때) remoteMessage는 수신한 메세지이다.
    override fun onMessageReceived(remoteMessage: RemoteMessage) {

        Log.d(TAG, "From: ${remoteMessage.from}")


        //메시지에 데이터 페이로드가 포함되어 있는지 확인한다. 여기서 페이로드란 전송된 데이터를 의한다.
        //데이터 값이 있는지 없는 지 확인 할때 쓰인다.
        if (remoteMessage.data.isNotEmpty()) {
            Log.d(TAG, "Message data payload: ${remoteMessage.data}")
            if (true) {
                //데이터를 처리하는데 10초 이상이 걸리면 workManager를 사용한다.
                scheduleJob()
            } else {
                //10초이내에 시작하면 아래 메서드를 실행한다.
                handleNow()
            }
        }

        //메세지에 알림 페이로드가 포함되어 있는지 확인한다.
        remoteMessage.notification?.let {
            Log.d(TAG, "Message Notification Body: ${it.body}")
        }
    }

    //FirebaseInstanceIdService는 이제 사라짐. 이제 이걸 사용한다.
    //FCM 등록 토큰이 업데이트되면 호출된다.
    //토큰이 처음 생성될때 여기에서 토큰을 검색할 수 있다.
    override fun onNewToken(token: String) {
        Log.d(TAG, "Refreshed token: $token")

        //이 앱 인스턴스에 메시지를 보내려는 경우나 서버 측에서 이 앱 구독을 관리한다면,
        //FCM 등록 토큰을 앱 서버에 추가합니다.

        sendRegistrationToServer(token)
    }

    //메세지 페이로드가 있을 때 실행되는 메서드(10초 이상 걸릴 떄 호출 된다)
    //WorkManager를 사용하여 비동기 작업을 예약한다.
    private fun scheduleJob() {
        // [START dispatch_job]
        val work = OneTimeWorkRequest.Builder(MyWorker::class.java).build()
        WorkManager.getInstance(this).beginWith(work).enqueue()
        // [END dispatch_job]
    }

    //메세지 페이로드가 있을 때 실행되는 메서드(10초 이내로 걸릴 때 호출된다)
    //BroadcastReceivers에 할당 된 시간을 처리합니다.
    private fun handleNow() {
        Log.d(TAG, "Short lived task is done.")
    }

    //타사 서비에 토큰을 유지해주는 메서드입니다.
    //사용자의 FCM등록 토큰을 서버 측 계정에 연결하려면 이 방법을 사용합니다.
    //응용 프로그램에서 유지 관리를 합니다.
    //파라미터에 들어있는 토큰은 새로운 토큰입니다.
    private fun sendRegistrationToServer(token: String?) {
        //이 메서드를 구현하여 앱 서버에 토큰을 보냅니다.
        Log.d(TAG, "sendRegistrationTokenToServer($token)")
    }


    //수신 된 FCM 메시지를 포함하는 간단한 알림을 만들고 표시합니다.
    //파라미터에 있는 messageBody에는 FCM 메세지 본문이 담겨져 있습니다.
    private fun sendNotification(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 = getString(R.string.default_notification_channel_id)
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.sooyeol)
                .setContentTitle(getString(R.string.fcm_message))
                .setContentText(messageBody)
                .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())
    }

    companion object {

        private const val TAG = "MyFirebaseMsgService"
    }
}

코드와 설명은 공식문서를 통해 정리해서 적어 두었다.

 

각 메서드 별로 메시지를 수신했을 때 어떤 식으로 메서드가 실행되는지 정리를 해보았다.

 

위 코드에서 말하는 페이로드는 전달받은 데이터를 말한다.

 

그리고 페이로드를 받아올 때, 10초 이상에 시간이 걸리면 

 

장기 실행 작업에 추가하기 위한 클래스를 만들어야 한다.

 

아래와 같이 만들어 주면 될 것이다.

 

class MyWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {

    override fun doWork(): ListenableWorker.Result {
        Log.d(TAG, "Performing long running task in scheduled job")
        //여기에 장기실행작업을 추가합니다.
        return ListenableWorker.Result.success()
    }

    companion object {
        private val TAG = "MyWorker"
    }
}

 

그러고 나서 메인 액티비티에 등록된 토큰을 가져오는 메서드를 넣어주면 끝이 난다.

 

class MainActivity : AppCompatActivity() {

    val TAG : String = "안녕"

    @SuppressLint("StringFormatInvalid")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //메인 액티비티에서 등록 토큰 가져오기
        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()
        })


    }
}

이렇게 하고 나서 다시 파이어 베이스로 돌아가 보자.

 

왼쪽 탭에 클라우드 메세징 탭을 누르고 , 앱에 보낼 메시지를 적어주고,

 

시간을 입력하면 위와 같이 완료가 되었다고 뜰 것이다.

 

그러면 기기에 따라서 시간은 다르지만, (나 같은 경우는 20초 후에 메시지가 왔다.)

 

아래와 같이 메시지가 온 것을 확인할 수 있을 것이다.

 

이런 식으로 메시지가 온 것을 확인할 수 있다.

 

FCM 끝.

728x90
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading