캡스톤 실습에 필요한 푸쉬 알림을 구현하기 위해서 Spring-boot 를 이용해 서버를 만들고 android 클라이언트 에서 test 하기로 하였다.
FCM 주요 용어
클라이언트 앱
Notification Server
Client App
Provider
Sender ID
Registration Token
FCM 프로젝트 생성
android studio app단에 다음과 같이 google-servieces.json 파일을 넣어준다.
루트 수준의 build.grdle 파일에 classpath 추가
implementation 'com.google.firebase:firebase-messaging:21.1.0'
}
apply plugin: 'com.google.gms.google-services'
<application>
<service android:name=".MyFirebaseMessagingService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
</application>
AndroidManifest.xml 파일에 service를 추가해주고 인텐트 필터 설정.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onNewToken(String token){
Log.d("FCM Log", "Registration token: "+token);
}
}
프로젝트 설정에서 새 비공개 키
를 생성하여 파일을 resource 밑에 넣어준다.
@Component
@RequiredArgsConstructor
public class FirebaseCloudMessageService {
private final String API_URL = "https://fcm.googleapis.com/v1/projects/{프로젝트 ID}/messages:send"; // 요청을 보낼 엔드포인트
private final ObjectMapper objectMapper;
public void sendMessageTo(String targetToken, String title, String body) throws IOException {
String message = makeMessage(targetToken, title, body);
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = RequestBody.create(message,
MediaType.get("application/json; charset=utf-8"));
Request request = new Request.Builder()
.url(API_URL)
.post(requestBody)
.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + getAccessToken())
.addHeader(HttpHeaders.CONTENT_TYPE, "application/json; UTF-8")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
private String makeMessage(String targetToken, String title, String body) throws JsonParseException, JsonProcessingException {
FcmMessage fcmMessage = FcmMessage.builder()
.message(FcmMessage.Message.builder()
.token(targetToken)
.notification(FcmMessage.Notification.builder()
.title(title)
.body(body)
.image(null)
.build()
).build()).validateOnly(false).build();
return objectMapper.writeValueAsString(fcmMessage);
}
}
@Component
@RequiredArgsConstructor
public class FirebaseCloudMessageService {
private String getAccessToken() throws IOException {
String firebaseConfigPath = "firebase/firebase_service_key.json";
GoogleCredentials googleCredentials = GoogleCredentials
.fromStream(new ClassPathResource(firebaseConfigPath).getInputStream())
.createScoped(List.of("https://www.googleapis.com/auth/cloud-platform")); //엑세스 토큰 받아오기
googleCredentials.refreshIfExpired();
return googleCredentials.getAccessToken().getTokenValue();
}
}
@RestController
@RequiredArgsConstructor
public class MainController {
private final FirebaseCloudMessageService firebaseCloudMessageService;
@PostMapping("/api/fcm")
public ResponseEntity pushMessage(@RequestBody RequestDTO requestDTO) throws IOException {
System.out.println(requestDTO.getTargetToken() + " "
+requestDTO.getTitle() + " " + requestDTO.getBody());
firebaseCloudMessageService.sendMessageTo(
requestDTO.getTargetToken(),
requestDTO.getTitle(),
requestDTO.getBody());
return ResponseEntity.ok().build();
}
}
@Builder
@AllArgsConstructor
@Getter
public class FcmMessage {
private boolean validateOnly;
private Message message;
@Builder
@AllArgsConstructor
@Getter
public static class Message {
private Notification notification;
private String token;
}
@Builder
@AllArgsConstructor
@Getter
public static class Notification {
private String title;
private String body;
private String image;
}
}
@Getter
@Setter
public class RequestDTO {
private String targetToken;
private String title;
private String body;
}
참고블로그
https://galid1.tistory.com/740
https://sol-devlog.tistory.com/11