Android Question FirebaseMessaging service re-start

peacemaker

Expert
Licensed User
Longtime User
HI, All

Making the FirebaseMessaging service as STICKY helps to restart it and receive push-messages after user removed the app from "recent apps list".
But not always :-(
I'm sending pushes by a customer server, using "data" key JSONed, so sending is fully OK.

But often after removing app from "recent apps" list and sending a push - i see in the log that the service is started
B4X:
** Service (firebasemessaging) Start **

but no
B4X:
Message arrived
.

How can it be - started, but not received the push message ?
 

KMatle

Expert
Licensed User
Longtime User

1. Please remove that option (STICKY). This will result in such problems.
2. Do not use any FCM code in the starter service (use another for it)
3. The service is started by Android automatically when a message arrives

i see in the log that the service is started

4. Yes, this is wanted (see #3).

but not received the push message

5. Hard to say. We need to

- see your complete code (FCM service only)
- see the code how you send the message (via OkHttpJob)
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Code is the same: https://www.b4x.com/android/forum/t...es-first-is-auto-cancelled.85552/#post-542076

Starter service just starts FirebaseMessaging service.
STICKY helps to re-start the services and going on receiving pushes. Without it - no more auto-starting FirebaseMessaging service at push (if app is removed from recent-list).

This topic is mainly for this - if user is removing an app with FB pushes from "recent apps" (and it's very easy for user) - the app must be able to get pushes later anyway, if sent. THis removing is not STOP state for app, but in fact - no messages are received.
So, it's the same common topic - never ending background push service is needed, for any app with FB pushes.
 
Last edited:
Upvote 0

KMatle

Expert
Licensed User
Longtime User
no messages are received

I did a lot of tests on my devices including "swiping". I did not have the issue of services not starting after a swipe. As I've mentioned in another thread that some users may have problems here like you and I'm not sure if it's code related or not (or depending on the type of FCM message you send background/foreground).

I will do some tests later/tomorrow and check that out with a small test project. Will report the results for Android 4, 5 and 6 in a seperate thread.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Thanks for reply.
Actually, i hate Samsung phones with their various "small features" that are not the same behaviour
I'm sending pushes by some PHP-script on customer side, that returns reply like this
B4X:
requestId = 0033
{"multicast_id":5355801556450523968,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"NotRegistered"}]}
and i always get the needed key (requestId) from RemoteMessage.GetData, not by Intent.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Hmmm, yes, user FB tokens are stored on web-server db for pushes.
And whole the day succes was =1 ! But now ...error...
But i have realised now that i'm not updating the token at "_TokenRefresh", is it often refreshed ?
 
Last edited:
Upvote 0

KMatle

Expert
Licensed User
Longtime User
I did some tests for some hours - nothing is needed in the service, just this:

B4X:
#Region  Service Attributes
    #StartAtBoot: False
#End Region

Sub Process_Globals
    Private fm As FirebaseMessaging
   
End Sub

Sub Service_Create
    fm.Initialize("fm")   
End Sub

Public Sub Subscribe
    'you can subscribe to more topics
    fm.SubscribeToTopic("nothing")
    Log(fm.Token)   
End Sub



Sub Service_Start (StartingIntent As Intent)
    If StartingIntent.IsInitialized And fm.HandleIntent(StartingIntent) Then Return

End Sub

Sub fm_MessageArrived (Message As RemoteMessage)
    'CallSubDelayed3(Main,"NewMess","System","Message arrived...")
    Log("Message arrived")
    Log($"Message data: ${Message.GetData}"$)
    Log("ID: " & Message.MessageId)
    Log("From: " & Message.From)
    Log("Collapse: " & Message.CollapseKey)
    Log(Message.GetData)
  
    Dim MessCompleteMap As Map
    MessCompleteMap=Message.GetData
   
    Dim n As Notification
    n.Initialize
    n.Icon = "icon"
    n.OnGoingEvent=False
    n.Light=True
    n.SetInfo2("FCM","Message arrived...","Info", "Main")
    n.Vibrate=False
    n.Notify(1)

End Sub

Sub Service_Destroy

End Sub

Even after hours and 10 swipes from the recent apps list everything works fine (as expected)

How I send the messages:

B4X:
Private Sub SendMessageToSingleDevice(Devtoken As String, datastring As String)
 
   Dim Job As HttpJob
   Job.Initialize("SendMessage", Me)
   Dim m As Map = CreateMap("to": $"${Devtoken}"$)
   Dim data As Map = CreateMap("data": datastring)
   m.Put("data", data)
   Dim jg As JSONGenerator
   jg.Initialize(m)
   Job.Tag=jg
   Log(jg.ToString)
   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)
  
  End Sub
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
KMatle,
Thanks much for your re-tests !
Which device models\brand\Android versions did you check ? I guess, this .... Samsung may work as it wants... comparing to other brands.

"Datastring" can be like "key1=value1,key2=value2,key3=value3" ?
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
Test devices: Huawei P8, Samsung S3 mini, Chuwi P7 and RockChip 10" tablet (Android 4, 5 and 6).

Check that there are no energy saving settings are active (like Huawei has "protected apps" -> you must switch your app to "protected" otherwise it WILL be stopped when the app is in background/screen is off). Maybe Android 7 (or e.g. Samsung has a similar setting). WhatsApp & Co. use the same logic to receive FCM messages. So no magic here.


Datastring can be anything (lists, maps, etc.). Before sending it, it will converted to a string (always done when you send data via OkHttpUtils job). Please note that FCM messages are limited to 4 KB. Anyway: FCM messages are ment to send short messages to inform the user/app that here's new data to fetch.

Example to send a map (from B4J). You can add whatever you want to the map (I've added date & time here)

B4X:
Sub SendMessageBTN_Action
    Number=Number+1
    Dim MyData As Map
    MyData.Initialize
    MyData.Put("key1","This is the data of key1")
    MyData.Put("key2","This is the data of key2")
    MyData.Put("key3","This is the data of key3")
    MyData.Put("key4","This is the data of key4")
    MyData.Put("date",DateTime.Date(DateTime.Now))
    MyData.Put("time",DateTime.time(DateTime.Now))
  
    SendMessageToSingleDevice(DevT,MyData)

End Sub

B4X:
Private Sub SendMessageToSingleDevice(Devtoken As String, MyData As Map)

   Dim Job As HttpJob
   Job.Initialize("SendMessage", Me)
 
   Dim m As Map = CreateMap("to": $"${Devtoken}"$)
   Dim data As Map = CreateMap("data": MyData)
   m.Put("data", data)
   Dim jg As JSONGenerator
   jg.Initialize(m)
   Job.Tag=jg
   Log(jg.ToString)
   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)
 
  End Sub

Note: "to" and "data" are keywords here (Google needs at least these two). Do not change it!

Inside the map named "data" you can put lists, maps, strings, etc.

In fm_MessageArrived

B4X:
Sub fm_MessageArrived (Message As RemoteMessage)
    'CallSubDelayed3(Main,"NewMess","System","Message arrived...")
    Log("Message arrived")
    Log($"Message data: ${Message.GetData}"$)
    Log("ID: " & Message.MessageId)
    Log("From: " & Message.From)
    Log("Collapse: " & Message.CollapseKey)
    Log(Message.GetData)
 
    Dim MessCompleteMap As Map
    MessCompleteMap=Message.GetData
  
    Dim MyData As Map
    MyData.Initialize
  
    Dim JSP As JSONParser
    JSP.Initialize(MessCompleteMap.get("data"))
    MyData=JSP.NextObject
    IntentDataMap=MyData
  
    Dim BodyText As String
    BodyText="New message: " & CRLF &CRLF
  
    For i=0 To MyData.Size-1
        BodyText=BodyText & MyData.GetKeyAt(i) & ": " & MyData.GetValueAt(i) & CRLF &CRLF
    Next
  
    Dim n As Notification
    n.Initialize
    n.Icon = "icon"
    n.OnGoingEvent=False
    n.Light=True
    n.SetInfo2("FCM",BodyText,"This is the tag", "Main")
    n.Vibrate=False
    n.Notify(1)

End Sub

The activity I use (even here: no additional parameters set!)

B4X:
#Region Module Attributes
    #FullScreen: False
    #IncludeTitle: false
    #ApplicationLabel: FCM Swipe
    #VersionCode: 1
    #VersionName: V1.0
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
#End Region

'Activity module
Sub Process_Globals
  
End Sub

Sub Globals
  
End Sub

Sub Activity_Create(FirstTime As Boolean)
      
    CallSubDelayed(FirebaseMessaging, "Subscribe")
  
  
End Sub

Sub Activity_Resume
   'When the user clicks on the notification you can handle it with this
    Dim in As Intent
    in = Activity.GetStartingIntent
    If in.HasExtra("Notification_Tag") Then
        Log(in.GetExtra("Notification_Tag")) 'Will log the tag
    End If

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

See the docs: There are two types of messages (Notification and data):

https://firebase.google.com/docs/cloud-messaging/concept-options

Notification (I use data messages only: better to handle)

Notification messages

For testing or for marketing and user re-engagement, you can send notification messages using the Firebase console. (please don't)

To programmatically send notification messages using the Admin SDK or the FCM protocols, set the notification key with the necessary predefined set of key-value options for the user-visible part of the notification message. For example, here is a JSON-formatted notification message in an IM app. The user can expect to see a message with the title "Portugal vs. Denmark" and the text "great match!" on the device:

{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}}

Data messages (My example uses these messages).

Data messages

Set the appropriate key with your custom key-value pairs to send a data payload to the client app. Data messages can have a 4KB maximum payload.

For example, here is a JSON-formatted message in the same IM app as above, where the information is encapsulated in the common data key and the client app is expected to interpret the content:

{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick":"Mario",
"body":"great match!",
"Room":"PortugalVSDenmark"
}
}}
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Thank you again for detailed description ! I'm sure it will be useful for community.
But i have to state anyway that at my device (Samsung A7, official ROM, Android 7) now sometimes after removing app from the recent apps list - the push is sent OK ("success":1), service is started (in log - ** Service (firebasemessaging) Start **), but no "Message arrived".
 
Last edited:
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
And found that my customer server's PHP script and your "Sub SendMessageToSingleDevice" sending the push with the result now:
B4X:
{"multicast_id":8387752217952910991,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1509558402508677%0806b3c5f9fd7ecd"}]}
but no message arrived.

But if to send by Firebase console (to the same device token) - it's received OK !
So, sending method is important ... :(
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Trouble is due to FB token empty. Sometimes. No idea why. Especially after FirebaseMessaging service is re-started - no token.
But after some re-makings - the service is re-starting and in 2-3 seconds the token is got, so, now all is working.
 
Last edited:
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
It seems to me that FB token is empty for some time just after the app version is changed.
And token is sometims not empty, but = "0", zero.
And after some time it's again working - token is again non-empty. It's not changed, but it's not returned for some time.
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
So, the final, i'm using such FirebaseMessaging service code, that works also if the app is removed from "recent apps" list.
Firebase token is "0" (zero) or empty on various devices for some time (i guess, re-registering the device on Google servers), if app's #VersionName is changed.
Saving the token (by StateManager class) is not needed, but it works now as is:

B4X:
#Region  Service Attributes
    #StartAtBoot: True
    #StartCommandReturnValue: android.app.Service.START_STICKY
#End Region

Sub Process_Globals
    Dim fm As FirebaseMessaging
    Dim Token As String
    Dim n As Notification
    Dim tim As Timer
End Sub

Sub Service_Create
    Token = StateManager.getSetting("fbtoken")
End Sub

Public Sub SubscribeToTopics
    fm.SubscribeToTopic("general") 'you can subscribe to more topics
    Log("SubscribedToTopics")
End Sub

Sub Service_Start (StartingIntent As Intent)
    If fm.IsInitialized Then
        fm = Null
    End If
    fm.Initialize("fm")
    tim.Initialize("tim", 2000) 'pause for getting the token
    tim.Enabled = True
    Log("FB.tim.Enabled = True")
    If StartingIntent.IsInitialized And fm.HandleIntent(StartingIntent) Then Return
End Sub

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")


Log(Message.GetData)    '(MyMap) {priority=high, vibration=1, body=some_text, sound=default, title=Notif_title, requestId=4454}
Dim requestId As String = Message.GetData.Get("requestId")

    orders.CurOrderID = requestId  'user's order - send and receive your keys
    orders.push = True  'flag to update the app interface for new push message
    If IsPaused(orders) Then
    Else
        CallSub(orders, "Activity_Resume")
    End If

    n.Initialize
    n.Icon = "icon"
    n.SetInfo(title, body, orders)
    n.AutoCancel = True
    n.Notify(1)

End Sub

Sub Service_Destroy
    fm.UnsubscribeFromTopic("general")
End Sub

Sub fm_TokenRefresh
    tim_Tick
End Sub

Sub tim_Tick
    If Starter.InternetConnected = False Then
        Log("FB.timer: no Internet")
        Return
    End If
    Dim a As String = fm.Token
    If a.Length > 5 Then   'token may be "0" on some devices for some time
        tim.Enabled = False
        If a <> Token Then
            Log("In Refresh " & $"Token(${fm.Token})"$)
        Else    'old existing token
            Log("In Service_Create " & $"Token(${fm.Token})"$)
        End If
        Token = a
        Dim userId As String = StateManager.GetSetting("userId")
        If userId <> "" Then    'if already registered user
            Starter.cls.Send_token   'send new token to my server
        End If
        StateManager.SetSetting("fbtoken", Token)
        StateManager.SaveSettings
    Else
        Log("FB token is empty!")
        SubscribeToTopics
        tim.Enabled = True
    End If
End Sub

Tested under Android 4.2\5\5.1\6 and 7.
 
Last edited:
Upvote 0
Top