skip to Main Content

In Firebase Functions, success logs are checked,
but Firebase onMessageReceived is not called

When another user subscribes to a specific topic,
I know I can send messages through that topic.
I just make the topic dynamic so other users can subscribe to it,
The function is looking at the real-time database as an update,
Contains a command to send a specific alarm message to that topic when the number of messages increases.

Here is the part of Unity C# script.

private void Start()
{
    // Firebase 초기화
    FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
    {
        var dependencyStatus = task.Result;
        if (dependencyStatus == DependencyStatus.Available)
        {
            // Firebase 메시징 시작
            FirebaseMessaging.TokenRegistrationOnInitEnabled = true;
            FirebaseMessaging.TokenReceived += OnTokenReceived;
            FirebaseMessaging.MessageReceived += OnMessageReceived;
        }
        else
        {
            Debug.LogError($"Firebase 초기화 실패: {dependencyStatus}");
        }
    });
}

public void SubscribeAsyncGeoLocation(string geoLocation)
{
    geoLocation = geoLocation.Replace("+", "_");
    Debug.Log("SubscribeAsyncGeoLocation geoLocation : " + geoLocation);
    FirebaseMessaging.SubscribeAsync($"{geoLocation}");
    Debug.Log("SubscribeAsyncGeoLocation(string geoLocation)");
}

private void OnMessageReceived(object sender, MessageReceivedEventArgs e)
{
    Debug.Log("Received a new message:");

    var notification = e.Message.Notification;
    var data = e.Message.Data;

    // 알림 메시지 표시
    if (notification != null)
    {
        Debug.Log($"Title: {notification.Title}");
        Debug.Log($"Body: {notification.Body}");
    }

    // 데이터 처리
    if (data != null)
    {
        foreach (var key in data.Keys)
        {
            Debug.Log($"{key}: {data[key]}");
        }
    }
}

Here is index.ts from Firebase Consoles:

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import serviceAccount from "../service-account.json";

// Firebase Admin SDK 초기화
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount as admin.ServiceAccount),
});

// FCM 인스턴스 가져오기
const fcm = admin.messaging();

export const onMessageUpdate = functions.database
  .ref("/geoRooms/{geoLocation}/messageCount")
  .onUpdate(async (change, context) => {
    functions.logger.log("onMessageUpdate");
    functions.logger.log(`change.after.val(): ${change.after.val()}`);
    functions.logger.log(`change.before.val(): ${change.before.val()}`);

    let geoLocation = context.params.geoLocation;
    const geoLocationParts = geoLocation.split("+");
    const latitude = geoLocationParts[0].replace(/bdotb/g, ".");
    const longitude = geoLocationParts[1].replace(/bdotb/g, ".");

    functions.logger.log(`geoLocation: ${geoLocation}`);
    functions.logger.log(`latitude: ${latitude}`);
    functions.logger.log(`longitude: ${longitude}`);

    const before = change.before.val();
    const after = change.after.val();

    if (after > before) {
      const payload = {
        notification: {
          title: `${latitude}, ${longitude}`,
          body: "New message in your place",
        },
        data: {
          click_action: `********://message?${latitude}?${longitude}`,
        },
      };

      geoLocation = geoLocation.replace("+", "_");
      const topicGeoLocation = `/topics/${geoLocation}`;
      functions.logger.log(`topicGeoLocation : ${topicGeoLocation}`);

      try {
        await fcm.sendToTopic(topicGeoLocation, payload);
        functions.logger.log("메시지를 성공적으로 보냈습니다.");
      } catch (error) {
        functions.logger.log("메시지 보내기 중 오류가 발생했습니다:", error);
      }
    }

    // 메시지 전송 후에 로그 출력
    functions.logger.log("메시지 전송과정이 완료되었습니다.");
  });

2

Answers


  1. Chosen as BEST ANSWER

    I couldn't subscribe with Unity code, so I decided to process it with Firebase Function TypeScript. It goes well. I am attaching part of the code. The Google Firebase team definitely needs to overhaul the Unity code. I hope the documentation says at least that it doesn't work anymore. please.

    public void SubscribeAsyncGeoLocation(string geoLocation)
        {
        
            geoLocation = geoLocation.Replace("+", "_");
            Debug.Log("SubscribeAsyncGeoLocation geoLocation : " + geoLocation);
    
            string topicGeoLocation = $"/topics/{geoLocation}";
    
            string url = "https://**********.cloudfunctions.net/subscribeTopic";
    
            // 요청에 필요한 데이터 구성
            var formData = new WWWForm();
            formData.AddField("userId", userId);
            formData.AddField("topic", topicGeoLocation);
    
            // 요청 보내기
            UnityWebRequest request = UnityWebRequest.Post(url, formData);
            request.SendWebRequest();
    
            // 응답 처리
            if (request.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError("Failed to send message: " + request.error);
            }
            else
            {
                if (request.responseCode >= 200 && request.responseCode < 300)
                {
                    Debug.Log("Message sent successfully");
                }
                else
                {
                    Debug.LogError("Failed to send message. Response code: " + request.responseCode);
                }
            }
        }
    

    Here is the firebase function typescript.

    export const subscribeTopic = functions.https.onRequest(async (req, res) => {
      const topic = req.body.topic as string;
      const userId = req.body.userId as string;
    
      functions.logger.log(`userId: ${userId}`);
      functions.logger.log(`topic: ${topic}`);
    
      // 사용자 아이디를 기반으로 토큰 검색
      const tokenSnapshot =
      await admin.database().ref(`users/${userId}/token`).once("value");
      const token = tokenSnapshot.val();
    
      if (!token) {
        res.status(404).send("User token not found");
        return;
      }
    
      fcm.subscribeToTopic(token as string, topic as string)
        .then((response) => {
          // See the MessagingTopicManagementResponse reference documentation
          // for the contents of response.
          console.log("Successfully subscribed to topic: ", response);
        })
        .catch((error) => {
          console.log("Error subscribing to topic: ", error);
        });
    });
    

  2. I haven’t tried your code but the problem is most probably due to the fact you don’t return a Promise (or a value) in order to indicate to the Cloud Function platform that all the asynchronous work has completed. More detail on this key point in the Firebase documentation.

    In addition it seems that you don’t declare the fcm object (used in await fcm.sendToTopic(topicGeoLocation, payload);). So you should do await admin.messaging().sendToTopic(topicGeoLocation, payload); (or declare fcm like const fcm = admin.messaging()).

    So you should adapt your code as follows:

    export const onMessageUpdate = functions.database
      .ref("/geoRooms/{geoLocation}/messageCount")
      .onUpdate(async (change, context) => {
    
        // ...
    
        const before = change.before.val();
        const after = change.after.val();
    
        if (after > before) {
          const payload = {
            notification: {
              title: `${latitude}, ${longitude}`,
              body: "New message in your place",
            },
            data: {
              click_action: `********://message?${latitude}?${longitude}`,
            },
          };
    
          geoLocation = geoLocation.replace("+", "_");
          const topicGeoLocation = `/topics/${geoLocation}`;
          functions.logger.log(`topicGeoLocation : ${topicGeoLocation}`);
    
          try {
            await admin.messaging().sendToTopic(topicGeoLocation, payload);
            functions.logger.log("메시지를 성공적으로 보냈습니다.");
            return true;  <==== See here
          } catch (error) {
            functions.logger.log("메시지 보내기 중 오류가 발생했습니다:", error);
            return true;  <==== See here
          }
        } else {
            return true;  <==== See here
        }
    
      });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search