์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- json
- RecyclerView
- layout_constrainedHeight
- ๊ธฐ๊ธฐ๊ณ ์ ๊ฐ
- layout_constrainedWidth
- Retrofit2
- http
- ThreeTen Backport
- SSAID
- log
- kotlin
- WorkManager
- Lifecycle
- DataBinding
- findNavController
- Room
- ์๋ช ์ฃผ๊ธฐ
- BottomSheetDialogFragment
- todo
- Android
- Load failed
- Navigation
- Collections Function
- DialogFragment
- NumberPIcker
- gradle plugin
- multipart
- Popup menu background color
- studywithme
- ํ๋ฉด ํ์
- Today
- Total
chacha's
โฐ Android FCM ํธ์ ์๋ฆผ ๋ณธ๋ฌธ
๋ชฉ์ฐจ
๐ฆ FCM ( Firebase Cloud Messaging )
Firebase Console
Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง(FCM)์ ๋ฉ์์ง๋ฅผ ์์ ์ ์ผ๋ก ์ ์กํ ์ ์๋ ํฌ๋ก์ค ํ๋ซํผ ๋ฉ์์ง ์๋ฃจ์ ์ ๋๋ค. ์ง์ ๊ตฌํํ ์๋ฒ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ฆผ/๋ฉ์์ง๋ฅผ ์ ์กํ๊ธฐ ์ํด์๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ์๋ฒ๊ฐ ์ฐ๊ฒฐ์ ๊ณ์ ์ ์งํ๊ณ ์์ด์ผ ํฉ๋๋ค. ํ์ง๋ง FCM์ ์ด์ฉํ๋ฉด, ์ฐ๊ฒฐ์ ์ ์งํ๊ณ ์์ง ์์๋ ๋ฉ์์ง๋ฅผ ์ ์กํ๊ณ ๋ฐ์ ์ ์์ต๋๋ค.
๐ฏ Notification๊ณผ Data
FCM ๋ฉ์์ง ์ ๋ณด
Android FCM Data์ Notification - ํด๋ฆฌ์ ์ ๋ชฉ์ฝ๋ฉ
ํธ์ ์๋ฆผ์ผ๋ก ๋ณด๋ผ ์ ์๋ ๋ฉ์์ง๋ ์๋์ ๊ฐ์ด 2๊ฐ์ง ์ ํ์ผ๋ก ๋๋ฉ๋๋ค. Notification์ ์ฑ์ด ํฌ๊ทธ๋ผ์ด๋์ผ ๋๋ง ํธ์ ์๋ฆผ์ด ์ค๊ณ Data๋ ์ฑ์ด ํฌ๊ทธ๋ผ์ด๋์ ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋์ ์๋ ์๊ด์์ด ํธ์ ์๋ฆผ์ด ์ต๋๋ค. ๋ํ Notification๊ณผ Data๋ฅผ ๊ฐ์ด ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ์์ต๋๋ค.
๐จ๐จ๐ง๐ฆ ๋๊ตฌ์๊ฒ ๋ณด๋ผ ๊ฒ์ธ๊ฐ? ( ํธ์ ์๋ฆผ ๋์ )
Android์์ ์ฃผ์ ๋ฉ์์ง(topic messagin)
Android์ ๊ธฐ๊ธฐ ๊ทธ๋ฃน์ ๋ฉ์์ง ๋ณด๋ด๊ธฐ
1. ํน์ ๋์ 1๋ช
ํน์ ๊ธฐ๊ธฐ์ Token ๊ฐ์ ์ด์ฉํ์ฌ ํด๋น ๊ธฐ๊ธฐ์๋ง ์๋ฆผ์ ์ ์กํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
2. ์ฌ๋ฌ ๋ช ( topic์ ๊ตฌ๋ ํ ์ฌ๋๋ค )
ํน์ topic์ ๊ตฌ๋ ํ ์ฌ๋ฌ ๊ธฐ๊ธฐ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ ์จ์ ๊ฐ์ด ๊ณต๊ฐ์ ์ผ๋ก ์ ๊ณต๋๋ ์ ๋ณด์ ์ฌ์ฉํ๋ฉด ์ ํฉํ ๋ฐฉ๋ฒ์ ๋๋ค. ํด๋ผ์ด์ธํธ์ธ ์ฑ์์ ๊ธฐ์กด topic์ ๊ตฌ๋ ํ๊ฑฐ๋ ์ topic์ ๋ง๋ค ์ ์์ต๋๋ค. Firebase ํ๋ก์ ํธ์ ์์ง ์๋ ์ topic์ ๊ตฌ๋ ํ๋ฉด FCM์์ ์ด ์ด๋ฆ์ผ๋ก ์ topic์ด ๋ง๋ค์ด์ง๊ณ , ์ดํ์ ๋ค๋ฅธ ํด๋ผ์ด์ธํธ์์ ๊ทธ topic์ ๊ตฌ๋ ํ ์ ์์ต๋๋ค. Firebase Admin SDK๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฒ ์ธก์์ ๊ธฐ๋ณธ์ ์ธ topic ๊ด๋ฆฌ ์์ ์ ์ํํ ์ ์์ต๋๋ค. ๋ฑ๋ก ํ ํฐ์ ์๊ณ ์์ผ๋ฉด ์๋ฒ ๋ก์ง์ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ ์ฑ ์ธ์คํด์ค๋ฅผ ์ผ๊ด ๊ตฌ๋ ํ๊ฑฐ๋ ๊ตฌ๋ ์ทจ์ํ ์ ์์ต๋๋ค. ์๋๋ณด๋ค ์ฒ๋ฆฌ๋์ ์์ฃผ๋ก ์ต์ ํ๋์ด ์๋ ๊ธฐ๋ฅ์ผ๋ก ๋น ๋ฅด๊ณ ์์ ํ๊ฒ ์ ์กํ๊ณ ์ถ๋ค๋ฉด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ผ๊ณ ๊ถ๊ณ ๋์ด ์์ต๋๋ค.
3. ์ฌ๋ฌ ๋ช ( ๊ธฐ๊ธฐ ๊ทธ๋ฃน์ ์ํ ์ฌ๋๋ค )
๊ทธ๋ฃน์ ์ํ ๊ธฐ๊ธฐ์๋ง ์๋ฆผ์ ๋ณด๋ด๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๊ธฐ๊ธฐ ๊ทธ๋ฃน ๋ฉ์์ง์ ์ฑ ๋ด์์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์๋๋ผ ์๋ฒ์์ ๊ธฐ๊ธฐ ๊ทธ๋ฃน์ ๊ด๋ฆฌํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๊ธฐ๊ธฐ ๋ชจ๋ธ์ ๋ฐ๋ผ์ ๋ค๋ฅธ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ค๋ฉด ์๋ฒ์์ ์๋ง์ ๊ทธ๋ฃน์ ๋ฑ๋ก/์ญ์ ํ์ฌ ๊ฐ ๊ทธ๋ฃน์ ์ ์ ํ ๋ฉ์์ง๋ฅผ ๋ณด๋ ๋๋ค. ํ์ง๋ง ์๋ฆผํค ํ๋ ๊ทธ๋ฃน์ ์ต๋ 20๋ช ๊น์ง๋ง ์ํ ์ ์์ต๋๋ค.
๐ FCM ์๋ฆผ์ ์ ์กํ๋ ์ ์ฒด ๊ณผ์
๐ฅ Android ์ฑ์์ ํธ์ ์๋ฆผ ๋ฐ๊ธฐ
1. Firebase ๊ตฌ์ฑ ํ์ผ ์ถ๊ฐ
Android์์ Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง ํด๋ผ์ด์ธํธ ์ฑ ์ค์ | Firebase Documentation
Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register ์๊ฒฌ ๋ณด๋ด๊ธฐ Android์์ Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง ํด๋ผ์ด์ธํธ
firebase.google.com
2. FirebaseMessagingService๋ฅผ ์์
์๋ฆผ์ ์์ ํ ์ ์๋ Service ์ฝ๋๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค. 2๊ฐ์ ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ ํด์ผ ํฉ๋๋ค.
onNewToken()
์ FCM ์๋ฒ์ ์ฑ์ด ๋ฑ๋ก๋์์ ๋ ํธ์ถ๋๊ณ , ํ๋ผ๋ฏธํฐ๋ก Token ๊ฐ์ด ์ ๋ฌ๋ฉ๋๋ค. ์ด Token ๊ฐ์ ๊ฐ๊ฐ์ ์ฑ์ ๊ตฌ๋ถํ๊ธฐ ์ํ ๊ณ ์ ํ ํค์
๋๋ค.
onMessageReceived()
๋ FCM ์๋ฒ์์ ๋ฉ์์ง๋ฅผ ์ ์กํ๋ฉด ํธ์ถ๋ฉ๋๋ค.
class ChordFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
Log.i("onNewToken", "Success save token")
sendRegistrationToServer(token) // Token์ ์๋ฒ๋ก ์ ์ก
}
// ๋ฉ์์ง๋ฅผ ์์ ํ๋ ๋ฉ์๋
override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (remoteMessage.data.isNotEmpty()) {
sendNotification(
remoteMessage.data["title"].toString(),
remoteMessage.data["body"].toString()
)
} else {
remoteMessage.notification?.let {
sendNotification(
remoteMessage.notification!!.title.toString(),
remoteMessage.notification!!.body.toString()
)
}
}
}
// ์๋ฆผ์ ์์ฑํ๋ ๋ฉ์๋
private fun sendNotification(title: String, body: String) {
val notifyId = (System.currentTimeMillis() / 7).toInt()
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent =
PendingIntent.getActivity(this, notifyId, intent, PendingIntent.FLAG_ONE_SHOT)
val channelId = getString(R.string.firebase_notification_channel_id)
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationManagerCompat.IMPORTANCE_HIGH)
.setAutoCancel(true)
.setSound(soundUri)
.setContentIntent(pendingIntent)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
channelId,
NotificationManager.IMPORTANCE_HIGH
)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(notifyId, notificationBuilder.build())
}
}
3. Manifest ํ์ผ ์์
1) ์ธํฐ๋ท์ ์ฌ์ฉํ๊ธฐ ์ํด ์ธํฐ๋ท ํผ๋ฏธ์ ์ ์ถ๊ฐํฉ๋๋ค.
2) ์๋น์ค ํ์ผ์ Manifest ํ์ผ์ ๋ฑ๋กํด์ผ ํฉ๋๋ค. ์ด๋, ๋ฉ์์ง๋ฅผ ์์ ํ๊ธฐ ์ํ intent-filter๋ฅผ ์ค์ ํด์ค๋๋ค.
<uses-permission android:name="android.permission.INTERNET"/>
<service android:name=".network.ChordFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
4. Firebase Console์์ Push ํ ์คํธ ํ๊ธฐ
์๋ฆผ ์ ๋ชฉ๊ณผ ์๋ฆผ ํ ์คํธ๋ฅผ ์ ๋ ฅ ํ [ํ ์คํธ ๋ฉ์์ง ์ ์ก] ๋ฒํผ์ ๋๋ฌ์ค๋๋ค. ๋ง์ฝ ํ ์คํธ ๋ฉ์์ง ์ ์ก์ ๋๋ ์ ๋ ์๋์ ๊ฐ์ ํ๋ฉด์ด ํ์๋๋ค๋ฉด FCM ํ ํฐ์ ์ ๋ ฅํด์ฃผ๋ฉด ๋ฉ๋๋ค.
- ํ ์คํธ ํ๋ฉด
๐ค Node js ํธ์ ์๋ฆผ ๋ณด๋ด๊ธฐ
๊ธฐ๊ธฐ ๋ฑ๋ก ํ ํฐ ์ก์ธ์ค
์ฑ ์๋ฒ ์ ์ก ์์ฒญ ์์ฑ
FCM์ ์ด์ฉํ์ฌ node js ํธ์ ์๋ ๊ตฌํํ๊ธฐ - Yusong ๋ธ๋ก๊ทธ
1. ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ํ์ฌ FCM ํ ํฐ ๊ฐ์ ์์๋ ๋๋ค. ( Android ํด๋ผ์ด์ธํธ ์ค์ )
FCM SDK๋ ์ฑ์ ์ฒ์ ์์ํ ๋ ํด๋ผ์ด์ธํธ ์ฑ ์ธ์คํด์ค์ฉ ๋ฑ๋ก ํ ํฐ์ ์์ฑํฉ๋๋ค. ์ด ํ ํฐ์ ์๋์ ๊ฒฝ์ฐ์ ๋ณ๊ฒฝ๋ ์ ์์ต๋๋ค.
- ์ ๊ธฐ๊ธฐ์์ ์ฑ์ ๋ณต์
- ์ฌ์ฉ์๊ฐ ์ฑ ์ญ์ /์ฌ์ค์น
- ์ฌ์ฉ์๊ฐ ์ฑ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐ
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()
})
2. ํน์ ๊ธฐ๊ธฐ (deviceToken์ ํด๋นํ๋ ๊ธฐ๊ธฐ)๋ก ํธ์ ์๋ฆผ์ ์ ์กํฉ๋๋ค.
/**
* Push Alarm
**/
const admin = require("firebase-admin"); // Firebase Admin SDK ์ค์น
let serviceAccount = require("./firebase_admin_key.json"); // ๋น๊ณต๊ฐ ์๋ฒํค ๋ค์ด๋ก๋ ํ ๋ก๋
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
// Push Test
app.get('/pushComplete', function (req, res, next) {
let deviceToken = "์ฑ FCM ํ ํฐ ๊ฐ"
let message = {
notification: {
title: "Test",
body: "push test in server"
},
token: deviceToken
}
admin
.messaging()
.send(message)
.then(function (response) {
console.log('Successfully sent message: : ', response)
return res.status(200).json({ success: true })
})
.catch(function (err) {
console.log('Error Sending message!!! : ', err)
return res.status(400).json({ success: false })
})
})
- ํ ์คํธ ํ๋ฉด
๐ ์ฐธ๊ณ
๋น๊ทผ๋ง์ผ์ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋ง์ ์ฌ์ฉ์์๊ฒ ์ด๋ป๊ฒ ๋น ๋ฅด๊ณ ์์ ์ ์ผ๋ก ํธ์ ์๋น์ค๋ฅผ ์ ๊ณตํ๋์ง์ ๋ํด ์์ ๋์ด ์์ต๋๋ค.
๋น๊ทผ๋ง์ผ์ ํธ์์๋ฆผ์ ์งํฑํ๊ณ ์๋ Node.js ์๋น์ค
ํธ์์๋ฆผ์ ๋น๊ทผ๋ง์ผ ์๋น์ค์์ ์ฑํ , ‘ํค์๋ ์๋ฆผ’, ‘๊ธ์ฃผ์ ์ธ๊ธฐ๋งค๋ฌผ’๊ณผ ๊ฐ์ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค. ์ด๋น 1500 ์์ฒญ์ ๋๋ฝ ์์ด ์ง์ํ๋ ํธ์ ์๋น์ค๋ฅผ Node.js, TypeScript๋ก ๊ฐ
medium.com
END
'Android > My Library' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๐ฌ Popup Menu ์ฌ์ฉํ๊ธฐ (0) | 2021.11.23 |
---|---|
๐ฐ Chip ์ฌ์ฉํ๊ธฐ (0) | 2021.08.06 |
๐งญ Navigation์ ์ด์ฉํด์ Dialog๋ก ์ ํํ๊ธฐ (0) | 2021.06.09 |
โป RecyclerView ์ ๐ฉHeader ์ถ๊ฐํ๊ธฐ (0) | 2021.06.07 |
โป RecyclerView์ ๐ Click ์ด๋ฒคํธ ์ถ๊ฐํ๊ธฐ (0) | 2021.06.07 |