04
21

서버 없이 FCM을 보내고 싶어서 CloudFunction을 사용해보기로 했다. 우선 Firebase 프로젝트의 요금제를 Blaze로 올려야 하고, 터미널에  아래 명령어를 입력해서 관리도구를 받아야한다.

# 초기 설정

npm을 설치했다는 가정하에 진행한다.

npm install -g firebase-tools

gloabl로 사용할 firebase CLI 툴을 설치한다.

firebase login

로그인을 해준다. 무슨 문제가 생기면 firebase logout으로 다시 로그인 하는 것도 좋아보인다.

firebase init functions

firebase functions을 쓸거니까 이걸 초기화 해준다. 예시를 한 세번은 따라해봤는데, firestore를 활용한 방법이 너무 오류가 많이난다... 내가 잘 몰라서 그럴 거라 믿고 firestore말고 realtime-database를 사용했다.

functions를 해주면 폴더가 하나 생기고, 함수를 관리할 파일인 index.js가 생긴다.(python으로 선택했다면 main.py다)

# Realtime-database에 토큰을 저장하는 메서드

exports.saveFCMToken = functions.onCall(async (request) => {
  // 사용자의 UID와 FCM 토큰을 요청에서 받아옴
  const data = request.data;
  const { uid, fcmToken } = data;

  // 요청을 보낸 사용자의 UID가 없을 경우 에러 반환
  if (!request.auth) {
    throw new functions.HttpsError(
      "unauthenticated",
      "인증되지 않은 사용자입니다."
    );
  }

  // 요청을 보낸 사용자의 UID와 받아온 UID가 일치하지 않을 경우 에러 반환
  if (uid !== request.auth.uid) {
    throw new functions.HttpsError(
      "permission-denied",
      "접근 권한이 없습니다."
    );
  }

  try {
    // Realtime Database에 FCM 토큰 저장
    await admin.database().ref(`fcmTokens/${uid}`).set(fcmToken);
    return { result: "success" };
  } catch (error) {
    logger.error("FCM 토큰 저장 중 오류:", error);
    throw new functions.HttpsError(
      "internal",
      "FCM 토큰을 저장하는 중에 오류가 발생했습니다."
    );
  }
});

기준은 CloudFunctoin V2다.

안드로이드 프로젝트에서 호출하는 방식은 아래와 같다.

fun uploadToken(uid: String, token: String) {
            val data = hashMapOf(
                "uid" to uid,
                "fcmToken" to token,
            )
            if (auth.currentUser == null){
                val functions = Firebase.functions

                functions
                    .getHttpsCallable("saveFCMToken")
                    .call(data)
                    .continueWith { task ->
                        if (task.isSuccessful) {
                            val res = task.result
                            Log.d(TAG, "onResponse: $res")
                        } else {
                            val exception = task.exception
                            Log.e(TAG, "Firebase Cloud Function 호출 실패: $exception")
                        }
                    }
            }
        }

함수 이름으로 호출할 수 있다. 당연히 firebase function dependency를 추가해줘야한다. 인증정보가 있을경우(uid)에 token을 realtime db에 저장하도록 작성했다. 계속 중복호출을 막기위해서 uid가 null인 경우에만 인증정보 등록하는 김에 토큰정보까지 등록했다.

# FirebaseMessagingError: Exactly one of topic, token or condition is required

이건 매개변수에 제대로된 값이 안들어가서 그렇다. 전송할 대상, FCM 토큰, 대상의 조건을 설정해야되는데, 내가 FCM토큰을 주지 않아서 발생한 에러메시지다.

 

https://stackoverflow.com/questions/60170040/firebase-admin-sdk-fcm-error-exactly-one-of-topic-token-or-condition-is-require

 

Firebase admin SDK FCM error Exactly one of topic, token or condition is required

I am fixing an error message which occurred, but it also used to work before. I am sending FCM notification with multiple tokens and am getting the following error 0|api | 2020-2-11 13:26:26 [

stackoverflow.com

# com.google.firebase.functions.FirebaseFunctionsException:Response is not valid JSON object.

이건 리턴값이 JSON형태랑 그냥 String형태랑 섞여있어서 생긴 문제다. 그냥 상태값에 대한 메시지도 JSON으로 맵핑해주니까 사라졌다.

  ################################################################
  res.status(200).json({ success: true, message: "알림 전송 완료" });
  } catch (error) {
    logger.error("알림 전송 중 오류 발생:", error);
    res.status(500).json({ success: false, message: "알림 전송 실패" });
  }

# Response is missing data field.

fcm을 보내는데, field에 data로 이름붙은 게 없다고 내뱉는 에러다...  찾아보니 똑같이 화내는 사람이 있어서 재밌는 이슈였다.

https://csiandal.medium.com/firebase-function-error-response-is-missing-data-field-2c27768e0bd

 

Firebase Function Error: Response is missing data field.

It’s a fucking problem.

csiandal.medium.com

 

 

 

 

 

도움이 됐다면 댓글이나 공감 버튼 한 번씩 누르고 가주세요! 로그인 안해도 됩니다 ^_^

 

반응형
COMMENT