๋ชฉ์ฐจ
๋ค์ด๊ฐ๊ธฐ ์ ์
์๋ ํ์ธ์!
1ํ์ ์ด์ด ๋ณธ๊ฒฉ์ ์ธ FCM๊ณผ Retrofit ๊ณผ ํจ๊ป ๋์์จ Mandy์ ๋๋ค ๐
์ง๋ 1ํ์์๋ Android์ Notification์ ๋ํด์ ์์๋ณด์๋๋ฐ์!
์ค๋์ ๋ ๋์๊ฐ FCM๊ณผ Retrofit์ ์ด์ฉํ์ฌ ์ธํ ์๋ฃ ์๋ฆผ ๊ธฐ๋ฅ์ ๋ง๋ฌด๋ฆฌ ํด๋ณด๋ ค๊ณ ํด์. ์ง๋ 1ํ๋ณด๋ค ์กฐ๊ธ ๋ ๋ง์ ๋ด์ฉ์ ๋ค๋ฃฐ ์์ ์ด๋ผ์ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐ๋ผ์์ฃผ์ธ์ ใ ใ

๊ฒฐ๊ณผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
๋ณธ๊ฒฉ์ ์ธ ๊ฐ๋ฐ์ ์์์ ๊ตฌํํ ๊ฒฐ๊ณผ๋ฅผ ๋จผ์ ๋ณด๋๋ก ํ ๊ฒ์!
[ ์์ ์ฒจ๋ถํ๊ธฐ]
์ด์ ์์ํด๋ด ์๋ค !!
FCM ์ดํดํ๊ธฐ
FCM์ ๋ชจ๋ฐ์ผ ์ฑ ๋ฐ ์น ์ฑ์์ ์ค์๊ฐ ๋ฉ์์ง๋ฅผ ์ ์กํ ์ ์๋ ๊ธฐ๋ฅ์ด์์. ์๋ฒ์์ ํด๋ผ์ด์ธํธ ๋๋ฐ์ด์ค๋ก ํธ์ ์๋ฆผ์ ๋ณด๋ผ ์ ์์ผ๋ฉฐ ๋ค์ํ ์๋ฆผ ์ ํ์ ๊ตฌํํ ์ ์์ด์!
FCM ํ๋ฆ ์ ๋ฆฌ
1๏ธโฃ FCM์์ ๋ฉ์์ง๋ฅผ ์์ ํ๋๋ก ๊ธฐ๊ธฐ ๋ฑ๋ก
- ํด๋ผ์ด์ธํธ ์ฑ์ด ๋ฉ์์ง๋ฅผ ์์ ํ๋๋ก ๋ฑ๋กํ์ฌ ์ฐ๋ฆฌ์ ํด๋์ ํ ๊ธฐ๊ธฐ์ ๊ณ ์ ํ๊ฒ ์๋ณํ๋ ๋ฑ๋ก ํ ํฐ์ ๋ฐ์์.
2๏ธโฃ ๋ฉ์์ง ์ ์ก ๋ฐ ์์
- ๋ฉ์์ง๋ FCM console ํ๊ฒฝ์ด๋ ์ ๋ขฐํ ์ ์๋ ํ๊ฒฝ(HTTP ๋ฑ)์์ ์์ฑ๋๋ฉฐ ๋ฉ์์ง ์์ฒญ์ด FCM ๋ฐฑ์๋๋ก ์ ์ก๋์ด์
- FCM ๋ฐฑ์๋(์๋ฒ)๋ ๋ฉ์์ง ์์ฒญ์ ์์ ํ๊ณ ๋ฉ์์ง ID์ ๊ธฐํ ๋ฉํ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ์ฌ ์๋๋ก์ด๋ ์ ์ก ๊ณ์ธต (Android transport layer)๋ก ๋ณด๋ด์.
- ๊ธฐ๊ธฐ์์ ํด๋ผ์ด์ธํธ์ฑ์ด ๋ฉ์์ง ๋๋ ์๋ฆผ์ ์์ ํด์.
FCM ๋ฐฑ์๋๋ ์๋ฒ์ ๋์ผํ ๊ฒ์ธ๊ฐ์?
๋ค ! FCM ์๋ฒ๋ firebase cloud messaging์ ์ง์ํ๊ณ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๋ ์๋ฒ ์์คํ
์ ๋งํด์! ์ด ์๋ฒ๋ฅผ ํตํด ํด๋ผ์ด์ธํธ์ฑ๊ณผ ์ํธ์์ฉํ์ฌ ๋ฉ์์ง๋ฅผ ์ ์กํ๊ณ ๋ฐ์ ์ ์์ด์.
FCM ์๋ฒ์ ์ญํ
1๏ธโฃ๋ฉ์์ง ์ ์ก :
ํด๋ผ์ด์ธํธ์ฑ์ ํธ์ ์๋ฆผ ๋ฐ ๋ฐ์ดํฐ ๋ฉ์์ง๋ฅผ ์ ์กํด์. ์ด๋ฅผ ํตํด ์๋ฒ์์ ํด๋ผ์ด์ธํธ ๋๋ฐ์ด์ค๋ก ๋ฉ์์ง๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ ๋ฌํ ์ ์์ด์,
2๏ธโฃ๋๋ฐ์ด์ค ๊ด๋ฆฌ
FCM ์๋ฒ๋ ๊ฐ ๋๋ฐ์ด์ค์ ๊ณ ์ ํ ์๋ณ์์ธ FCM ํ ํฐ์ ํ๋๋ฐ์. ์ด ํ ํฐ์ ์ฌ์ฉํด ์๋ฒ๋ ํน์ ๋๋ฐ์ด์ค์ ๋ฉ์์ง๋ฅผ ์ ์กํ ์ ์์ด์!
์ฐ๋ฆฌ ํ์ ์์๋ Retrofit ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ FCM ์๋ฒ์ HTTP ์์ฒญ์ ๋ณด๋ด๋ ๋ฐฉ์์ ์ด์ฉํ์ด์!
์ด๋ฅผ ์ํด FCM ์๋ฒ์ ํธ์์๋ฆผ์ ๋ณด๋ด๊ธฐ ์ํ Retrofit ์ธํฐํ์ด์ค์ธ NotiAPI๋ฅผ ์ ์ํด์ฃผ์์ด์.
๋ชฉํ
- ์ ์ ์ ํ ํฐ ์ ๋ณด๋ฅผ ๋ฐ์์์
- Firebase ์๋ฒ๋ก ๋ณด๋ด๋ผ๊ณ ๋ช ๋ นํ๊ณ
- Firebase ์๋ฒ์์ ์ฑ์ผ๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด์ฃผ๊ณ
- ์ฑ์์๋ ๋ฉ์์ง๋ฅผ ๋ฐ์์ → ๋ฉ์์ง ์์ ๋ถ๋ถ
- ์ฑ์์๋ ์๋์ ๋์์ค → ๋ฉ์์ง ์์ ๋ถ๋ถ์์ notification ์ฒ๋ฆฌ
์ฐ๋ฆฌ์ ๋ชฉํ๋ ์์ ๊ฐ์์๐ช์ด๋ฅผ ์ํด ๊ธฐ๋ณธ ์ค์ ์ ํด์ค๊ฒ์.
์ฑ ๋งค๋ํ์คํธ ์์
FirebaseMessagingService ๋
FCM์ ์ฌ์ฉํ์ฌ ๋๋ฐ์ด์ค๋ก ๋ฉ์์ง๋ฅผ ์์ ํ๊ณ ์ฒ๋ฆฌํ๋ ์๋น์ค ๋ฅผ ๋งํด์.
์ด ์๋น์ค๋ฅผ ํ์ฅํ์ฌ FCM ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๊ณ ํฌ๊ทธ๋ผ์ด๋ ๋ฐ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์๋ฆผ์ ์์ ํ ์ ์์ด์.
์ด๋ฅผ ์ํด FirebaseMessagingService๋ฅผ ํ์ฅํ๋ ์๋น์ค๋ฅผ ๋งค๋ํ์คํธ ํ์ผ์ ์ถ๊ฐํด์ค์.
์๋น์ค๋?
์๋๋ก์ด๋์์ Service๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํ๋๋ ์์ ์ ์ํํ๋ ์ปดํฌ๋ํธ๋ฅผ ๋งํด์!
- ๋ฐฑ๊ทธ๋ผ์ด๋ ์์
- ์๋ฅผ ๋ค์ด ์์ ์ฑ์ด ํ๋ฉด์ ํ์๋์ง ์์๋ ์์ ์ฌ์์ด ๊ณ์ ๋๋ ๊ฒ์ ์๊ฐํ๋ฉด ๋์ด์!
- ๊ณ์๋ ์คํ
- ์๋ฅผ ๋ค์ด ์์น ์ถ์ ์๋น์ค๋ ์ฌ์ฉ์๊ฐ ์ด๋ค ์ฑ์ ์ฌ์ฉํ๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๊ณ์ํด์ ์์น๋ฅผ ์ถ์ ํด์!
- ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ํต์
- ์๋น์ค๋ ์กํฐ๋นํฐ, ๋ธ๋ก๋์บ์คํธ ์์ ์ ๋ฑ๊ณผ ํต์ ํ ์ ์์ด์. ์ด๋ฅผ ํตํด ์ฑ์ ์ฌ๋ฌ ๋ถ๋ถ๊ณผ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋ต๋๋ค. ์๋ฅผ ๋ค์ด ์ฑ์์ ์์ ์ ์ฌ์ํ๋ ์๋น์ค๋ ์ฌ์ฉ์๊ฐ ์ฑ์ ์กํฐ๋นํฐ์์ ์์ ์ ์ผ์์ ์งํ๊ฑฐ๋ ์คํฌํ ๋ ์ด๋ฅผ ์ฒ๋ฆฌํ ์ ์์ด์.
- ์๋ช
์ฃผ๊ธฐ ๊ด๋ฆฌ
- ์๋น์ค๋ ์กํฐ๋นํฐ์๋ ๋ค๋ฅธ ์์ฒด ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๊ณ ์์ด์.
<service
android:name=".fcm.FirebaseCloudMessagingService"
android:exported="false"
android:permission="TODO">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
๐จ์ฃผ์์ฌํญ
android:name์๋ **FirebaseMessagingService** ๋ฅผ ์์๋ฐ์ ํด๋์ค๋ช ์ ์ ์ด์ฃผ์ด์ผํด์.
๋ค๋ฅธ ์กํฐ๋นํฐ ํด๋์ค๋ ๋ค๋ฅธ ํด๋์ค๋ช ์ ์ ์ ๊ฒฝ์ฐ ์ ๋๋ก ์๋ํ์ง ์์ผ๋ ์ฃผ์ํด์ฃผ์ธ์!
์ด๊ฒ๋๋ฌธ์ ๊ณ ์ํ ๊ธฐ์ต์ด.. ๐
์ ์ ์ ํ ํฐ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
์ด์ ์์ ์ธ๊ธํ๋ ํ ํฐ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ๊ฒ์!
ํ ํฐ์ ๋๋ฐ์ด์ค๋ฅผ ๊ณ ์ ํ๊ฒ ์๋ณํด์ฃผ๊ณ , ์๋ฒ์์ ๋ฉ์์ง๋ฅผ ํน์ ๋๋ฐ์ด์ค๋ก ์ ์ก๋ ๋ ์ฌ์ฉ๋ผ์.
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w(TAG, "Fetching FCM registration token failed", task.exception)
return@addOnCompleteListener
}
// Get new FCM registration token
val token = task.result
// Log
Log.d("token๋ณด๊ธฐ", token)
}
์ ์ ์ ํ ํฐ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด์ MainActivity์์ ์ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ฃผ์์ด์!
์ด๋ฅผ ํตํด ๋ก๊ทธ๋ก์ ํ์ฌ์ token์ ์ ์ ์์ด์
ํ์ง๋ง ์ถํ ์คํ๋์ ํ๋ฉด์ ์ถ๊ฐํ๊ณ , ์คํ๋์ ํ๋ฉด์ด ๋ ์๋ ๋์ token ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋๋ก ๋ก์ง์ ์ด๋ํ ์์ ์ด์์!
์๋์ ๋ก๊ทธ๋ฅผ ๋ณด๋ฉด ํ ํฐ์ด ์ ๊ฐ์ ธ์์ง ๊ฒ์ ํ์ธํ ์ ์์ด์!
๐Firebase Console์์ ํ ์คํธ ๋ฉ์์ง ๋ณด๋ด๊ธฐ
FCM ์์์ ์ํด ์ฑ์ด ๋ฐฑ๊ทธ๋ผ์ด๋ ์ํ์ผ ๋ ์ฝ์ ํ๊ฒฝ์์ ๊ฐ๋ฐ ๊ธฐ๊ธฐ๋ก ํ ์คํธ ์๋ฆผ ๋ฉ์์ง๋ฅผ ์ ์กํด๋ณด๋ ์ค์ต์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์!
๋ฐฑ๊ทธ๋ผ์ด๋ ์ฑ์ ํ ์คํธ ๋ฉ์์ง ๋ณด๋ด๊ธฐ | Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง
๋ฐฑ๊ทธ๋ผ์ด๋ ์ฑ์ ํ ์คํธ ๋ฉ์์ง ๋ณด๋ด๊ธฐ | Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง
Google I/O 2023์์ Firebase์ ์ฃผ์ ์์์ ํ์ธํ์ธ์. ์์ธํ ์์๋ณด๊ธฐ ์๊ฒฌ ๋ณด๋ด๊ธฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ฑ์ ํ ์คํธ ๋ฉ์์ง ๋ณด๋ด๊ธฐ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ
firebase.google.com
๊ธฐ๋ณธ ์ค์
- ํ๋ก์ ํธ ์์ค์ Gradle ํ์ผ์์ dependencies ๋ด๋ถ์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
classpath 'com.google.gms:google-services:4.3.15'
- ๋ชจ๋(์ฑ ์์ค) Gradle ํ์ผ์ ์๋์ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ฃผ์ธ์
dependencies {
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:32.1.0')
// Add the dependencies for the Firebase Cloud Messaging and Analytics libraries
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-messaging-ktx'
implementation 'com.google.firebase:firebase-analytics-ktx'
}
๋ฑ๋ก ํ ํฐ
ํน์ ๊ธฐ๊ธฐ๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ธฐ ์ํด์๋ ํ ํฐ์ด๋ผ๋ ๊ฒ์ ์์์ผํ๋ค๊ณ ํ์์ฃ ?
์ฝ์ํ๊ฒฝ์์ ์ด ๋ ๊ฐ์ ธ์จ ํ ํฐ์ ์ ๋ ฅํ์ฌ ํ ์คํธ๋ฅผ ์งํํ ์ ์์ด์.
์์ ๋งค๋ํ์คํธ ํ์ผ์์ ์๋น์ค๋ก ๋ฑ๋กํด์ค ํด๋์ค ํ์ผ์ ์ด์ด์ฃผ์ธ์.
class FirebaseCloudMessagingService :FirebaseMessagingService()
์ฒ๋ผ FirebaseMessagingService๋ฅผ ํ์ฅํ๊ณ onNewToken ๋ฉ์๋๋ฅผ ์ฌ์ ์ํด์ค๊ฑฐ์์.
override fun onNewToken(token: String) {
super.onNewToken(token)
}
โ ๋ฑ๋ก ํ ํฐ์ด ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ
- ์ฑ์ด ์ ๊ธฐ๊ธฐ์ ๋ณต์๋๋ ๊ฒฝ์ฐ
- ์ฌ์ฉ์๊ฐ ์ฑ์ ์ ๊ฑฐ / ์ฌ์ค์นํ๋ ๊ฒฝ์ฐ
- ์ฌ์ฉ์๊ฐ ์ฑ ๋ฐ์ดํฐ๋ฅผ ์ง์ฐ๋ ๊ฒฝ์ฐ
๐๋ฉ์์ง ๋ฐ๊ธฐ
๋ฉ์์ง๋ฅผ ๋ฐ์ผ๋ ค๋ฉด FirebaseMessagingServiceํด๋์ค๋ฅผ ์์๋ฐ์ onMessageReceived ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ์ฌ ์ฒ๋ฆฌํ ์ ์์ด์.
Firebase ์๋ฒ์์ ์์ ๋ RemoteMessage ๊ฐ์ฒด๋ฅผ ๊ธฐ์ค์ผ๋ก ์์ ์ ์ํํ๊ณ ๋ฉ์์ง ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ด์
์๋์ ๊ฐ์ด ํ์ด์ด๋ฒ ์ด์ค ์๋ฒ์์ ๋ณด๋ด์ค๋ RemoteMessage๋ฅผ ๋ฐ์ Log๋ก ์ฐ์ด๋ณด๋ฉด ํ์ธํด๋ณด์์ด์!
// message.data๋ฅผ ์ฌ์ฉํ ์ฝ๋
val title= message.data["title"].toString()
val body = message.data["content"].toString()
Log.d("Cloud",message.data.toString())
//message.notification๋ฅผ ์ฌ์ฉํ ์ฝ๋
if (message.notification != null) {
Log.e("CloudMessage", "Notification ${message.notification}")
Log.e("CloudMessage", "Notification Title ${message.notification!!.title}")
Log.e("CloudMessage", "Notification Body ${message.notification!!.body}")
์ ์ฝ๋์ ๊ฒฐ๊ณผ๋ก ์๋์ฒ๋ผ ๋ก๊ทธ๋ฅผ ํตํด ํ์ธํด๋ณผ ์ ์์ด์.
์ฒซ ๋ฒ์งธ ์ฝ๋์ ๊ฒฐ๊ณผ๋ Cloud ํ๊ทธ๋ก ํ์ธํ ์ ์์ด์.
๋ ๋ฒ์งธ ์ฝ๋์ ๊ฒฐ๊ณผ๋ CloudMessage ํ๊ทธ๋ก ํ์ธํ ์ ์์ด์.
์ฌ๊ธฐ์ ์ CloudMessageํ๊ทธ์๋ null์ด ๋จ๊ณ ์์๊น์?
message.notification๊ณผ message.data๋ ๋ฌด์จ ์ฐจ์ด๊ฐ ์์๊น์?
FCM์์ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ ๋ ์ฌ์ฉ๋๋ ๋ ๊ฐ์ง ์ฃผ์ ์ ํ์ ํ์ด๋ก๋๋ฅผ ๋งํด์.
- message.notification
message.notification๋ notification๋ง ๋ณด๋ด๋ ๋ฉ์์ง๋ก ์ฐ๋ฆฌ๊ฐ firebase console์์ Cloud Message๋ฅผ ๋ณด๋ด๋ ๊ฒฝ์ฐ์ ํด๋นํด์
์์ฒ๋ผ ์ฝ์ํ๊ฒฝ์์ ํ ํฐ์ ์ด์ฉํด ์ ๊ธฐ๊ธฐ๋ก ํ ์คํธ ๋ฉ์์ง๋ฅผ ์ ์กํด๋ณด์๋๋ฐ์. ์๋์ ๋ก๊ทธ๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด message.notification์ ํตํด ์ ๋ฌ๋๊ณ ์์์ ์ ์ ์์ด์.
message.data
message.data ํ์ด๋ก๋๋ ๊ฐ๋ฐ์๊ฐ ์ ์ํ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ ๋ ์ฌ์ฉํด์.
ํด๋ผ์ด์ธํธ ์ฑ์์ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ฃผ์ด์ผํด์.
๋ค์ ๋งํด ํฌ๊ทธ๋ผ์ด๋ ๋๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ฉ์์ง๋ฅผ ์์ ํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ onMessageReceived ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ง์ ๊ตฌํํด์ฃผ์ด์ผํด์.
์ ๊ฐ ๊ตฌํํ message.data์ ํํ๋ ์๋์ ๋ฐ์ดํฐํด๋์ค๋ฅผ ๋ฐ๋ฅด๊ณ ์์ด์,
data class NotiModel(
val title:String="",
val content:String=""
)
๊ทธ๋์ ๋ก๊ทธ๋ฅผ ์ดํด๋ณด๋ฉด ์ ์ํด์ค title๊ณผ content ํํ๋ฅผ ๋ฐ๋ฅด๊ณ ์์์ ํ์ธํ ์ ์์ด์.
์ ๋ onMessageReceived ๋ฉ์๋ ์์์
1๏ธโฃ ์ฝ์์์ ๋ณด๋ด์จ ๋ฉ์์ง๋ฅผ ํ์ธํ๊ธฐ ์ํด message.notification๋ฅผ Log๋ก ํ์ธํ๋ ์ฝ๋
2๏ธโฃ์ ๊ฐ ์ ์ํ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ ์ํ message.data ์ฝ๋
3๏ธโฃ์ด์ ์ฑํฐ์์ ์ด์ผ๊ธฐํ๋ ์๋ฆผ ์ฑ๋๊ณผ notification์ ์์ฑํ๋ ์ฝ๋๋ฅผ ๊ตฌํํด์ฃผ์์ด์.
๐์ ์ฒด ํ๋ฆ ์ ๋ฆฌ
FCM ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ๋ชฉ์ ์ ๋ํด ๊ธฐ์ตํ์๋์? ์ธํ์ด ์๋ฃ๋์์ ๋ ์ฌ์ฉ์์ ๊ธฐ๊ธฐ์ ์๋ฆผ์ ์ฃผ๊ธฐ ์ํจ์ด์์ด์.
๋ฐ๋ผ์ ์ ๋ ์ธํ์ด ์๋ฃ๋์์ ๋ ํธ์ ์๋ฆผ์ ๋ณด๋ด๊ธฐ ์ํด ์ธํ์ด ์๋ฃ๋๋ฉด ์๋์ ์์๋ก ์ฝ๋๋ฅผ ๊ตฌ์ฑํ์ด์.
1๏ธโฃNotiModel ํด๋์ค ๊ฐ์ฒด ์์ฑ
2๏ธโฃPushNotification ํด๋์ค ๊ฐ์ฒด ์์ฑ
3๏ธโฃ testPush ํจ์ ์คํ
4๏ธโฃ RetrofitInstance๋ฅผ ํตํด FCM ์๋ฒ์ ํต์
์ฝ๋๋ฅผ ์์ธํ ์ดํด๋ณผ๊ฒ์!
0๏ธโฃ WasherScreen
val notiModel = NotiModel("${washer.washerId}๋ฒ ์ธํ์ด ์๋ฃ๋์์ด์!","\uD83D\uDE0A ์ธํ๋ฌผ์ ์ฐพ์ผ๋ฌ์์ฃผ์ธ์ ")
// TODO: ํ ํฐ ์ ์ฅ ํ ํด๋น ํ ํฐ์ ๋ฃ์ด์ฃผ๋ ๋ก์ง ์ถ๊ฐ ํ์
val pushModel = PushNotification(notiModel)
testPush(pushModel)
- NotiModel ๊ฐ์ฒด์ธ notiModel์ ๋ง๋ค์ด์ค์.
- PushNotification ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ๋ก ์ด notiModel ์ ๋๊ฒจ์ค์.
1๏ธโฃNotiModel
data class NotiModel(
val title:String="",
val content:String=""
)
NotiModel์ ์์์ ์ดํด๋ฉด message.data ํํ์ ํ์ด๋ก๋, ์ฆ ๋ฐ์ดํฐ ํ์ด๋ก๋๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํ ๋ฐ์ดํฐ ํด๋์ค์์.
- title์ ์๋ฆผ์ ์ ๋ชฉ์, content๋ ์๋ฆผ์ ๋ด์ฉ์ ๋ํ๋ด์.
2๏ธโฃPushNotification
class PushNotification(
val data : NotiModel,
val to: String
)
PushNotification๋ FCM ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ธฐ ์ํ ์ ์ฒด ๋ฉ์์ง ๊ตฌ์กฐ๋ฅผ ์ ์ํ๋ ํด๋์ค์์.
- data๋ NotiModel ๊ฐ์ฒด
- to๋ FCM์์ ์ฌ์ฉ์ ๊ธฐ๊ธฐ๋ฅผ ์๋ณํ๋ token๊ฐ์ ๋๊ฒจ์ค์
3๏ธโฃtestPush ํจ์
private fun testPush(notification:PushNotification)= CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitInstance.api.postNotification(notification)
if(response.isSuccessful) {
Log.d("testPush์ฑ๊ณต","๋ ํธ๋กํ")
}
else {
Log.e("์คํจ","${response.errorBody()?.string()}")
Log.e("์คํจ","${response.code()}")
Log.e("์คํจ","${response.headers()}")
}
}
catch (e:Exception){
e.printStackTrace()
}
}
testPush ํจ์๋ RetrofitInstance ์์ฑํ์ฌ retrofit์ ํตํด FCM ๋ฉ์์ง๋ฅผ ์๋ฒ๋ก ๋ณด๋ด๋ ๋น๋๊ธฐ ํจ์์์.
์ฌ๊ธฐ์ Retrofit์ ์๋๋ก์ด๋์์ ์๋ฒ์ ํต์ ํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋งํด์. ์๋ ์ฝ๋ ์ค๋ช ์ ์ ์ฒด ํ๋ฆ์ ์ดํดํ ํ์ ๋ณด๋ ๊ฒ์ ์ถ์ฒ๋๋ ค์!
์ฝ๋ ์ค๋ช
CoroutineScope(Dispatchers.IO).launch { ... }
- CoroutineScope๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ์์ ์ ์ฒ๋ฆฌํด์.
- Dispatchers.IO ๋ I/O์์
์ ์ํํ๊ธฐ ์ ํฉํ ๋์คํจ์ฒ๋ก ๋คํธ์ํฌ ์์
๊ณผ ๊ฐ์ I/O์ค์ฌ์ ์์
์ ์ฌ์ฉ๋์ด์.
- Dispatchers๋ ?
- ์ฝ๋ฃจํด์ ๋ํด์๋ ๋ค์ ํฌ์คํ ์์ ๋ ์์ธํ ์๋ ค๋๋ฆด๊ฒ์!
- launch๋ ๋น๋๊ธฐ ์ฝ๋ ๋ธ๋ก์ ์คํํ๋ฉฐ, ์์ ์ด ์๋ฃ๋๊ธฐ ์ ์ ๋ค์ ์ฝ๋๋ก ์งํ๋์ง ์์์.
- val response = RetrofitInstance.api.postNotification(notification)
- postNotification์ Retrofit์ ์ ์๋ API ์ธํฐํ์ด์ค ๋ฉ์๋๋ก ์๋ฒ์ POST์์ฒญ์ ์ํํด์.
- ์๋ฒ์ ์๋ต์ response์ ์ ์ฅ๋ผ์.
4๏ธโฃRetrofitInstance
class RetrofitInstance {
companion object {
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val api = retrofit.create(NotiAPI::class.java)
}
}
์ด ํด๋์ค๋ Retrofit์ ์ด์ฉํ์ฌ ์๋ฒ ํต์ ์ ์ํ ์ธ์คํด์ค๋ฅผ ์ ๊ณตํ๋ ํด๋์ค์์.
- ์ฝ๋ ์ค๋ช
1๏ธโฃ companion object ๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๊ธํค ํจํด์ผ๋ก Retrofit ์ธ์คํด์ค๋ฅผ ๊ด๋ฆฌํด์. ์ด๋ ํตํด ์ฑ ์ ์ฒด์์ ํ๋์ Retrofit ์ธ์คํด์ค๋ง์ ์ฌ์ฉํ ์ ์์ด์.
๐ lazy๋?
ํด๋น ๋ณ์๊ฐ ์ฒ์์ผ๋ก ์ฌ์ฉ๋ ๋๊น์ง ์ด๊ธฐํ๋ฅผ ์ง์ฐ์ํฌ ์ ์์ด์
ํ์ํ ์์ ์ ๋ณ์๋ฅผ ์ด๊ธฐํํ ์ ์์ด ์์์ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๋ต๋๋ค.
2๏ธโฃretrofit ๋ณ์
Retrofit ๋น๋ ํจํด์ ์ฌ์ฉํ์ฌ ์์ฑ๋ Retrofit ์ธ์คํด์ค๋ฅผ ์ ์ฅํ๋ ๋ณ์์์.
addConverterFactory ๋ฅผ ํตํด Gson ๋ณํ๊ธฐ๋ฅผ ์ถ๊ฐํ์ฌ JSON ๋ฐ์ดํฐ๋ฅผ Kotlin ๊ฐ์ฒด๋ก ๋ณํํ์ด์.
build( ) ๋ฅผ ํตํด ์ค์ ์ด ์๋ฃ๋ Retrofit ์ธ์คํด์ค๋ฅผ ์์ฑํด์ฃผ์์ด์.
3๏ธโฃ api ๋ณ์
api ๋ณ์์๋ ์์ฑ๋ retrofit ์ธํฐํ์ด์ค๋ฅผ ์ ์ฅํ์ด์
retrofit.create(NotiAPI::class.java) ๋ฅผ ํธ์ถํ์ฌ Retrofit์์ ์์ฑ๋ ์ธ์คํด์ค๋ก๋ถํฐ NotiAPI ๊ตฌํ์ฒด๋ฅผ ์์ฑํด์.
retrofit.create()๋ฅผ ํตํด Retrofit์ ์ ์๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ด์.
์ด ๋ ๋๊ฒจ์ฃผ๋ NotiAPI๋ Retrofit์ ์ฌ์ฉํ์ฌ FCM ์๋ฒ์ ํต์ ํ๊ธฐ ์ํ API ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ ๊ฒ์ด์์.
FCM ์๋ฒ์ ํต์ ํ ๋ ์ฌ์ฉ๋๋ ์๋ํฌ์ธํธ ๋ฐ ๋ฉ์๋๋ฅผ ๋ช ์ํด์ค์
5๏ธโฃ NotiAPI ์ธํฐํ์ด์ค
interface NotiAPI {
// 1
@Headers("Authorization: key=$SERVER_KEY", "Content-Type:$CONTENT_TYPE")
// 2
@POST("/fcm/send")
// 3
suspend fun postNotification(@Body notification: PushNotification): Response<ResponseBody>
}
์ด์ ๋ง์ง๋ง์ผ๋ก NotiAPI ์ธํฐํ์ด์ค์ ๋ํด ์์๋ณผ๊ฒ์.
์ด ์ธํฐํ์ด์ค๋ FCM ์๋ฒ์ ํธ์ ์๋ฆผ์ ์ ์กํ๊ธฐ ์ํ HTTP ์์ฒญ์ ์ ์ํ๋ ์ธํฐํ์ด์ค์ ๋๋ค.
์ฝ๋ ์ค๋ช
1๏ธโฃ@Header์ด๋ ธํ ์ด์
- HTTP ์์ฒญ ํค๋ ์ค์
- "Authorization: key=$SERVER_KEY"
- FCM ์๋ฒ์ ํต์ ํ๊ธฐ ์ํ ์๋ฒํค๋ฅผ ํค๋์ ์ถ๊ฐ
- "Content-Type:$CONTENT_TYPE"
- HTTP ์์ฒญ์ ์ปจํ ์ธ ํ์ ์ค์
2๏ธโฃ@POST("/fcm/send")
- POST ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ fcm/send ์๋ํฌ์ธํธ์ ์์ฒญ์ ์ ์กํด์
- FCM์์๋ ํธ์์๋ฆผ์ ์ ์กํฉ๋๋ค.
โ ๊ทธ๋ฅ fcm/send ๋ผ๊ณ ํด๋ ๋์ผํ๊ฒ ๋์ํด์.
3๏ธโฃpostNotification ๋ฉ์๋
- ํธ์ ์๋ฆผ์ ์ ์กํ๊ธฐ ์ํ ๋น๋๊ธฐํจ์์์
- suspend ํค์๋๋ ์ฝ๋ฃจํด์์ ํธ์ถ๋ ์ ์์์ ์๋ฏธํด์.
suspend fun postNotification(@Body notification: PushNotification): Response<ResponseBody>
- @Body notification : HTTP ์์ฒญ์ ๋ณธ๋ฌธ์ ํด๋นํ๋ฉฐ, PushNotification ๊ฐ์ฒด๋ฅผ ์ ์กํด์.
- ์ด ๊ฐ์ฒด๋ ํธ์ ์๋ฆผ์ ๋ด๊ณ ์์ด์
- Response<ResponseBody>
- Response๋ ์๋ฒ์์ ๋ฐ์ HTTP ์๋ต์ ๋ํ๋ด๋ ํด๋์ค์์
- Responces<T>์์ T๋ ์๋ฒ๊ฐ ์๋ต ๋ณธ๋ฌธ์ผ๋ก ์ ์กํ ๋ฐ์ดํฐ์ ํํ๋ฅผ ๋งํด์.
- Response์๋ HTTP ์ํ ์ฝ๋, ์๋ต ํค๋, ๋ณธ๋ฌธ ๋ฑ์ด ํฌํจ๋์ด์์ด์.
- ResponseBody๋ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ ์๋ต์ ๋ณธ๋ฌธ์ ์ฒด๋ฅผ ๋ํ๋ด๋ ํด๋์ค์์.
- Response ํด๋์ค์ body( ) ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ResponseBody ๊ฐ์ฒด๋ฅผ ์ป์ ์ ์์ด์.
- Response๋ ์๋ฒ์์ ๋ฐ์ HTTP ์๋ต์ ๋ํ๋ด๋ ํด๋์ค์์
์ ๋ฆฌํ๊ธฐ
๋ง๋ฌด๋ฆฌํ๋ฉฐ
์ด๋ ๊ฒ ์ธํ ์๋ฃ ์๋ฆผ ๊ธฐ๋ฅ์ FCM์ผ๋ก ๊ตฌํํ๋ ์ฌ์ ์ ๋ํ ์ด์ผ๊ธฐ๋ฅผ ํด๋ณด์์ด์.
์ ๋ FCM์ ์ค์ ๋ก ๊ตฌํํ๊ธฐ ์ ์๋ ์๋ฒ๋ฅผ ์ง์ ๊ตฌํํด์ผํ๋๊ฑด์ง ์ด๋ป๊ฒ ํต์ ์ ํ๊ณ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ผํ๋ ๊ฑด์ธ์ง ์ดํดํ๊ธฐ๊ฐ ์ด๋ ค์ ์ด์. ์ด๋ ๊ฒ ์ค์ ๋ก ๊ตฌํํด๋ณด๋ฉฐ ๊ฐ์ ์ก์ ์ ์์๋ต๋๋ค ๐
์กฐ๊ธ์ด๋๋ง ๊ธ์ ์ฝ๋ ์ฌ๋ฌ๋ถ๋ค์ด FCM์ ์ดํดํ๋๋ฐ ๋์์ด ๋์์ผ๋ฉด ์ข๊ฒ ๋ค์ ใ ใ
์ง๋ฌธ์ ์ธ์ ๋ ๋๊ธ์ ํตํด ๋จ๊ฒจ์ฃผ์ธ์.
FCM ๊ฐ๋ฐ ์ฌ์ ์ ์ฌ๊ธฐ์ ๋ง๋ฌด๋ฆฌํ๊ณ ๋ค์ ํฌ์คํ ์ผ๋ก ์ฐพ์์ฌ๊ฒ์! ๐
๊ทธ๋ผ ์ด๋ง ์ด์ด ๐พ

ํจ๊ป ๋ณด๋ฉด ์ข์ ์ฌ์ดํธ
https://firebase.google.com/docs/cloud-messaging/android/client?hl=ko
Android์์ Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง ํด๋ผ์ด์ธํธ ์ฑ ์ค์
Google I/O 2023์์ Firebase์ ์ฃผ์ ์์์ ํ์ธํ์ธ์. ์์ธํ ์์๋ณด๊ธฐ ์๊ฒฌ ๋ณด๋ด๊ธฐ Android์์ Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง ํด๋ผ์ด์ธํธ ์ฑ ์ค์ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ
firebase.google.com
'๐ค2024 ์๋๋ก์ด๋ > ๊ธฐ์์ฌ ํ๋ก์ ํธ ๊ธฐ๋ก' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Compose์์ ๊ตฌ์ฑ๋ณ๊ฒฝ ์ ์ ์ฅ๋์ง ์๋ ๋ฌธ์ ํด๊ฒฐํ๊ธฐ (2) | 2024.01.21 |
---|---|
android Flow ์์๋ณด๊ธฐ (2) | 2024.01.21 |
compose์ preferences datastore ์ด์ฉํ๊ธฐ (1) | 2024.01.18 |
kotlin coroutines basic ๊ณต์๋ฌธ์ ์ฝ์ด๋ณด๊ธฐ (0) | 2024.01.17 |
๐Android FCM ์ ์ฉ๊ธฐ 1ํ : Notification ํํค์ณ๋ณด๊ธฐ (1) | 2024.01.06 |