B4J Question FCM Notifications and Server handler

yiankos1

Well-Known Member
Licensed User
Longtime User
Hello,

I am trying to send notifications by creating a handler "sendNotification". If i put all code from b4j example then, only the first notification arrives correctly and the second throws a verification error:

b4j code:
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
    If req.Method <> "POST" Then
        resp.SendError(500, "Method not supported!")
        Return
    End If
        
    Private StreamReader As TextReader
    StreamReader.Initialize(req.InputStream)
    Private parser As JSONParser
    parser.Initialize(StreamReader.ReadAll)
    Private m As Map = parser.NextObject
    
    If m.Get("typeNotification") = "" Then
        resp.SendError(500,"Missing parameter!")
        Return
    End If
    
    Private Token As String = GetTokenValue(Main.ServiceAccountFilePath)
    
    sendNotification(m,token)
End Sub

Private Sub GetTokenValue (FilePath As String) As String
    Dim GoogleCredentials As JavaObject
    GoogleCredentials.InitializeStatic("com.google.auth.oauth2.GoogleCredentials")
    Dim Credentials As JavaObject = GoogleCredentials.RunMethodJO("fromStream", Array(File.OpenInput(FilePath, ""))) _
        .RunMethod("createScoped", Array(Array As String("https://www.googleapis.com/auth/firebase.messaging")))
    Credentials.RunMethod("refreshIfExpired", Null)
    Return Credentials.RunMethodJO("getAccessToken", Null).RunMethod("getTokenValue", Null)
End Sub

Sub sendNotification(dataMap As Map, Token As String) As ResumableSub
    
    Dim Job As HttpJob
    Job.Initialize("", Me)
    Dim data As Map = CreateMap("title": dataMap.Get("title"), "body": dataMap.Get("text"), "userSent": dataMap.Get("userSent"), _
    "userTo": dataMap.Get("userTo"),"typeNotification": dataMap.Get("typeNotification"),"selectedIdWorkout" : dataMap.Get("selectedIdWorkout"), _
    "chatID" : dataMap.Get("chatID"),"chatMessageID" : dataMap.Get("chatMessageID"))
    
    'Checking if device is ios or android in order to send the correct notification
    Private sql As SQL = DBM.GetSQL
    Private os As Int = sql.ExecQuerySingleResult2("SELECT os FROM users WHERE id = ?", Array As String(dataMap.Get("userTo")))
    DBM.CloseSQL(sql)
    
'    If dataMap.Get("userTo").As(String).StartsWith("ios_") Then
    If os = 1 Then
        'B4i
        Dim message As Map = CreateMap("topic": "ios_" & dataMap.Get("userTo"), "data": data)
        Dim Badge As Int = 0
        Dim iosalert As Map =  CreateMap("title": dataMap.Get("title"), "body": dataMap.Get("text"))
        message.Put("notification", iosalert)
        message.Put("apns", CreateMap("headers": _
            CreateMap("apns-priority": "10"), _
            "payload": CreateMap("aps": CreateMap("sound":"default", "badge": Badge))))
    Else
'        B4A
        Dim message As Map = CreateMap("topic": dataMap.Get("userTo"), "data": data)
        message.Put("android", CreateMap("priority": "high"))
    End If
    Dim jg As JSONGenerator
    jg.Initialize(CreateMap("message": message))
    Log(jg.ToPrettyString(4))
    Job.PostString($"https://fcm.googleapis.com/v1/projects/${Main.ProjectId}/messages:send"$, jg.ToString)
    Job.GetRequest.SetContentType("application/json;charset=UTF-8")
    Job.GetRequest.SetHeader("Authorization", "Bearer " & Token)
    Wait For (Job) JobDone(Job As HttpJob)
    If Job.Success Then
        Log(Job.GetString)
    End If
    Job.Release

End Sub

server output:
B4X:
{
    "message": {
        "data": {
            "chatID": "06348c10-cf37-11ef-9bd1-52894e2c9ee7",
            "typeNotification": "chat",
            "chatMessageID": "5ef8e312-9e8c-a169-8491-68efeff6303f",
            "title": "Lorem Ipsum",
            "body": "e",
            "selectedIdWorkout": null,
            "userTo": "d5b3ac4f-f191-11ee-ae89-a8a159113189",
            "userSent": "e4e8eec0-5a42-11ef-a763-52894e2c9ee7"
        },
        "android": {
            "priority": "high"
        },
        "topic": "d5b3ac4f-f191-11ee-ae89-a8a159113189"
    }
}
Command: query: getLastChatMessage, took: 43ms, client=[0:0:0:0:0:0:0:1]
Command: batch (size=1), took: 31ms, client=[0:0:0:0:0:0:0:1]
Command: batch (size=1), took: 68ms, client=[0:0:0:0:0:0:0:1]
Command: batch (size=1), took: 88ms, client=[0:0:0:0:0:0:0:1]
{
    "message": {
        "data": {
            "chatID": "06348c10-cf37-11ef-9bd1-52894e2c9ee7",
            "typeNotification": "chat",
            "chatMessageID": "aa0fb71c-483c-aa47-8338-498347c0a749",
            "title": "Lorem Ipsum",
            "body": "poo",
            "selectedIdWorkout": null,
            "userTo": "d5b3ac4f-f191-11ee-ae89-a8a159113189",
            "userSent": "e4e8eec0-5a42-11ef-a763-52894e2c9ee7"
        },
        "android": {
            "priority": "high"
        },
        "topic": "d5b3ac4f-f191-11ee-ae89-a8a159113189"
    }
}
ResponseError. Reason: , Response: {
  "error": {
    "code": 401,
    "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "status": "UNAUTHENTICATED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "CREDENTIALS_MISSING",
        "domain": "googleapis.com",
        "metadata": {
          "method": "google.firebase.fcm.v1.FcmService.SendMessage",
          "service": "fcm.googleapis.com"
        }
      }
    ]
  }
}

The only way that i get it working is by putting the sendNotification sub at main page and calling it with CallSubDelayed3(Main,"sendNotification",m,token). The problem here is that after a couple of days it stops to send everything without any error. Just does not send.

B4X gpt mentions these:

Any ideas are welcome.

Thank you for your time.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
 
Upvote 0

yiankos1

Well-Known Member
Licensed User
Longtime User
Hello Erel,

Even with StartMessageLoop and StopMessageLoop, the "UNAUTHENTICATED" error keeps showing at the second and after notification.

If I did not send notification for a couple of minutes, then notifcation sent successfully (just for that one, not the next one again).

The only working solution is by doing single theard handler:
B4X:
srvr.AddHandler("/notification", "sendNotification", True)

Are there any other downturns except from queuing notifications?

Thank you for your time.
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…