Google Firebase 연동

FCM 아키텍처

image-20230919091002062

build.gradle

implementation 'com.google.auth:google-auth-library-oauth2-http:1.19.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.7.1'
implementation 'com.google.firebase:firebase-admin:9.2.0'

비공개키 생성

https://console.firebase.google.com/u/1/project/digital-receipt-f71ef/settings/serviceaccounts/adminsdk?hl=ko

image-20230918161839534

새 비공개 키 생성을 하면 json 파일이 다운로드 되어지는데, 다운로드 받은 json 파일을 프로젝트 폴더로 옮긴다.

image-20230918162053818

프로젝트 ID확인

https://console.cloud.google.com/projectselector2/settings/general?authuser=1&hl=ko&pli=1

Fcm 메시지 전송

푸시 메시지 형식

IOS 푸시 헤더

Http v1 API

각 언어 별 라이브러리

푸시 메시지를 전송하는 방법은 admin을 이용하는 방법과 구글 인증라이브러리를 사용하는 방법 두 가지가 있다.

admin 방식

String serviceAccountKeyPath = "firebase/digital-receipt-f71ef-firebase-adminsdk-v7ayu-604f77e641.json";
Resource serviceAccountResource = new ClassPathResource(serviceAccountKeyPath);
InputStream serviceAccountStream = serviceAccountResource.getInputStream();

FirebaseOptions options = new FirebaseOptions.Builder()
        .setCredentials(GoogleCredentials.fromStream(serviceAccountStream))
        .setProjectId("프로젝트 ID")
        .build();

FirebaseApp.initializeApp(options);

com.google.firebase.messaging.Message message = ...

String response = FirebaseMessaging.getInstance().send(message);
System.out.println(response);
// projects/digital-receipt-f71ef/messages/0:1695101285793698%726136130198d25a

구글 인증 라이브러리 방식

admin 방식과 다르게 Message를 커스마이징한 객체를 만들어줘야 한다. 그 이유는 resttemplate로 json을 직접 전송해야되는데 com.google.firebase.messaging.Message를 그대로 json으로 변환하면 json 형식이 맞지 않기 때문이다. 따라서 다음과 같이 메시지 클래스를 생성하여 사용한다.

@Getter
@AllArgsConstructor
@Builder
public class FcmMessage {

    @JsonProperty("validate_only")
    private boolean validateOnly; 
    private Message message;

    @Getter
    @AllArgsConstructor
    @Builder
    public static class Message {
        private final String token;
        private final Data data;
        private final Notification notification;
        private final AndroidConfig android;
        private final ApnsConfig apns;
    }

    @Getter
    @AllArgsConstructor
    @Builder
    public static class Data {
        private final String message;
        private final String time;
        @JsonProperty("registration_ids")
        private final String registrationIds;
        private final String senderId;
    }

    @Getter
    @AllArgsConstructor
    @Builder
    public static class Notification {
        private final String title;
        private final String body;
    }
}
{
    final String fcmEndPoint = "https://fcm.googleapis.com/v1/projects/프로젝트ID/messages:send";
    FcmMessage fcmMessage = ...
    String accessToken = getAccessToken();


    final HttpHeaders httpHeaders = new HttpHeaders();
    final String PREFIX_ACCESS_TOKEN = "Bearer ";
    httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
    httpHeaders.add(HttpHeaders.AUTHORIZATION, PREFIX_ACCESS_TOKEN + accessToken);

    final HttpEntity<String> httpEntity = new HttpEntity<>(gson.toJson(fcmMessage), httpHeaders);
    restTemplate.exchange(
                    fcmEndPoint,
                    HttpMethod.POST,
                    httpEntity,
                    String.class);
}

private String getAccessToken() {
        try {
            String serviceAccountKeyPath = "firebase/digital-receipt-f71ef-firebase-adminsdk-v7ayu-604f77e641.json";
            Resource serviceAccountResource = new ClassPathResource(serviceAccountKeyPath);
            InputStream serviceAccountStream = serviceAccountResource.getInputStream();

            GoogleCredentials googleCredentials = GoogleCredentials
                    .fromStream(serviceAccountStream)
                    .createScoped(List.of("https://www.googleapis.com/auth/cloud-platform"));

            googleCredentials.refreshIfExpired();

            return googleCredentials.getAccessToken().getTokenValue();
        } catch (Exception e) {
            return null;
        }
    }

기타 참조

https://medium.com/@rajdeepify/push-notifications-using-springboot-and-firebase-cloud-messaging-ad136746c57e

https://velog.io/@komment/Spring-Boot-APNs%EA%B3%BC-FCM%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%98%EC%97%AC-%ED%91%B8%EC%8B%9C%EC%95%8C%EB%A6%BC-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-2-an9sfu6s

댓글남기기