B4A Library FirebaseNotifications - Push messages / Firebase Cloud Messaging (FCM)

Status
Not open for further replies.
Updated tutorial: https://www.b4x.com/android/forum/threads/b4x-firebase-push-notifications-2023.148715/


Clarification: The nice thing about FCM is that your app doesn't need to run in order to receive messages. The FirebaseMessaging receiver will be started by the OS when a new message arrives.
It is not a real issue, but if the user closed your app with a "force close" from the device settings then messages will not arrive, until the app is started again.
On some misbehaving devices, killing the app with a swipe will also cause messages not to arrive, until the app is started again.

Firebase Cloud Messaging service is a layer above Google Cloud Messaging service.
It makes it simple to add support for push messages.

Sending messages is done with a simple HTTP request. It is also possible to send message from the Firebase console, though it is not very useful and is actually more complicated than using the REST api.

1. The first step is to follow the Firebase integration tutorial:
https://www.b4x.com/android/forum/threads/integrating-firebase-services.67692/

Make sure to add the Notifications snippet.
You should also reference FirebaseAnalytics

2. Add a Receiver named FirebaseMessaging to your app (must be this name):
B4X:
Sub Process_Globals
    Private fm As FirebaseMessaging
End Sub

Private Sub Receiver_Receive (FirstTime As Boolean, StartingIntent As Intent)
    If FirstTime Then
        fm.Initialize("fm")
    End If
    fm.HandleIntent(StartingIntent)
End Sub

Public Sub SubscribeToTopics
    fm.SubscribeToTopic("general")
End Sub

Sub fm_MessageArrived (Message As RemoteMessage)
    Log("Message arrived")
    Log($"Message data: ${Message.GetData}"$)
    Dim n2 As Notification
    n2.Initialize2(n2.IMPORTANCE_DEFAULT)
    n2.Icon = "icon"
    n2.SetInfo(Message.GetData.Get("title"), Message.GetData.Get("body"), Main)
    n2.Notify(1)  
End Sub

Sub fm_TokenRefresh (Token As String)
    Log("TokenRefresh: " & Token)
End Sub

fm_MessageArrived will be raised whenever a message is received. In this case we show a notification. You can do whatever you need.

We call SubscribeToTopics from the starter service to make sure that the app will be subscribed when it starts:
B4X:
'Starter service
Sub Process_Globals

End Sub

Sub Service_Create
   CallSubDelayed(FirebaseMessaging, "SubscribeToTopics")
End Sub

Now we can send messages to a "topic" and all the subscribed devices will receive it.

See the code in the attached B4J tool. Note that the API_KEY should be set in the B4J code. It shouldn't be distributed in your app.

API_KEY is the server key from:

SS-2017-04-07_08.10.47.png


A simple non-ui B4J program is attached.

Note that messages sent from Firebase Console will not arrive in some cases. Use the B4J code to test it.
 

Attachments

  • B4J-SendingTool.zip
    1.1 KB · Views: 899
Last edited:

ilan

Expert
Licensed User
Longtime User
Hi

As far as I understand this library ( FirebaseNotification ) is just for push a notify to users , but how can I send a message to an user ? ( without app_key , because it is secrect key and we can't use it in the source code ( client side ))

Regards

what do you mean with message? SMS?

when you send the notify its up to you how to show it to the user you can show it as a notification or in another way. (like when user open the app show msgbox)
 

alimanam3386

Active Member
Licensed User
Longtime User
what do you mean with message? SMS?

when you send the notify its up to you how to show it to the user you can show it as a notification or in another way. (like when user open the app show msgbox)

Thank you, I want send a pm ( like whatsapp or telegram messangers ) userTouser pm , I know by this library I just can handel and get messages from server app. But how can I send pm without secret key ???
 

ilan

Expert
Licensed User
Longtime User
I know by this library I just can handel and get messages from server app.

yes thats what you can do.

i dont know if it is possible to send directly a msg to whatsapp or telegram from a third party application.
 

ilan

Expert
Licensed User
Longtime User

DonManfred

Expert
Licensed User
Longtime User
But how can I send pm without secret key ???
you cant.

Use a server side man-in-the-middle (php for example). Send a request to your server (php) and the script there will send the Notification. The key is stored savety on your server...
No need to store the TOKEN in source.
 

sasidhar

Active Member
Licensed User
Longtime User
hi,

I followed the procedure mentioned for firebug notifications on mobile. when I run Jar file i get error mentioned below. same project in the example i have used. API key changed, compiled the project, FCMPush.jar file created. same using command prompt when i run i get the error. please let me know the issue.

C:\Softwares\basic4android-Licensed\Projects\Samples\NFC\UltraLightReader\Limousine\Limousine b4x6.0\FCMPush\Objects>java -jar FCMPush.jar
Picked up _JAVA_OPTIONS: -Xmx1g -Xms1g
httpjob._postbytes (java line: 215)
java.lang.NoClassDefFoundError: javafx/application/Platform
at anywheresoftware.b4j.objects.FxBA.postRunnable(FxBA.java:17)
at anywheresoftware.b4a.keywords.Common.CallSubDelayed4(Common.java:500)
at anywheresoftware.b4a.keywords.Common.CallSubDelayed2(Common.java:484)
at b4j.example.httpjob._postbytes(httpjob.java:215)
at b4j.example.httpjob._poststring(httpjob.java:261)
at b4j.example.main._sendmessage(main.java:109)
at b4j.example.main._appstart(main.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:93)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:84)
at b4j.example.main.main(main.java:29)
Caused by: java.lang.ClassNotFoundException: javafx.application.Platform
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang

thanks
sasidhar
 

Anser

Well-Known Member
Licensed User
Longtime User
Question : If i need to send a message for just one selected device out of 100 devices, how can I do that?

Answered by Erel : Either subscribe each device to a unique topic or use your own server with the token ids (see FirebaseMessaging.Token).

While using GCM, in the PushService Service we used to make use of the following event Sub to get the Token ID

B4X:
Sub HandleRegistrationResult(Intent As Intent)
    If Intent.HasExtra("error") Then
        Log("Error: " & Intent.GetExtra("error"))
        ToastMessageShow("Error: " & Intent.GetExtra("error"), True)
    Else If Intent.HasExtra("unregistered") Then
        Log("Reached HandleRegistrationResult Unregister")
        'Remove GCM ID details from My Table

    Else If Intent.HasExtra("registration_id") Then
        Log("Reached HandleRegistrationResult registration ID")
        Dim rid As String
        rid = Intent.GetExtra("registration_id")
        Log("GCM RegID from PushService : " & rid )
        'Update My Table with the newly received GCM Registration ID
     
    End If
End Sub

Here you have mentioned about the FirebaseMessaging.Token, Is there any even to get the TokenID like as shown above in case of Gcm
OR
The Token ID is available immediately after Subscribing to a topic
For eg:
B4X:
Sub Process_Globals
   Private fm As FirebaseMessaging
End Sub

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

Public Sub SubscribeToTopics
   fm.SubscribeToTopic("general") 'you can subscribe to more topics
   fm.Token 'Will I get the Token ID from here
End Sub

Or Should I have some Sub in the FireBaseMessaging Service as follows
B4X:
Sub fm_TokenRefresh(cTokenID as String)
   Log( cTokenID )
End Sub
 

Anser

Well-Known Member
Licensed User
Longtime User
fm.Token will return the current token. TokenRefresh will fire whenever the token changes.
Thanks for confirming.

So, incase if the token changes, is that the right way to get the refreshed token ?. I mean the code in FireBaseMessaging Service as posted below
B4X:
Sub fm_TokenRefresh(cTokenID as String)
   Log( cTokenID )
End Sub

Do I have to take care of the above in FireBaseMessaging Service ?
 

Anser

Well-Known Member
Licensed User
Longtime User
I am just converting my existing code that used GCM to FCM

When we receive Push Messages In GCM, in the Sub MessageArrived (Intent As Intent), we used to check whether a particular property/data was there in the sent message using the following code

B4X:
Dim cMsg As String
Dim UseBigPictureStyle As Boolean
UseBigPictureStyle = False
If Intent.HasExtra("message") Then cMsg = Intent.GetExtra("message")
If Intent.HasExtra("UseBigPictureStyle") Then UseBigPictureStyle = True

How do I execute the same when I receive Message in FCM in the Sub fm_MessageArrived (Message As RemoteMessage)
The following works well if the received message contains a Key, but fails when the received message does not contain the key. For eg
B4X:
Dim cMsg As String
Dim UseBigPictureStyle As Boolean
UseBigPictureStyle = False
If Message.GetData.Get("message") <> "" Then cMsg = Message.GetData.Get("message")
'If  "UseBigPictureStyle" is not included then the code freezes there
If Message.GetData.Get("UseBigPictureStyle") <> "" Then UseBigPictureStyle = True

If I include UseBigPictureStyle data in the message that I send, then everything works fine, but if it doesn't contain then the code does not get executed beyond the point
If Message.GetData.Get("UseBigPictureStyle") <> "" Then UseBigPictureStyle = True


EDIT : Sorry for the confusion. Forgot that it is a Map, the solution is
B4X:
If Message.GetData.ContainsKey("UseBigPictureStyle") Then UseBigPictureStyle = True

Regards

Anser
 
Last edited:

alimanam3386

Active Member
Licensed User
Longtime User
Hi

When I use Web Socket Server(B4J) to send a message with FCM I get an error :

B4X:
{
  "data": {
  "receivertoken": "",
  "pmsenderid": "SenderId HERE",
  "body": "hi my friend !"
  },
  "to": "AcQQ4p4WI1g:APA91bGhKhiydgATbIkNgzu5F6WGF5pm_HxLM9lNSA7bHM0dg89sCbpgpEQc3srf4J92oZkyKd3DId5HqroBmWMWkGCVMHYvxOY1nYrcV6GnTJ--x2T61igugVdDwgCM-D-OJPzZThze"
}

java.lang.RuntimeException: java.lang.IllegalStateException: Toolkit not initialized
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:114)
   at anywheresoftware.b4a.BA.raiseEvent(BA.java:84)
   at anywheresoftware.b4j.object.WebSocketModule$Adapter$1.run(WebSocketModule.java:126)
   at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:30)
   at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:26)
   at anywheresoftware.b4j.object.WebSocketModule$Adapter$ThreadHandler.run(WebSocketModule.java:195)
   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
   at java.util.concurrent.FutureTask.run(FutureTask.java:266)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
   at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
   at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
   at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
   at javafx.application.Platform.runLater(Platform.java:83)
   at anywheresoftware.b4j.objects.FxBA.postRunnable(FxBA.java:17)
   at anywheresoftware.b4a.keywords.Common.CallSubDelayed4(Common.java:500)
   at anywheresoftware.b4a.keywords.Common.CallSubDelayed2(Common.java:484)
   at b4j.example.httpjob._postbytes(httpjob.java:215)
   at b4j.example.httpjob._poststring(httpjob.java:261)
   at b4j.example.b4a._v6(b4a.java:123)
   at b4j.example.b4a._pm_message(b4a.java:79)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   at java.lang.reflect.Method.invoke(Method.java:498)
   at anywheresoftware.b4a.BA.raiseEvent2(BA.java:93)
   ... 10 more

I attached my source code , how can I solve this error ?
 

Attachments

  • WebSocketWithFirebaseCloudMessaging.zip
    1.6 KB · Views: 351

dar2o3

Active Member
Licensed User
Longtime User
I can get a list of topics to which I subscribe?
I have an application in which customers subscribe to receive information by provinces, you can subscribe or unsubscribe as they want, I would check when there are no clients subscribed to a particular topic this topic no longer exists.

Is there a limit when creating new topics?
 
Status
Not open for further replies.
Top