본문 바로가기
카카오 REST API & SDK/푸시 알림

android(kotlin) + fcm + Postman 예제 - 푸시 알림

by kakao-TAM 2021. 3. 30.

카카오 푸시 알림 가이드 : developers.kakao.com/docs/latest/ko/push/common

 

1. Firebase에 가입하고 Project를 추가합니다. https://firebase.google.com/

next> next> next>

2. 구글 앱스토어(플레이 콘솔)에 등록한 앱 패키지 명과 이름을 등록합니다.

3. google-services.json 파일을 다운받아 프로젝트 app 폴더에 넣습니다.

4. build.gradle(Project)에 class path를 추가합니다.

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = "1.4.21"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.1.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.4'
        // 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
}

5. build.gradle(Module)에 plugin과 implementation을 추가합니다.

plugins {
   ...
    id 'com.google.gms.google-services'
}

...
dependencies {
...

    implementation platform('com.google.firebase:firebase-bom:33.0.0')
    implementation 'com.google.firebase:firebase-auth-ktx:23.0.0'
    implementation 'com.google.firebase:firebase-analytics-ktx:22.0.0'
    implementation 'com.google.firebase:firebase-messaging:24.0.0'
}

* 모든 설정을 마치고 Curl 명령으로 아래와 같이 푸시알림 발송 성공 응답 받았지만 실제로 알림이 오지 않는 경우 firebase 라이브러리 버전 문제이거나 사용자 기기 앱 푸시알림 권한 설정 문제일 수 있음 

{"multicast_id":7886073677899122950,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1715656525167464%c22cb0a5c22cb0a5"}]}

- firebase 라이브러리 버전은 https://firebase.google.com/support/release-notes/android 에서 확인합니다.

- 사용자 기기 앱 푸시알림 권한 설정은 "6. AndroidManifest.xml : service 추가"의 user-permission과 "9. 사용자기기에 설치된앱 권한 설정"을 참고합니다. 

 

6. AndroidManifest.xml : service 추가

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.googsu.myapplication">
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_googsu"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_googsu_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service
            android:name=".MyFirebaseMessagingService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
    </application>
</manifest>

7. MyFirebaseMessagingService 클래스 추가

package com.googsu.myapplication

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.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 or PendingIntent.FLAG_IMMUTABLE)

        val channelId = "my_channel"
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_googsu_background)
            .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())
    }

}

8. 푸시 알림을 보내기 위해서는 받는 장치의 토큰을 알아야합니다. MainActivity나 GlobalApplication 클래스에 토큰확인을 위해 onCreate 함수 안에 아래 코드를 넣습니다.

        FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
            if (!task.isSuccessful) {
                Log.w("FCM", "Fetching FCM registration token failed", task.exception)
                return@OnCompleteListener
            }

            // Get new FCM registration token
            val token = task.result

            // Log and toast
            val msg = token.toString()
            Log.d("FCM", msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        })

9. 사용자기기에 설치된앱 권한 설정

    // Declare the launcher at the top of your Activity/Fragment:
    override fun onCreate(savedInstanceState: Bundle?) {
       .... 생략 ....
       askNotificationPermission()
    }

    private val requestPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestPermission(),
    ) { isGranted: Boolean ->
        if (isGranted) {
            // FCM SDK (and your app) can post notifications.
        } else {
            // TODO: Inform user that that your app will not show notifications.
        }
    }

    private fun askNotificationPermission() {
        // This is only necessary for API level >= 33 (TIRAMISU)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
                PackageManager.PERMISSION_GRANTED
            ) {
                // FCM SDK (and your app) can post notifications.
            } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
                // TODO: display an educational UI explaining to the user the features that will be enabled
                //       by them granting the POST_NOTIFICATION permission. This UI should provide the user
                //       "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission.
                //       If the user selects "No thanks," allow the user to continue without notifications.
            } else {
                // Directly ask for the permission
                requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
            }
        }
    }

 

10. 에뮬레이터를 실행한 후, Logcat에서 "FCM"으로 토큰을 검색. (호출할때 써야하니 일단 보관)

11. 다시 firebase에 등록한 프로젝트로 돌아가서 서버키를 복사

12. Command 창이나 Bash 명령창에서 curl로 호출

curl -X POST --header "Authorization: key=10번에서 받은 서버키" --header "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d '{"to" : "11번에서 저장한 토큰",  "priority" : "high",  "notification" : {    "body" : "바디 내용",    "title" : "푸시 알림"  },  "data" : {    "title" : "푸시",    "message" : "메세지"  }}'

13. 카카오 푸시 알림 사용하기

[내 애플리케이션] > [제품 설정] > [푸시 알림] 메뉴에서 기능을 활성화하고 위 10번에서 복사한 서버 키를 FCM key에 등록

 

토큰등록

curl -v -X POST "https://kapi.kakao.com/v2/push/register" \
  -H "Authorization: KakaoAK {APP_ADMIN_KEY}" \
  -d "uuid=1234" \
  -d "device_id=0f365b39-c33d-39be-bdfc-74aaf5534470&push_type=fcm" \
  -d "push_token=APA91bEZ3fjwrKV2mxAFvZMC960zKBWBVffLErwZgFzsFnzzsxgi5lSQlq3zvzObZBe4OnbwkTZfMqV7_a6fF0AJNgUjt5Scpo2BTaHyLVlK54QmwIQBahUwJprKjj0YvF_rh8l7CTvl6TRxqlqO_NIwaoAcI0MssA"

* push_token에는 위 9번에서 logcat에서 얻은 토큰 세팅 

* device_id 

FirebaseInstallations.getInstance().getId()
        .addOnCompleteListener(new OnCompleteListener<String>() {
    @Override
    public void onComplete(@NonNull Task<String> task) {
        if (task.isSuccessful()) {
            Log.d("Installations", "Installation ID: " + task.getResult());
        } else {
            Log.e("Installations", "Unable to get Installation ID");
        }
    }
});

* -1 : 응답은 정상 등록

토큰조회

curl -v -X POST "https://kapi.kakao.com/v2/push/tokens" \
  -H "Authorization: KakaoAK {APP_ADMIN_KEY}" \
  -d 'uuids=["1234", "5678"]'

푸시알림 보내기 

* 토큰등록을 했다면 토큰 만료전 재발송 가능

curl -v -X POST "https://kapi.kakao.com/v2/push/send" \
  -H "Authorization: KakaoAK {APP_ADMIN_KEY}" \
  -d 'uuids=["1234", "5678"]'  \
  --data-urlencode 'push_message={
  "for_fcm":{
     "notification" : {    "body" : "바디 내용",    "title" : "푸시 알림"  }
  }
}'

 

댓글