앞에서 python 코드를 이용해서 random 숫자를 만들고 FCM 전송하는 코드를 구현해 보았다면, 이번에 그걸 이용해서 수신하는 앱을 하나 만들어 볼 차례다.
https://billcorea.tistory.com/179
코드 구현은 kotlin으로 해 보았다. 이제 걸음마 단계이기 때문에 코드가 조금 길어질 수 도 있지만, 아직은 준비 중인 단계이기 때문에...
먼저 FCM을 수신하기 위해서는 firebase와 연동을 위한 gradle 구성이 필요하다.
import java.text.SimpleDateFormat
plugins {
id 'com.android.application'
id 'com.google.gms.google-services'
id 'com.google.firebase.crashlytics'
id 'kotlin-android-extensions'
id 'kotlin-android'
id 'kotlin-kapt'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.bi.......tto"
minSdk 28
targetSdk 32
versionCode 10
versionName "0.1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
buildConfigField "Boolean", "DEBUG_MODE", "true"
}
release {
buildConfigField "Boolean", "DEBUG_MODE", "false"
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// jetPack compose add
buildFeatures {
viewBinding true
}
kotlinOptions {
jvmTarget = "1.8"
}
def archiveBuildType = ["release"]
applicationVariants.all { variant ->
variant.outputs.each { output ->
if (variant.buildType.name in archiveBuildType) {
def df = new SimpleDateFormat("yyyyMMdd")
df.setTimeZone(TimeZone.getDefault())
if (variant.versionName != null) {
String name = "GetLotto645_${df.format(new Date())}_${defaultConfig.versionCode}_${variant.versionName}.apk"
output.outputFileName = name
}
}
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'com.google.android.play:core:1.10.3'
// 파이어 베이스 연동을 위한 설정...
implementation platform('com.google.firebase:firebase-bom:29.2.1')
// 메시징
implementation 'com.google.firebase:firebase-messaging:23.0.2'
// 인증처리
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.android.gms:play-services-auth:20.1.0'
// realtime database
implementation 'com.google.firebase:firebase-database-ktx'
// crashlytics
implementation 'com.google.firebase:firebase-crashlytics-ktx'
implementation 'com.google.firebase:firebase-analytics-ktx'
// safetynet 앱 인증
implementation 'com.google.firebase:firebase-appcheck-safetynet:16.0.0-beta05'
implementation 'com.google.firebase:firebase-appcheck-debug:16.0.0-beta05'
implementation 'androidx.preference:preference-ktx:1.2.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation "androidx.core:core-ktx:1.7.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.google.android.gms:play-services-ads:20.6.0'
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
implementation 'com.google.zxing:core:3.4.1'
}
다음은 manifest에 intenet 활용을 위한 permission 선언이 필요하고.
<uses-permission android:name="android.permission.INTERNET" />
그리고 service을 등록해야 한다. FCM 수신을 위한 리시버...
<service
android:name="com.billcoreatech.getLotto.utils.FcmReceiveService"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
다음은 kotlin으로 구현한 service 코드 (사실 개발자 문서의 내용을 그대로 옮겨 왔다고 해도 과언은 아닐 것이다.)
package com.b...................to.utils
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
import android.media.RingtoneManager
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import com.billcoreatech.getLotto.MainActivity
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import getLotto.R
class FcmReceiveService : FirebaseMessagingService() {
var TAG:String = "FcmReceiveService"
override fun onMessageReceived(remoteMessage: RemoteMessage) {
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
Log.e(TAG, "From: " + remoteMessage.from)
// Check if message contains a data payload.
if (remoteMessage.data.size > 0) {
Log.e(TAG, "Message data payload: " + remoteMessage.data)
sendNotification(remoteMessage.data["body"])
var sp = getSharedPreferences("Messageing", MODE_PRIVATE)
var editor = sp.edit()
editor.putString("SendMsg", remoteMessage.data["body"]);
editor.putBoolean("msgSet", true)
editor.commit()
}
// Check if message contains a notification payload.
if (remoteMessage.notification != null) {
Log.e(
TAG, "Message Notification Body: " + remoteMessage.notification!!.body
)
sendNotification(remoteMessage.notification!!.body)
}
onDeletedMessages()
}
// [END receive_message]
override fun onNewToken(token: String) {
Log.e(TAG, "Refreshed token: $token")
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// FCM registration token to your app server.
sendRegistrationToServer(token)
}
// [END on_new_token]
/**
* Handle time allotted to BroadcastReceivers.
*/
private fun handleNow() {
Log.d(TAG, "Short lived task is done.")
val intent = Intent(this@FcmReceiveService, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM registration token with any
* server-side account maintained by your application.
*
* @param token The new token.
*/
private fun sendRegistrationToServer(token: String) {
// TODO: Implement this method to send token to your app server.
}
/**
* Create and show a simple notification containing the received FCM message.
*
* @param messageBody FCM message body received.
*/
private fun sendNotification(messageBody: String?) {
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
Log.e(TAG, "mesg=${messageBody}")
val pendingIntent = PendingIntent.getActivity(
this, 0 /* Request code */,
intent, PendingIntent.FLAG_IMMUTABLE
)
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val channelId = getString(R.string.default_notification_channel_id)
val channelName: CharSequence = getString(R.string.default_notification_channel_name)
val importance = NotificationManager.IMPORTANCE_LOW
val notificationChannel = NotificationChannel(channelId, channelName, importance)
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.BLUE
notificationChannel.enableVibration(true)
notificationChannel.vibrationPattern =
longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
notificationManager.createNotificationChannel(notificationChannel)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_logo645_foreground)
.setContentTitle(getString(R.string.fcm_message))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.extend(
NotificationCompat.WearableExtender()
.setBridgeTag("Foo")
.setContentIcon(R.mipmap.ic_logo645_foreground)
)
.setContentIntent(pendingIntent)
// 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)
}
// Dismiss notification once the user touches it.
notificationBuilder.setAutoCancel(true)
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
}
}
필요한 부분만 일부 수정을 했다.
이번에 또 알게 된 부분이라면 전송할 때 코드 구현에 따라 수신되는 위치가 달라진다는 것이다.
<data로 구현했을 때>
def lambda_handler(token, context):
FCMToken = token
Data = {'data': {'title': 'Lotto 보내 드립니다.', 'body': context}, 'to': FCMToken}
Headers = {'Content-type': 'application/json',
'Authorization': 'Key=AAAAR_..........................3uTasJ-DGfJKZkS-ccyNr0xhRHTepcuk4GaFoNMTADl4jvNFM1HYIRqzSLs219BxVA-T9frSd3VCSUIRXXn1PSxhOKgqroBVqTaxmWk'}
http = urllib3.PoolManager().request('POST', 'https://fcm.googleapis.com/fcm/send', headers=Headers,
body=json.dumps(Data))
return {'statusCode': 200, 'body': json.dumps('Hello from Lambda!')}
<notification으로 구현했을 때>
def lambda_handler(token, context):
FCMToken = token
Data = {'notification': {'title': 'Lotto 보내 드립니다.', 'body': context}, 'to': FCMToken}
Headers = {'Content-type': 'application/json',
'Authorization': 'Key=AAAAR_0..........................uTasJ-DGfJKZkS-ccyNr0xhRHTepcuk4GaFoNMTADl4jvNFM1HYIRqzSLs219BxVA-T9frSd3VCSUIRXXn1PSxhOKgqroBVqTaxmWk'}
http = urllib3.PoolManager().request('POST', 'https://fcm.googleapis.com/fcm/send', headers=Headers,
body=json.dumps(Data))
return {'statusCode': 200, 'body': json.dumps('Hello from Lambda!')}
같은 코드 이기는 하지만, 전송하는 parameter에 따라서 그걸 수신 앱에서는 다른 처리를 할 수 있다는 것이 된다.
그래서 앞으로는 필요에 따라서 parameter을 다르게 해서 전송할 생각이다.
두 영상의 미묘한 차이를 찾을 수 있을까??? 위에 기술한 fcmReceiceService 코드를 같이 보면서 이해를 해 보면 작은 차이을 알 수 있지 않을까 싶다.
오늘도 즐 코딩 ...
'모바일 앱(안드로이드)' 카테고리의 다른 글
안드로이드 앱 만들기 : compose 예제 찾아 보기... feat Room Database (0) | 2022.04.22 |
---|---|
안드로이드 앱 만들기 : Jetpack Compose 항목들 예시... (5) | 2022.04.13 |
안드로이드 앱 만들기 : Jetpack Compose 와 xml 의 차이 (0) | 2022.04.09 |
안드로이드 앱 만들기 : 오늘도 jetpack compose 에 헤메이다... (3) | 2022.04.07 |
안드로이드 앱 만들기 : 왜 Jetpack Compose 인가 ? (3) | 2022.04.03 |