-
[๊ตฌํ] Spring์์ Firebase ํธ์์๋ฆผ ๊ตฌํํ๊ธฐSPRING/PROJECT 2023. 9. 26. 02:52
ํธ์ ์๋ ๊น๊น Firebase ํ๋ก์ ํธ ์ธํ ํ๊ธฐ
https://firebase.google.com/?hl=ko
Firebase | Googleโs Mobile and Web App Development Platform
Discover Firebase, Googleโs mobile and web app development platform that helps developers build apps and games that users will love.
firebase.google.com
firebase ์น์ฌ์ดํธ์ ๋ค์ด๊ฐ์ ํ๋ก์ ํธ๋ฅผ ์์ฑํด์ค๋๋ค.
ํ๋ก์ ํธ ์ด๋ฆ๊ณผ ํจ๊ป ํ๋ซํผ์ ์ ํํ๋ผ๊ณ ๋์ต๋๋ค.
ํ์ํ client ํ๋ซํผ์ ๋ชจ๋ ์์ฑํด์ ์ํค๋ ๋๋ก ํด์ค์๋ค. ์ด ๋ client ๊ฐ๋ฐ์๋ค์๊ฒ ์ด๊ฑฐ ๋ณด๊ณ ์ด๋๋ก ํด๋ฌ๋ผ๊ณ ํฉ์๋ค!
iOS๋ ๋ฒ๋คID๋ผ๋ ๊ฒ์ ์ ๋ ฅํด์ผ ํด์
https://firebase.google.com/docs/ios/setup?hl=koApple ํ๋ก์ ํธ์ Firebase ์ถ๊ฐ | Firebase for Apple platforms
Google I/O 2023์์ Firebase์ ์ฃผ์ ์์์ ํ์ธํ์ธ์. ์์ธํ ์์๋ณด๊ธฐ ์๊ฒฌ ๋ณด๋ด๊ธฐ Apple ํ๋ก์ ํธ์ Firebase ์ถ๊ฐ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์
firebase.google.com
๊ทธ๋ค๋ firebase ์๋์ ๋ฐ์ ๋ฐ์์ ์ด ํ์ํ๋๊น ์ด๊ฒ๋ ๋งํด์ฃผ๊ธฐ
์ ๋ ์ ์ค๋์ง ํ์ธํ๊ธฐ ์ํด Android Studio๋ฅผ ๊น์์ ์ง์ ํด๋ดค๋ต๋๋ค...ใ Android ์ธํ ํ๊ธฐ
์ผ๋จ Firebase ์ ์ฑ ์ถ๊ฐํ ๋ google-services.json ํ์ผ ์ฃผ๋ฉด์ ์ง์ด๋ฃ์ผ๋ผ๊ณ ํ๋ค.
์ฌ๊ธฐ๋ค ๋ฃ์ด์ฃผ๋ฉด ๋ฉ๋๋ค.๋ค์ ์ฝ๋๋ค์ ์ถ๊ฐํด์ค์๋ค
build.gradledependencies { classpath 'com.google.gms:google-services:4.3.5' }
build.gradle(:app)
dependencies { ... implementation 'com.google.firebase:firebase-messaging:21.1.0' implementation 'com.google.firebase:firebase-analytics-ktx:17.3.0' } apply plugin: 'com.google.gms.google-services'
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET"/> <application ...> ... <service android:name=".MyFirebaseMessagingService" android:exported="true"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT"/> </intent-filter> </service> </application> </manifest>
//MyFirebaseMessagingService.kt class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onNewToken(token: String) { Log.d("FCM Log", "Refreshed token: $token") } override fun onMessageReceived(remoteMessage: RemoteMessage) { // TODO(developer): Handle FCM messages here. } }
Spring Boot ์ธํ
build.gradle๋ถํฐ ์์ ํด์ค๋๋ค.
implementation 'com.google.firebase:firebase-admin:6.8.1' implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.2.2'
๊ทธ๋ฆฌ๊ณ Firebase ํ๋ก์ ํธ์์ ๋ฐ์ ์ ์๋ jsonํ์ผ
์๋ ๊ฒฝ๋ก์ ๋ฃ์ด์ค๋๋ค.
๊ตฌํ
์ผ๋จ ํ์๊ฐ์ , ๋ก๊ทธ์ธ ์ DB์ device token์ ์ ์ฅํ๋ ์์ ์ด ํ์ํฉ๋๋ค.
Android ๋ fcm token์ ์ ์ฅํ๋ฉด ๋๊ตฌ์
iOS๋ device token ์ ์ฅํ๋ฉด ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฉ์ธ์ง๋ฅผ ์ ์กํ ๋, ์ ์กํ ๊ธฐ๊ธฐ๋ค์ ์ด token์ List๋ก ๋๊ฒจ์ค์ผ ํด์
FirebaseCloudMessageUtil๋ผ๋ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์- Firebase App์ ์ด๊ธฐํํ๋ initialFirebaseApp
- ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ด๋ sendMessage <- ์๋ฅผ ์ธ๋ถ์์ ์ฌ์ฉํจ์ผ๋ก์จ ํธ์์๋ฆผ์ ๋ณด๋ผ๊ฒ๋๋ค
ํฌ๊ฒ ๋ ๊ฐ์ ๋ฉ์๋๋ก ์ด๋ฃจ์ด์ง ์์ ์ ๋๋ค.
์ฒ์์๋ sendMessage ๋ฉ์๋์์ Android์ iOS๋ฅผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ํธ์์๋ฆผ์ ๋ณด๋ด๊ณ ์ ํ์ต๋๋ค.FcmMessage fcmMessage = FcmMessage.builder() .message(FcmMessage.Message.builder() .token(targetToken) .data( new LinkedHashMap<>() {{ put("type", String.valueOf(type)); }} ) .notification(FcmMessage.Notification.builder() .title(title) .body(body) .build() ).build()).validateOnly(false).build(); return objectMapper.writeValueAsString(fcmMessage);
์ด ๋ฐฉ์์ ๋ฌธ์ ์ ์ ์๋๋ก์ด๋๊ฐ ์๋์ ์์ ํ์ ๋
ํ๋ฉด์ด ์ผ์ง์ง ์์์ต๋๋คโฆ!
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ notification์ผ๋ก ๋ณด๋ด๋ฉด ์๋์ด์
๊ทธ๋ ๋ค๊ณ iOS๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ณด๋ด๋ฉด ์ ์์ ์์ ์ด ๋์ง ์๋๋ผ๊ตฌ์
๊ทธ๋์ ์ฐพ์๋ธ ๋ฐฉ๋ฒ
setAndroidConfig, setApnsConfig์ ์ด์ฉํ์ฌ ๊ฐ์์ ๋ง๊ฒ ๋ณด๋ด๊ธฐ@Component @RequiredArgsConstructor public class FirebaseCloudMessageUtil { static FirebaseApp firebaseApp; static final String firebaseAppName = "[์ฑ์ด๋ฆ]"; static final String firebaseConfigPath = "firebase/firebase_service_key.json"; //์์กด์ฑ ์ฃผ์ ์ฒ์๋ ๋ ํ ๋ฒ ํธ์ถ @PostConstruct private void initialFirebaseApp() throws IOException { FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.fromStream(new ClassPathResource(firebaseConfigPath).getInputStream())) .build(); firebaseApp = FirebaseApp.initializeApp(options, firebaseAppName); } public void sendMessage(List<String> deviceTokenToSendList, String title, String body, Map<String, String> data) { if (deviceTokenToSendList.size() > 0) { MulticastMessage message = MulticastMessage.builder() .addAllTokens(deviceTokenToSendList) .setAndroidConfig(AndroidConfig.builder() .putAllData(creatDataForAOS(title, body, data)) .build()) .setApnsConfig(ApnsConfig.builder() .putAllCustomData(createDataForiOS(data)) .setAps(Aps.builder() .setContentAvailable(true) .setAlert(ApsAlert.builder() .setTitle(title) .setBody(body) .build()) .build()) .build()) .build(); try { FirebaseMessaging.getInstance(firebaseApp).sendMulticast(message); } catch (FirebaseMessagingException e) { throw new CustomException(ResponseCode.SERVER_ERROR_FAILED_TO_SEND_FCM); } } } @NotNull private static LinkedHashMap<String, String> creatDataForAOS(String title, String body, Map<String, String> data) { LinkedHashMap<String, String> dataForAOS = new LinkedHashMap<>() {{ put(FcmDataType.TITLE.getType(), title); put(FcmDataType.BODY.getType(), body); }}; dataForAOS.putAll(data); return dataForAOS; } @NotNull private static LinkedHashMap<String, Object> createDataForiOS(Map<String, String> data) { LinkedHashMap<String, Object> dataForiOS = new LinkedHashMap<>(); dataForiOS.putAll(data); return dataForiOS; } }
deviceTokenToSendList๋ ์ ์กํ ๋๋ฐ์ด์ค ํ ํฐ๋ค์ด ๋ค์ด์๋ List!
๋จ์ฒด๋ก ํ ๋ฒ์ ๋ณด๋ด๊ธฐ ์ํด MulticastMessage๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
https://firebase.google.com/docs/cloud-messaging/send-message?hl=ko์ฑ ์๋ฒ ์ ์ก ์์ฒญ ์์ฑ | Firebase ํด๋ผ์ฐ๋ ๋ฉ์์ง
Google I/O 2023์์ Firebase์ ์ฃผ์ ์์์ ํ์ธํ์ธ์. ์์ธํ ์์๋ณด๊ธฐ ์๊ฒฌ ๋ณด๋ด๊ธฐ ์ฑ ์๋ฒ ์ ์ก ์์ฒญ ์์ฑ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. Fire
firebase.google.com
setAndroidConfig, setApnsConfig ์ค์ ํ๋ ๋ฐฉ๋ฒ์ด ๋ฌ๋ผ์ ๊ฐ์์ ๋ง์ถฐ์ง Data๋ฅผ ๋ง๋ค ์ ์๋ ๋ฉ์๋ ๋ ๊ฐ (creatDataForAOS, createDataForiOS)๋ฅผ ์ถ๊ฐํด์คฌ์ต๋๋ค.
+) FcmDataType์ ํ์ ๋ช enum ํด๋์ค์ ๋๋ค.
+) ํน์ ์ ๊ฐ๋์ง ํ์ธ์ด ํ์ํ๋ค๋ฉด message๋ฅผ ๋ก๊ทธ ์ฐ์ด ๋ณด์ธ์ฌ
์ฌ์ฉ๋ฒ!firebaseCloudMessageUtil.sendMessage({๋ฉ์ธ์ง ๋ฐ์ User๋ค device token list}, {ํธ์์๋ฆผ ์ ๋ชฉ}, {ํธ์์๋ฆผ ๋ด์ฉ}, {๋ณด๋ผ ๋ฐ์ดํฐ ํ์ , ๋ฐ์ดํฐ HashMap});
ํธ์์๋ฆผ ์ ๋ชฉ์ ๋ง ๊ทธ๋๋ก ์ ๋ชฉ
ํธ์์๋ฆผ ๋ด์ฉ์ ๋ง ๊ทธ๋๋ก ๋ด์ฉ
๋ณด๋ผ ๋ฐ์ดํฐ๋ payload, ํธ์ ์๋ฆผ์ ๋ณด์ด์ง๋ ์์ง๋ง Client ์ธก์์ ํธ์ ์๋ฆผ์ ์์ ํ์ ์ ๊บผ๋ด์ฌ ์ ์๋ ๋ฐ์ดํฐ์ ๋ชฉ๊ณผ ๋ด์ฉ ์์
LinkedHashMap<String, String> dataToSend = new LinkedHashMap<>() {{ put(FcmDataType.TYPE.getType(), String.valueOf(FcmPushType.CPR_CALL.ordinal())); put(FcmDataType.CPR_CALL_ID.getType(), String.valueOf(cprCall.getId())); }}; List<String> deviceTokenToSendPushList; do { pageable = PageRequest.of(offset, maxSize); deviceTokenToSendPushList = deviceTokenRepository.findAllDeviceTokenByUserAddressExceptCaller(cprCall.getAddress().getId(), userId, pageable); firebaseCloudMessageUtil.sendMessage( deviceTokenToSendPushList, FcmMessage.CPR_CALL_TITLE.getMessage(), cprCall.getFullAddress(), dataToSend ); offset += maxSize; } while (deviceTokenToSendPushList.size() >= maxSize);
ํ ์คํธ ํด๋ณด๊ธฐ
ํด๋ผ์ด์ธํธ ๊ฐ๋ฐ์๋ฅผ ์ง์ ๋ง๋์ง ์๊ณ ๋ ํ ์คํธ ํ๊ธฐ๊ฐ ํ๋ญ๋๋ค
ํผ์ ํ ์คํธ ํ๊ธฐ ์ํด์ ์๊น ๋ง๋ Android ํ๋ก์ ํธ๋ฅผ ๋ค์ ์ผญ์๋คclass MyFirebaseMessagingService : FirebaseMessagingService() { override fun onNewToken(token: String) { Log.d("FCM Log", "Refreshed token: $token") } 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.d("FCM LOG", "From: ${remoteMessage.from}") // Check if message contains a data payload. if (remoteMessage.data.isNotEmpty()) { Log.d("FCM LOG", "Message data payload: ${remoteMessage.data["type"]}") } // Check if message contains a notification payload. remoteMessage.notification?.let { Log.d("FCM LOG", "Message Notification Body: ${it.body}") } // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. } }
๊ฐ์ธ ๊ณต๊ธฐ๊ณ๋ฅผ ํ๋ก์ ํธ์ ๋ฑ๋กํ๊ณ , ์ด ์ฑ์ ์ค์นํด์ ์ด๋ฐ ์์ผ๋ก ๋ก๊ทธ๋ฅผ ์ฐ์ผ๋ฉฐ ํ์ธํด๋ด ์๋ค
๋!'SPRING > PROJECT' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๊ตฌํ] Spring Security ์ ์ฐ๋๋ฐ? (0) 2024.05.02 [์ ๋ณด] IntelliJ์์ Querydsl ์ธ ๋ clean build, build ํ ๋ฒ์ ์ํํ๊ธฐ (0) 2023.09.26 [๊ตฌํ] Spring์์ ์นด์นด์คํก ๋ก๊ทธ์ธ (0) 2023.09.25 [๊ตฌํ] Spring์์ ์๋ฌ๋ฅผ ๋ด๋ 3๊ฐ์ง ๋ฐฉ๋ฒ (2) 2023.04.02 [๊ตฌํ] ์คํ๋ง์ผ๋ก ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ๋งํฌ ๋ง๋ค๊ธฐ (0) 2021.12.12