이번엔 메시지 API를 만들어서 Postman을 통해 토큰과 타이틀, 바디를 보내 폰으로 알림을 받는 과정을 정리해보려 합니다. Firebase프로젝트를 생성하는 과정은 이전 게시글을 참고하시면 됩니다.
[FCM]Firebase Cloud Messaging 수신하기
Android에서 Firebase 클라우드 메시징 클라이언트 앱 설정 Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보
huzit.tistory.com
시작하기 전
어느 정도 배웠던 기억을 살려서 구현한 거라 최신 빌드에 맞지 않을 수 있습니다. 참고 정도로만 보시는 걸 추천드려요.
Springboot 프로젝트 생성
프로젝트를 생성할 때 언어는 코틀린, 빌드 툴은 Gradle로 해줬습니다. 언어와 빌드 툴은 안드로이드와 동일하게 진행하겠습니다.
의존성은 롬복과 SpringWeb 정도만 추가해줍니다.
Firebase SDK 설치
프로젝트 빌드가 완료되었다면 한 번 실행해준 뒤 FirebaseSDK를 설치해줍니다.
키를 넣을 패키지를 만든 후 알기쉬운 이름으로 변경해서 넣어줍니다.
이제 프로젝트의 build.gradle.kts로 가서 의존성을 추가해줍니다.
//FirebaseSDK
implementation("com.google.firebase:firebase-admin:9.1.1")
//OkHttp
implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.10")
//jackson
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
http통신을 이용해야하므로 OkHttp의 의존성도 추가해주고 Jackson 어노테이션을 하나 쓸 것이므로 같이 해줍니다.
여기까지가 프로젝트 설정입니다. 절반 왔네요
기능 구현에 앞서 앞으로 해야할 것을 정리하자면
- FCMService 클래스 작성
- 통신을 위한 DTO 작성
- Controller작성
이 있습니다. 간단한 것 부터 시작해보죠.
DTO 작성
FCM 메시지 정보 | Firebase 클라우드 메시징
Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보기 이 페이지는 Cloud Translation API를 통해 번역되었습니
firebase.google.com
우리가 보내야 하는 메시지는 단순 알림 메시지이며 JSON 형식은 다음과 같습니다. (다른 메시지는 위 링크에서 확인할 수 있습니다)
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}
}
메시지 안에 토큰, 알림(타이틀, 내용) 이 들어가 있는 구조입니다.
따라서 Message와 Notification 데이터 클래스를 만들어줍니다.
@JsonIgnoreProperties(ignoreUnknown = true)
data class FCMMessage(
var message: Message,
var validate_only: Boolean = false,
){
data class Message(
var token: String = "",
var notification: Notification,
)
data class Notification(
var title: String = "",
var body: String = "",
var image: String = "",
)
}
@JsonIgnoreProperties(ignoreUnknown = true) 어노테이션으로 데이터 클래스에 선언되지 않은 프로퍼티에 맵핑이 되면 예외를 발생시키지 말고 무시하도록 만듭니다.
이제 Request로 부터 보낼 대상의 토큰, 타이틀, 내용을 받을 데이터 클래스가 필요합니다.
data class RequestDTO(
val targetToken: String,
val title: String,
val body: String
)
Controller에서 RequestBody를 통해 받기 위함이므로 RequestDTO 만들어줍니다.
FCM Service 클래스 작성
서비스 클래스의 메서드는 3가지 입니다.
getAccessToken()
자격 증명을 이용하여 액세스 토큰을 발행하는 메서드입니다.
@Service
class FCMService{
...
@Autowired
lateinit var resourceLoader: ResourceLoader
@Throws(IOException::class)
private fun getAccessToken(): String{
// val firebaseConfigPath = "src/main/resources/serviceKey/firebaseServiceKey.json"
// val inputStream = FileInputStream(firebaseConfigPath)
val firebaseConfigPath = "classpath:/serviceKey/firebaseServiceKey.json"
val inputStream = resourceLoader.getResource(firebaseConfigPath).inputStream
val googleCredentials = GoogleCredentials
.fromStream(inputStream)
.createScoped(listOf("https://www.googleapis.com/auth/cloud-platform"))
googleCredentials.refreshIfExpired()
return googleCredentials.accessToken.tokenValue
}
}
createScoped에는 Google API의 OAuth 2.0 범위를 위한 스코프를 입력해야 합니다.
Google API의 OAuth 2.0 범위 | Authorization | Google Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 Google API의 OAuth 2.0 범위 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이
developers.google.com
우리가 필요한 건 FirebaseCloudMessaging이므로 둘 중 하나를 넣어주면 됩니다.
여기서 의문점이 하나 생깁니다. "주석은 왜 했지?"
// val firebaseConfigPath = "src/main/resources/serviceKey/firebaseServiceKey.json"
// val inputStream = FileInputStream(firebaseConfigPath)
val firebaseConfigPath = "classpath:/serviceKey/firebaseServiceKey.json"
val inputStream = resourceLoader.getResource(firebaseConfigPath).inputStream
두 코드의 차이는 절대 경로 / 상대 경로 , FileInputStream / resourceLoader입니다.
일단 FileInputStream에 대해 간단히 설명하자면 하드 디스크 상에 존재하는 파일로부터 바이트 단위를 입력받는 클래스입니다. 여기서 하드 디스크가 가장 중요합니다.
저는 Docker를 통해 라즈베리 파이로 배포할 생각이기 때문에 .jar로 압축해야 합니다. 하드 디스크가 아니라 jar에서 읽어야 합니다.
그래서 FileInputStream이 아니라 ResourceLoader를 통해 읽고 있는 것입니다.
또한 주석처럼 절대 경로를 넣게 되면 파일 자체를 찾을 수 없으므로 classpath를 이용해서 상대 경로로 넣어줬습니다
makeMessage()
@Service
class FCMService{
...
//메시지 생성
private fun makeMessage(targetToken: String, title: String, body: String): String{
val notification = FCMMessage.Notification(title, body)
val message = FCMMessage.Message(targetToken, notification)
val fcmMessage = FCMMessage(message = message)
val objectValue = jacksonObjectMapper().writeValueAsString(fcmMessage)
return objectValue
}
}
앞서 생성한 데이터 클래스에 맞춰서 객체를 만들어 주면 됩니다. jacksonObjectmapper를 통해 생성한 FCMMessage객체를 JSON형식으로 변경해줍니다.
sendMessageTo()
@Service
class FCMService{
private val SERVER_ENDPOINT = "https://fcm.googleapis.com/v1/projects/내 파베 프로젝트 ID/messages:send"
...
//메시지 전송
@Throws(IOException::class)
fun sendMessageTo(targetToken: String, title: String, body: String){
lateinit var response: Response
try {
val message = makeMessage(targetToken, title, body)
val requestBody = message.toRequestBody("application/json; charset=utf-8".toMediaType())
val request = Request.Builder()
.url(SERVER_ENDPOINT)
.post(requestBody)
.addHeader(HttpHeaders.CONTENT_TYPE, "application/json; UTF-8")
.addHeader(HttpHeaders.AUTHORIZATION, "Bearer ${getAccessToken()}")
.build()
response = OkHttpClient().newCall(request).execute()
println(response.body.toString())
} finally{
response.body.close()
}
}
...
}
서버 엔드포인트로 앞서 생성한 파이어 베이스 프로젝트 id를 지정해주면 됩니다.
Controller
컨트롤러 차례입니다.
@RestController
@RequiredArgsConstructor
class NotificationController {
@Autowired
val fCMService = FCMService()
@Throws(IOException::class)
@PostMapping("/sendNotification")
fun sendNotification(@RequestBody requestDTO: RequestDTO): ResponseEntity<String> {
fCMService.sendMessageTo(requestDTO.targetToken, requestDTO.title, requestDTO.body)
return ResponseEntity.ok().build()
}
@GetMapping("/{testValue}")
fun test(@PathVariable(name = "testValue") test : String): String{
return "testvalue is $test"
}
}
실행
이제 실행해봅시다. 로컬에서 테스트하므로 Postman을 설치해줘야 합니다.
Get은 정상적으로 작동되는 것을 볼 수 있습니다. 이제 Post로 보내볼 차례입니다.
우리가 RequestDto에서 작성한 대로 Body를 작성해줘야 합니다. getAccessToken()으로 발급한 토큰을 넣어주면 됩니다.
이제 토큰 발급한 기기를 보면 알림이 온 것을 확인할 수 있습니다.
만약 알림이 오지 않는다면 앱을 껐다 켜보거나 알림에서 알림 일시중지 무시를 해 보시면 됩니다.
마치며
만약 도커에 올려서 배포하고 싶다면 아래 게시글을 참고하시면 됩니다.
[docker]kotlin + SpringBoot를 Docker Hub에 올리기(feat.FCM)
1. 스프링 부트 프로젝트 만들기 빌드 툴은 gradle이므로 build.gradle.kts에 spring-boot-starter-web 의존성을 추가하고 테스트할 수 있는 맵핑을 하나 만들어주면 됩니다. @RestController @RequiredArgsConstructor clas
huzit.tistory.com
다음은 Retrofit2를 이용해서 RestAPI 통신하는 어플 제작 과정을 올리겠습니다.
참고
[SpringBoot] FCM을 통해 Push알림 보내보기
( + 진행 당시, 기능 구현에 집중하다보니 전체적인 설계나 코드가 클린하지 못할 수 있으니 이 부분은 리팩토링 하면서 적용하시면 좋을 것 같아요! :) ) 현재 참여하고 있는 IT연합 동아리 YAPP에
sol-devlog.tistory.com
'안드로이드 > Firebase' 카테고리의 다른 글
Firebase Crashlytics 시작하기 (0) | 2023.04.14 |
---|---|
Firebase 시작하기 (0) | 2023.04.14 |
[FCM] Retrofit2로 API통신하기 (0) | 2022.11.16 |
[FCM]Firebase Cloud Messaging 수신하기 (0) | 2022.11.11 |
파이어베이스로 구글 소셜로그인 (0) | 2022.06.13 |