안드로이드/앱개발(Android)

(Android) 파이어베이스 Notification 알림 앱

김염인 2022. 1. 28. 17:35

 

⚠️ 주의사항

Firebase 프로젝트 에서 다운받은 google-services.json 파일을 추가해야합니다.

목차

  1. 인트로, 프로젝트 셋업
  2. 기본 UI 구성하기
  3. Cloud Messaging 소개
  4. Cloud Messaging 구성하기
  5. Cloud Messaging 연동하기
  6. Notification구현하기 - 1
  7. Notification구현하기 - 2

결과화면

 


1) 파이어베이스 코틀린 연동

Firebase란 구글에서 인수한 'Firebase'에서 만든 개발 플랫폼이다.

푸시 알림을 보내거나, 데이터를 서버에 저장하거나, 계정을 이용해 로그인하는 등의 작업을

아주 쉽고 편리하게 사용할 수 있게 도와주는 녀석이다.

안드로이드뿐만 아니라 IOS도 사용이 가능하니 사용 방법을 익혀두면 아주 좋다.

무료로 사용 가능하지만 일정량 이상 사용하기 위해서는 요금제에 가입해야 한다.

 

파이어베이스를 코틀린에 연동을 하기 위해서는 FireBase에 접속하여 로그인 후 Console로 이동한다.

그 이후 프로젝트 추가를 하여 원하는 프로젝트 Name을 넣어준다. 프로젝트 생성 중 받은 google-services.json 파일을 Project의 App 수준 폴더에 넣어준다. 그리고 프로젝트 수준의 build.gradle에

buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.3"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
        classpath 'com.google.gms:google-services:4.3.10'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

해당 dependencies와 google() mavenCentral(), classpath등을 추가 해 파이어베이스를 사용할 수 있도록 만들어 준다.

app 수준의 build.gradle()은 아래와 같이 설정해준다.

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'com.google.gms.google-services'
}

최상위 plugins에 'com.google....' 과 같은 id 형식으로 추가해주고 맨 아래 dependences에 자기가 firebase에 이용할 기능을 추가하는 형식으로 넣어주면 된다. 여기서 나는 아래와같이 추가해주었다.

    implementation platform('com.google.firebase:firebase-bom:29.0.3')
    implementation 'com.google.firebase:firebase-messaging-ktx'
    implementation 'com.google.firebase:firebase-analytics-ktx'

}

파이어베이스 메시징 기능과 가장 기초적인 firebase-bom기능을 추가해주었고 마지막 간단하게 toyProject로 진행할 앱에서 analytics는 있어도 되고 없어도 되는 기능이다.

 

그러면 이제 파이어베이스의 연동기능은 마무리 됐다.

 

2) 파이어베이스 메시징 이용하기

 

푸시 알림으로 보낼 수 있는 메시지는 2가지 유형이 있다.

Notification은 앱이 포그라운드일 때 (앱이 실행 중일 때)만 푸시 알림이 오고

Data는 포그라운드/백그라운드 상관없이 푸시알림이 도착한다.

(Notification과 Data를 같이 쓰는 경우도 있지만 논외로 하겠다)

 

이 말만 들어보면 Data를 쓰지 않을 이유가 없을 것 같다.

실제로 어느 블로그를 보니 회사에서도 이유 불문하고 Data를 쓴다는 글을 보았는데

이유도 없이 Notification이 있을 것 같진 않다.

 

공식문서 : https://firebase.google.com/docs/cloud-messaging/concept-options?hl=ko 에서 확인 가능하다.

 

앱의 매니페스트에 다음을 추가해야한다.

  • FirebaseMessagingService를 확장하는 서비스를 추가합니다. 백그라운드에서 앱의 알림을 수신하는 것 외에 다른 방식으로 메시지를 처리하려는 경우에 필요합니다. 포그라운드 앱의 알림 수신, 데이터 페이로드 수신, 업스트림 메시지 전송 등을 수행하려면 이 서비스를 확장해야 합니다.
<service android:name=".MyFirebaseMessagingService"
    android:exported="false"> // 사진 공유 시 여러 앱들이 뜨는 것처럼 그런 기능을 막는다는 의미 !
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"></action>
    </intent-filter>
</service>

 

onNewToken 토큰을 생성하는 메서드이다.

 

onMessageReceived 메시지를 수신하는 메서드이다.

메시지에 제목이나 내용이 들어있는지 검사하고 문제가 없다면 sendNotification을 호출한다.

 

sendNotification 알림을 생성하는 메서드이다. 아이콘은 어떻게 할 건지, 알림 소리는 어떻게 할건지 등

이런 세세한 옵션을 설정하고 알림을 생성하면 비로소 푸시 알림이 뜨게 되는 것이다. 여기서는 사용하지 않는다.

 

Android 8.0(API 수준 26)부터는 모든 알림을 채널에 할당해야 합니다. 채널마다 채널의 모든 알림에 적용되는 시각적/음향적 동작을 설정할 수 있습니다. 그런 다음 사용자는 이 설정을 변경하고 앱에서 차단하거나 표시해야 하는 알림 채널을 결정할 수 있습니다. 

 

3) FirebaseMessagingService 만들기

먼저 알림 채널을 만들려면 다음 단계를 따라야한다.

  1. 고유한 채널 ID, 사용자가 볼 수 있는 이름, 중요도 수준을 사용하여 NotificationChannel 객체를 구성합니다.
  2. 선택적으로 setDescription()을 사용하여 시스템 설정에서 사용자에게 표시되는 설명을 지정합니다.
  3. 알림 채널을 createNotificationChannel()에 전달하여 등록합니다.
private fun createNotificationChannel() { // channel 생성하는 과정 !!~!
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            CHANNEL_ID,
            CHANNEL_NAME,
            NotificationManager.IMPORTANCE_DEFAULT
        )
        channel.description = CHANNEL_DESCRIPTION

        (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
            .createNotificationChannel(channel)
    }
}

위와같이 순서에 따라 정의를 해주면 이렇게 채널이 생성 된다. 그리고 생성된 채널에 의해 알림을 끄고 킬 수 있다.

이번앱에서는 notification을 

send를 통해 api 형식으로 전송 할 수있다.
이런식으로 json 형식으로 cutom된 타입의 노티피케이션을 전송 !

package com.example.aop_part3_chaptor01

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context
import android.content.Intent
import android.os.Build
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

open class MyFirebaseMessagingService : FirebaseMessagingService() {
    override fun onNewToken(p0: String) {
        super.onNewToken(p0)
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)

        createNotificationChannel()

        val type = remoteMessage.data["type"]?.let {
            NotificationType.valueOf(it)
        }
        val title = remoteMessage.data["title"]
        val message = remoteMessage.data["message"]

        type ?: return


        NotificationManagerCompat.from(this).notify(type.id, createNotification(type, title, message))
    }

    private fun createNotificationChannel() { // channel 생성하는 과정 !!~!
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                CHANNEL_NAME,
                NotificationManager.IMPORTANCE_DEFAULT
            )
            channel.description = CHANNEL_DESCRIPTION

            (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
                .createNotificationChannel(channel)
        }
    }

    private fun createNotification(
        type: NotificationType,
        title: String?,
        message: String?
    ): Notification {
        val intent = Intent(this,MainActivity::class.java).apply{
            putExtra("NotificationType", "${type.title} 타입")
            addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) // Stack 구조에서 TOP에는 Single 한개만 있는 것 화면이 한개 밖에 없음
            // B에서 B화면 으로 이동하는 경우 기존화면을 갱신하면
        }

        val pendingIntent = PendingIntent.getActivity(this,type.id,intent,FLAG_UPDATE_CURRENT)
        // pendingIntent란 ? 누군가한테 인텐트를 다룰 수 있는 권한을 준다고 생각!

        val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true) // 클릭했을때 자동으로 Notification이 닫힌다.

        when (type) {
            NotificationType.NORMAL -> Unit
            NotificationType.EXPENDABLE -> {
                notificationBuilder.setStyle(
                    NotificationCompat.BigTextStyle()
                        .bigText(
                            "😁😒😊☺️😘😭😭☺️😳" +
                                    "😔😉😉😌😉😌🙈🙈👀" +
                                    "🙈👀😜😑😜😑😜😜😋😄😄" +
                                    "😔😉😉😌😉😌🙈🙈👀" +
                                    "🙈👀😜😑😜😑😜😜😋😄😄" +
                                    "🙈👀😜😑😜😑😜😜😋😄😄"
                        )
                )
            }
            NotificationType.CUSTOM -> {
                notificationBuilder.setStyle(NotificationCompat.DecoratedCustomViewStyle())
                    .setCustomContentView(
                        RemoteViews(
                            packageName,
                            R.layout.view_custom_notification
                        ).apply {
                            setTextViewText(R.id.title,title)
                            setTextViewText(R.id.message, message)
                        }
                    )
            }
        }

        return notificationBuilder.build()
    }

    companion object {
        private const val CHANNEL_NAME = "Emogi Party"
        private const val CHANNEL_DESCRIPTION = "Emogi Party를 위한 채널"
        private const val CHANNEL_ID = "Channel Id"
    }
}

최종코드,

'안드로이드 > 앱개발(Android)' 카테고리의 다른 글

(코틀린 kotlin) 알람 앱  (0) 2022.02.11
(코틀린 kotlin) 명언앱  (0) 2022.02.05
(코틀린 kotlin) 웹뷰 앱  (0) 2022.01.25
(코틀린 kotlin) 녹음기 앱  (0) 2022.01.24
(코틀린 kotlin) 타이머 앱  (0) 2022.01.22