Android Tutorial FCM Push-Messages: Foreground/Background/Data/Notification

KMatle

Expert
Licensed User
Erel made a fantastic example how to use Google's FCM Push-Messaging:
https://www.b4x.com/android/forum/t...-messages-firebase-cloud-messaging-fcm.67716/

To complete the example, it is important to know FCM works in detail. Otherwise you wonder why your messages "don't arrive", etc.

IMPORTANT: Check if your app will not be stopped when it will send back to the background or swiped! (See Android settings -> apps -> your app -> energy, etc.)

1. What kind of message do you send to the device (Notification, Data or both)? Yes, this is important!

Each message is sent by the REST API. Here you use a JSON to provide the data you want to send.

Notification (it is just a notification without any data)

B4X:
{
   "to" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...", 'device token
    "notification" : {
      "body" : "great match!",
      "title" : "Portugal vs. Denmark",
      "icon" : "myicon"
    }
Data (there is just data, no notification)

B4X:
{
"data" : {
"Nick" : "Mario",
"Room" : "PortugalVSDenmark"
}
}
Both (notification AND data)

B4X:
'{
'    "to" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
'    "notification" : {
'      "body" : "great match!",
'      "title" : "Portugal vs. Denmark",
'      "icon" : "myicon"
'    }
'    "data" : {
'      "Nick" : "Mario",
'      "Room" : "PortugalVSDenmark"
'    }
'  }
2. In what state is your App?

Foreground (the app is visible and running)
Background (the app is not visible and is paused OR it has been whiped by the user)

3. Take a look at this table to see how the service (app) behaves:
fcm.JPG


Example:

a) If the App is in the foreground AND you send just a notification, all the data will be available in "onMessageReceived" ONLY (there's no DATA part!)

b) If the App is in the Background AND you send both (notification AND data) the notification will appear automatically in the system tray (also known as THE NOTIFICATION but without sound, etc.). As you can read you don't need to throw an extra notification! When the user clicks on it, the data wil be vailable in the extras of the intent.

c) If your send data only, everything is available in "onMessageReceived" only. So you need to throw a notification on your own.

4. What is"onMessageReceived", "System tray" and "extras of the intent" exactly?

a) onMessageReceived

B4X:
Sub fm_MessageArrived (Message As RemoteMessage)
in the FirebaseMessaging service

b) System tray

Where notifications for the users live

c) extras of the intent

B4X:
Sub Activity_Resume
    Dim in As Intent
    in = Activity.GetStartingIntent
    Log(in.GetExtra("data"))
End Sub
With

B4X:
Log(in.ExtrasToString)
all "extras" are shown like:

B4X:
Bundle[{google.sent_time=1479841813693, data=8, from=3xxxxxxxx, google.message_id=0:xxxxxxxxxx%yyyyyyyyy, collapse_key=your.package.name}]
I've sent just an "8" as data

in the main activity (= the app will be started "by intent" = Click on the notification)

So now you know how f.e. WhatsApp does it :)

5. Good to know

TO, DATA and NOTIFICATION are keywords! Under this structure you can add maps with any name (key/value) as you like, even 1000 will do (except you don't exceed the max length of 4 KB).
 
Last edited:

peacemaker

Expert
Licensed User
Super ! THanks for the topic.
Just not enough a code sample to send "both" in your format, including the "notification" map.
Will try...
 

KMatle

Expert
Licensed User
code sample
Here you go:

B4X:
Dim m As Map = CreateMap("to": $"${Devtoken}"$) 'this will send the message to ONE device
   Dim noti As Map = CreateMap("body":"Notification","title":"New Notification")
   Dim data As Map = CreateMap("Name": "Michael","Age": "36" )
   m.Put("notification", noti) 'keyword!
   m.Put("data", data) 'keyword!
   Dim jg As JSONGenerator
   jg.Initialize(m)
   Job.Tag=jg
   Job.PostString("https://fcm.googleapis.com/fcm/send", jg.ToString)
   Job.GetRequest.SetContentType("application/json;charset=UTF-8")
   Job.GetRequest.SetHeader("Authorization", "key=" & API_KEY)
Just comment one of the "m.putxxxx" (to send notification OR data) or just keep it to send both

This creates the following JSON structure:

B4X:
'{
'    "to" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...", 'dev-token
'    "notification" : {
'      "body" : "Notification",
'      "title" : "New Notification"
'    }
'    "data" : {
'    "Name" : "Michael", "Age" : "36"
'    }
'  }
 

An Schi

Well-Known Member
Licensed User
Thank you very much!
I think erel should include this in the main topic or at least link to it.
 

Erel

Administrator
Staff member
Licensed User
To complete the example, it is important to know FCM works in detail. Otherwise you wonder why your messages "don't arrive", etc.
I think erel should include this in the main topic or at least link to it.
The B4J code from my example will work in all cases. You don't need to change it.
 

peacemaker

Expert
Licensed User
It seems, Erel was right - this sending sample anyway is not delivered to my devices, if the app is killed for sure...
 

peacemaker

Expert
Licensed User
Hm, yes, you are right - Erel's sample is to a topic, i'm test this variant.
And i think that most usual variant - the mass notificating all the users - so, it must be sent to the common topic.
 

Luiz Orlandini

Member
Licensed User
That's fantastic!!! Although I have a problem when trying to lead with the Intent Extras and firing a new Activity.

The main activity it's killed by OS, which prevents me to redirect to another screen/activity.

Any ideas about how to deal with that?

Posting here b/c I figure out that it's related about the main topic here.

Cheers.
 

peacemaker

Expert
Licensed User
So, is there the full universal code sample to get push by any way ?

I use such, but, seems, it's not all covered:

1) FirebaseMessaging.bas:
B4X:
Sub fm_MessageArrived (Message As RemoteMessage)
    Log("Message arrived")
    Log($"Message data: ${Message.GetData}"$)
   
    Dim title As String = Message.GetData.Get("title")
    Dim body As String = Message.GetData.Get("body")

    If title.ToLowerCase = "null" Then
        title = Application.LabelName
    End If
   
    If body.ToLowerCase = "null" Then
        body = "New push alert"
    End If
    Dim n As Notification
    n.Initialize
    n.Icon = "icon"
    n.SetInfo(title, body, Main)
    n.Notify(1)
   
    Log(Message.GetData)    '(MyMap) {message=hi, new order, requestId=12345678}
    'check keys of Data here
    Dim requestId As String = Message.GetData.Get("requestId")
    If requestId <> "" Then
        orders.CurOrderID = requestId
        StartActivity(orders)
    End If
End Sub
2) Main activity:
B4X:
Sub Process_Globals
Dim PrevIntent As Intent
End Sub

Sub Activity_Resume
    'push
    Dim pushIntent As Intent = Activity.GetStartingIntent
    'Log(pushIntent.ExtrasToString)
    If Activity.GetStartingIntent = PrevIntent Then
        'intent already handled
    Else
        PrevIntent = Activity.GetStartingIntent
        If pushIntent.HasExtra("requestId") Then
            Dim requestId As String = pushIntent.GetExtra("requestId")
            'Log("push from Main: " & requestId)
            If requestId <> "" Then
                orders.CurOrderID = requestId
                StartActivity(orders)
            End If
        End If
    End If
End Sub
Seems, if app is killed - no push delivered.
 

peacemaker

Expert
Licensed User
If app was started for the very first time, and then killed, or device is rebooted (app without autostart service) - no push in these 2 variants ?
 

ELCHARO

Member
Licensed User
Erel:
Is this a way to receive from gmail acount when a new message arrive?
Are a way? or i need to read mail in predefined time gap?
Thanks
 

aeric

Well-Known Member
Licensed User
You should search the forum or start a new thread in question section.
 
Top