Firebase - 푸시알림 보내기 (2)
앱을 실행중일때 푸시알람을 받는 방법에대해서 알아보겠습니다.
푸시 알림을 보내기 위해서는 토큰이 있어야 합니다.
또한 안드로이드 푸시를 사용하기 위해서는 라이브러리가 있어야 합니다.
안드로이드 라이브러리를 build.gradle(module)의 dependencies에 추가합니다.
| //firebase 푸시알람 라이브러리 implementation 'com.google.firebase:firebase-messaging:17.3.4' | cs
|
그리고 푸시아이콘을 drawable에 등록해줍니다(ic_push로 등록)
그리고 manifest에 아래 내용을 추가합니다.
Manifest 설정
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
.....
<!-- - 안드로이드 8.0 이상 푸시 처리 추가 코드 -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_push"/>
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent"/>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
<service
android:name=".fcm.FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".util.MyJobService"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>
</application>
</manifest>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_push"/>
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent"/>
푸시알람이 왔을 때 기본 아이콘 및 색상을 설정하는 메타데이터입니다.
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
(Optional) Android 8.0(API 수준 26) 이상부터는 알림 채널이 지원 및 권장됩니다. FCM은 기본적인 설정과 함께 기본 알림 채널을 제공합니다. 기본 채널을 직접 만들어 사용하려면 아래와 같이 default_notification_channel_id
를 알림 채널 객체의 ID로 설정합니다. 수신 메시지에 명시적으로 설정된 알림 채널이 없으면 FCM에서 항상 이 값을 사용합니다.
<service
android:name=".fcm.FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
FirebaseMessagingService는 백그라운드에서 앱의 알람을 수신하는 것 외에 다른 방식으로 메시지를 처리하려는 경우에 필요합니다. 포그라운드 앱의 알림 수신, 데이터 페이로드 수신,
업스트림 메시지 전송 등을 수행하려면 이 서비스를 확장해야 합니다.
<service
android:name=".util.MyJobService"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>
이 서비스는 Handler응용 프로그램의 주 스레드 에서 실행중인 각 수신 작업을 실행합니다.
즉, 실행 논리를 선택한 스레드 / 처리기 / 다른 스레드로 오프로드 해야합니다.
AsyncTask . 그렇게하지 않으면 JobManager에서 향후 콜백을 차단하게됩니다.
구체적으로 onStopJob(android.app.job.JobParameters)일정 요구 사항이 더 이상 충족되지 않는다는 것을 알리기위한 것입니다.
class FirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String?) { //토큰이 변경되었을때 호출
super.onNewToken(token)
//v17.0.0 이후부터는 onTokenRefresh()-depriciated
//var pushToken = FirebaseInstanceId.getInstance().token
var uid = FirebaseAuth.getInstance().currentUser!!.uid
var map = mutableMapOf<String, Any>()
map["pushtoken"] = token!!
FirebaseFirestore.getInstance().collection("pushtokens").document(uid!!).set(map)
//서버로 바뀐토큰 전송
sendRegistrationToServer(token)
}
private fun sendRegistrationToServer(token: String?) {
//서버로 바뀐 토큰 전송할 메소드 작성하는 부분
}
override fun onMessageReceived(remoteMessage: RemoteMessage?) { //푸시알림을 받았을때 호출되는 메소드
Log.d(TAG, "From: ${remoteMessage?.from}")
remoteMessage?.data?.isNotEmpty()?.let {
Log.d(TAG, "Message data payload: " + remoteMessage.data)
if (true) {/* 장기 실행 작업으로 데이터를 처리해야하는지 확인*/
//장기 실행 작업 (10 초 이상)의 경우 Firebase Job Dispatcher를 사용하십시오
scheduleJob()
} else {
//10 초 이내에 메시지 처리
handleNow()
}
}
// 메시지에 알림 페이로드가 포함되어 있는지 확인하십시오.
remoteMessage?.notification?.let {
Log.d(TAG, "Message Notification Body: ${it.body}")
sendNotification(it.body!!)
}
}
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, 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.mipmap.ic_launcher)
.setContentTitle("Beomstargram.")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// android Oreo 알림 채널이 필요합니다
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 */, notificationBuilder.build())
}
private fun scheduleJob() { //장기작업인지(10초이상)일때 처리하는 메소드
val dispatcher = FirebaseJobDispatcher(GooglePlayDriver(this))
val myJob = dispatcher.newJobBuilder()
.setService(MyJobService::class.java)
.setTag("my-job-tag")
.build()
dispatcher.schedule(myJob)
}
private fun handleNow() {
Log.d(TAG, "Short lived task is done.")
}
companion object {
private val TAG = "FirebaseMessageService"
}
}
onNewToken() 메소드
override fun onNewToken(token: String?) { //토큰이 변경되었을때 호출
super.onNewToken(token)
//v17.0.0 이후부터는 onTokenRefresh()-depriciated
//var pushToken = FirebaseInstanceId.getInstance().token
var uid = FirebaseAuth.getInstance().currentUser!!.uid
var map = mutableMapOf<String, Any>()
map["pushtoken"] = token!!
FirebaseFirestore.getInstance().collection("pushtokens").document(uid!!).set(map)
//서버로 바뀐토큰 전송
sendRegistrationToServer(token)
}
여기서 FirebaseStore에 토큰을 저장합니다 .
onNewToken메소드는 발급받았던 토큰이 새로 변경될때 호출됩니다.
onMessageRecived() 메소드
override fun onMessageReceived(remoteMessage: RemoteMessage?) { //푸시알림을 받았을때 호출되는 메소드
Log.d(TAG, "From: ${remoteMessage?.from}")
remoteMessage?.data?.isNotEmpty()?.let {
Log.d(TAG, "Message data payload: " + remoteMessage.data)
if (true) {/* 장기 실행 작업으로 데이터를 처리해야하는지 확인*/
//장기 실행 작업 (10 초 이상)의 경우 Firebase Job Dispatcher를 사용하십시오
scheduleJob()
} else {
//10 초 이내에 메시지 처리
handleNow()
}
}
// 메시지에 알림 페이로드가 포함되어 있는지 확인하십시오.
remoteMessage?.notification?.let {
Log.d(TAG, "Message Notification Body: ${it.body}")
sendNotification(it.body!!)
}
}
푸시알림을 받았을때 호출되는 메소드입니다.
장기작업일때 schedulejob() 메소드를 호출합니다.
10초이내 메시지 처리가 가능할 경우 handleNow() 를 호출합니다.
sendNotification(body)메소드로 메시지의 body를 넘겨줍니다.
sendNotification() 메소드
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, 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.mipmap.ic_launcher)
.setContentTitle("Beomstargram.")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// android Oreo 알림 채널이 필요합니다
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 */, notificationBuilder.build())
}
푸시알람을 만들어주는 메소드입니다.
PendingIntent에 알람을 받을시 넘어갈 화면을 지정합니다.
channelId 는 수신 메시지에 명시적으로 설정된 알림 채널이 없다면 이값이 쓰입니다.
넘겨받은 body로 notificationCompat.Builder로 알림을 만들어줍니다.
scheduleJob(), handleNow() 메소드
private fun scheduleJob() { //장기작업인지(10초이상)일때 처리하는 메소드
val dispatcher = FirebaseJobDispatcher(GooglePlayDriver(this))
val myJob = dispatcher.newJobBuilder()
.setService(MyJobService::class.java)
.setTag("my-job-tag")
.build()
dispatcher.schedule(myJob)
}
private fun handleNow() {
Log.d(TAG, "Short lived task is done.")
}
장기 작업(10초이상)일때는 scheduleJob() 메소드
그 이하로 처리가능한 작업일때는 handleNow()에 추가적으로 처리할 내용을 작성해줍니다.
MyJobService 클래스
class MyJobService : JobService() {
/*
* 이 서비스는 Handler응용 프로그램의 주 스레드 에서 실행중인 각 수신 작업을 실행합니다.
* 즉, 실행 논리를 선택한 스레드 / 처리기 / 다른 스레드로 오프로드 해야합니다AsyncTask . 그렇게하지 않으면 JobManager에서 향후 콜백을 차단하게됩니다.
* 구체적으로 onStopJob(android.app.job.JobParameters)일정 요구 사항이 더 이상 충족되지 않는다는 것을 알리기위한 것입니다.*/
override fun onStartJob(jobParameters: JobParameters): Boolean {
//작업이 실행되기 시작했음을 나타 내기 위해 호출됩니다.
// TODO(developer): add long running task here.
return false
}
override fun onStopJob(jobParameters: JobParameters): Boolean {
return false
//이 메서드는 호출 기회가 있기 전에도 작업 실행을 중지해야한다고 시스템에서 결정한 경우 호출 jobFinished(JobParameters, boolean)됩니다.
}
companion object {
private const val TAG = "MyJobService"
}
}
이 서비스는 Handler응용 프로그램의 주 스레드 에서 실행중인 각 수신 작업을 실행합니다.
즉, 실행 논리를 선택한 스레드 / 처리기 / 다른 스레드로 오프로드 해야합니다.
AsyncTask . 그렇게하지 않으면 JobManager에서 향후 콜백을 차단하게됩니다.
구체적으로 onStopJob(android.app.job.JobParameters)일정 요구 사항이 더 이상 충족되지 않는다는 것을 알리기위한 것입니다.
MainActivity
class MyJobService : JobService() {
/*
* 이 서비스는 Handler응용 프로그램의 주 스레드 에서 실행중인 각 수신 작업을 실행합니다.
* 즉, 실행 논리를 선택한 스레드 / 처리기 / 다른 스레드로 오프로드 해야합니다AsyncTask . 그렇게하지 않으면 JobManager에서 향후 콜백을 차단하게됩니다.
* 구체적으로 onStopJob(android.app.job.JobParameters)일정 요구 사항이 더 이상 충족되지 않는다는 것을 알리기위한 것입니다.*/
override fun onStartJob(jobParameters: JobParameters): Boolean {
//작업이 실행되기 시작했음을 나타 내기 위해 호출됩니다.
// TODO(developer): add long running task here.
return false
}
override fun onStopJob(jobParameters: JobParameters): Boolean {
return false
//이 메서드는 호출 기회가 있기 전에도 작업 실행을 중지해야한다고 시스템에서 결정한 경우 호출 jobFinished(JobParameters, boolean)됩니다.
}
companion object {
private const val TAG = "MyJobService"
}
}
MainActivity에서 FirebaseMessaging을 객체를 얻어 초기화 해주면 마지막으로 설정이 끝납니다. subscribeToTopic() 메소드는 사용하면 특정 채널을 구독할 수 있습니다.
https://firebase.google.com/docs/cloud-messaging/android/receive?hl=ko
위 사이트에서 직접 코드도 확인해 볼 수 있습니다
댓글