B4J Code Snippet FREE MQTT Private Notification Push Messaging

hi b4x's communauty ,
this is my first thread on b4x forum , and i'm so happy to do this ,first excuse me for my poor english and i want to give this gift to all with a best thank's to EREL and all supervisor and teams who make this possible , i'm in b4x since 2 years , to learn all time every days , and i can tell that i'm just in 20% knowledge with the best ever programing lanquage . i've make a lot of b4a and b4j apps , there is somes in playstore , somes b4j get good success , and now i begin to add here best of my knowledge to others totaly for free to cross a thanks to EREL and all others .

for fisrt this is a tested MQTT push notification messaging with server app ( UI or not ) and receiver in client apps ( B4a/B4j ) i've not test b4i because i dont have it , the structure is very simple to learn and applies just change what you want ( broker name / room .... ) ,

* the good things in this app is to send private or global push ( send message to specific user if user for ex connect with you client app with email you can use it as txtTargetUser ) or send message to all connected users , i've test a stress and the message arrived to 31800 users same time without any problem ,
* second thing , i use AS_FloatingActionMenu and AS_Badges , the message arrive instantally and AS_Badges show badge as number of push , if click on button or label associated show.

AS_FloatingActionMenu with messages arrived and if click on message it turn to (alredy read massage) and badge turn to null , i've stor message arrived on list ( you can do it with filewrite or sql if you want )

1)this is server app :


server app:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 400
#End Region


Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private mqtt As MqttClient
    Private serializator As B4XSerializator
    Private BrokerUser As String = ""
    Private BrokerPass As String = ""
    Private BrokerName As String = "" 'ex:b4x/b4j '
    Private txtTargetUser As TextField
    Private txtMessageTitle As TextField
    Private txtMessageBody As TextField
    Private btnSend As Button
    Private xui As XUI
End Sub


Sub AppStart (Form1 As Form, Args() As String)
    ' UI Setup
    MainForm = Form1
    MainForm.RootPane.LoadLayout("MainPage")
    MainForm.Show
    mqtt.Initialize("mqtt_server", "tcp://broker you want to use : broker port ", "PushServer_" & Rnd(0, 99999))
End Sub


' Event for the "Send" button
Private Sub btnSend_Click
    Dim targetUser As String = txtTargetUser.Text
    Dim msgTitle As String = txtMessageTitle.Text
    Dim msgBody As String = txtMessageBody.Text


    If targetUser.Trim = "" And msgBody.Trim = "" Then
        xui.MsgboxAsync("Target User and Message Body cannot be empty for personal messages.", "Error")
        Return
    End If


    ' Connect to the broker if not already connected
    If Not(mqtt.Connected) Then
        Dim mo As MqttConnectOptions
        mo.Initialize(BrokerUser, BrokerPass) ' Use same credentials as your client
        mqtt.Connect2(mo)
        Wait For mqtt_Connected (Success As Boolean)
        If Not(Success) Then
            xui.MsgboxAsync("Could not connect to MQTT Broker.", "Connection Error")
            Return
        End If
    End If
    
    If targetUser.Trim <> "" Then
        ' Send to specific user
        Dim pushTopic As String = BrokerName & targetUser
        
        ' Create a structured message using a Map
        Dim messageMap As Map
        messageMap.Initialize
        messageMap.Put("title", msgTitle)
        messageMap.Put("body", msgBody)
        messageMap.Put("timestamp", DateTime.Now)
        
        ' Serialize the Map to bytes
        Dim payload() As Byte = serializator.ConvertObjectToBytes(messageMap)
        
        ' Publish the message to the specific user's topic
        mqtt.Publish(pushTopic, payload)
        Log($"Message published to topic: ${pushTopic}"$)
        
        xui.MsgboxAsync("Personal message sent to " & targetUser & " successfully!", "Success")
    Else
        ' Optionally, keep the broadcast functionality if no target user is specified
        Dim broadcastTopic As String = "fetsync/broadcast"
        
        ' Create a structured message using a Map to identify it as a broadcast
        Dim broadcastMap As Map
        broadcastMap.Initialize
        broadcastMap.Put("type", "broadcast")
        broadcastMap.Put("content", msgBody)
        
        ' Serialize the Map to bytes
        Dim broadcastPayload() As Byte = serializator.ConvertObjectToBytes(broadcastMap)
        
        ' Publish the message to the broadcast topic
        mqtt.Publish(broadcastTopic, broadcastPayload)
        Log($"Broadcast message published to topic: ${broadcastTopic}"$)
        
        xui.MsgboxAsync("Broadcast message sent successfully!", "Success")
    End If
End Sub




' This sub is required for the Wait For call, even if empty
Sub mqtt_Connected (Success As Boolean)
    Log("Server MQTT Connected: " & Success)
End Sub


' Disconnect when the app closes
Sub MainForm_CloseRequest (EventData As Event)
    If mqtt.Connected Then
        mqtt.Close
    End If
End Sub


2)and this is client app in b4j / b4x :

Client app:
Sub mqtt_Connected(Success As Boolean)

    If Success Then

        Log("βœ… Successfully connected to MQTT Broker")

        

        ' Always set PushTopic correctly with the username

        PushTopic = BrokerName&"/push/"&Labelusername.Text

        Log($"Setting PushTopic to: ${PushTopic}"$)

        

        ' Subscribe to personal push topic

        mqtt.Subscribe(PushTopic, 1)

        Log($"πŸ“± Subscribed to push topic: ${PushTopic}"$)

        

        ' Subscribe to broadcast messages

        mqtt.Subscribe(BroadcastTopic, 1)

        Log($"πŸ“’ Subscribed to broadcast topic: ${BroadcastTopic}"$)

        

        Log("Push Receiver - " & Labelusername.Text & " (Connected)")

    Else

        Log("❌ Failed to connect to MQTT Broker: " & LastException.Message)

    End If

End Sub







Sub mqtt_messagearrived(Topic As String, Payload() As Byte)

    Log($"Message arrived on topic: ${Topic}"$)

    Log($"PushTopic variable: ${PushTopic}"$)

    Log($"Labelusername.Text: ${Labelusername.Text}"$)

'    Log($"TargetUsername: ${TargetUsername}"$)

    Log($"Topic matches PushTopic: ${Topic = PushTopic}"$)

    Log($"Topic matches Labelusername: ${Topic = ("fetsync/push/" & Labelusername.Text)}"$)

    

    ' Handle personal push messages

    If Topic = PushTopic Then

        Try

            Dim messageMap As Map = serializator.ConvertBytesToObject(Payload)

            

            Dim title As String = messageMap.GetDefault("title", "new message")

            Dim body As String = messageMap.GetDefault("body", "you have a message ")

            

            Log($"πŸ”” PUSH NOTIFICATION RECEIVED:"$)

            Log($"   Title: ${title}"$)

            Log($"   Body: ${body}"$)

            

            ' Store the message

            Dim pushMessage As Map

            pushMessage.Initialize

            pushMessage.Put("title", title)

            pushMessage.Put("body", body)

            pushMessage.Put("timestamp", DateTime.Now)

            pushMessage.Put("read", False)

            

            PushMessages.Add(pushMessage)

            

            ' Update badge count

            UpdateBadgeCount

            

            ' Show notification popup for testing

'            xui.MsgboxAsync(body, title)

            

        Catch

            Log("❌ Error processing push message: " & LastException.Message)

        End Try

        

        ' Handle broadcast messages

    Else If Topic = BroadcastTopic Then

        Try

            Dim messageMap As Map = serializator.ConvertBytesToObject(Payload)

            

            If messageMap.GetDefault("type", "") = "broadcast" Then

                Dim content As String = messageMap.Get("content")

                

                Log($"πŸ“’ BROADCAST RECEIVED: ${content}"$)

                

                ' Store broadcast as a message

                Dim broadcastMessage As Map

                broadcastMessage.Initialize

                broadcastMessage.Put("title", "important")

                broadcastMessage.Put("body", content)

                broadcastMessage.Put("timestamp", DateTime.Now)

                broadcastMessage.Put("read", False)

                broadcastMessage.Put("type", "broadcast")

                

                PushMessages.Add(broadcastMessage)

                

                ' Update badge count

                UpdateBadgeCount

                

                ' Optionally show notification popup

'                xui.MsgboxAsync(content, "important")

            End If

            

        Catch

            Log("❌ Error processing broadcast message: " & LastException.Message)

        End Try

        

    Else

        Log($"❓ Unknown topic: ${Topic}"$)

    End If

End Sub







Private Sub UpdateBadgeCount

    ' Only update if components are initialized

    If Not(PushMessages.IsInitialized) Then

        Log("PushMessages not initialized")

        Return

    End If

    

    If Not(AS_Badges1.IsInitialized) Then

        Log("AS_Badges1 not initialized")

        Return

    End If

    

    If Not(Labelpushnotif.IsInitialized) Then

        Log("Labelpushnotif not initialized")

        Return

    End If

    

    ' Count unread messages

    BadgeCount = 0

    For Each msg As Map In PushMessages

        If msg.Get("read") = False Then

            BadgeCount = BadgeCount + 1

        End If

    Next

    

    ' Update badge display

    If BadgeCount > 0 Then

        Dim BadgeProperties As AS_Badges_BadgeProperties = AS_Badges1.BadgeProperties

        BadgeProperties.BackgroundColor = xui.Color_Red

        BadgeProperties.Orientation = AS_Badges1.Orientation_TopRight

        AS_Badges1.SetBadge2(Labelpushnotif, BadgeCount, BadgeProperties)

    Else

        ' Do not use RemoveBadge if it's not accessible

        ' Rely on AutoRemove to hide the badge when count is 0

        AS_Badges1.AutoRemove = True

        ' Optionally, set badge to 0 to ensure it's hidden

        Dim BadgeProperties As AS_Badges_BadgeProperties = AS_Badges1.BadgeProperties

        BadgeProperties.BackgroundColor = xui.Color_Red

        BadgeProperties.Orientation = AS_Badges1.Orientation_TopRight

        AS_Badges1.SetBadge2(Labelpushnotif, 0, BadgeProperties)

    End If

    

    Log($"Badge count updated: ${BadgeCount} unread messages"$)

End Sub





Private Sub MarkAllMessagesAsRead

    If PushMessages.IsInitialized Then

        For Each msg As Map In PushMessages

            msg.Put("read", True)

        Next

        UpdateBadgeCount

        Log("All messages marked as read")

    Else

        Log("PushMessages not initialized - cannot mark as read")

    End If

End Sub











Sub mqtt_Disconnected

    Log("πŸ”Œ Disconnected from MQTT Broker")

    MainForm.Title = "Push Receiver - " & Username & " (Disconnected)"

    

    ' Auto-reconnect after 10 seconds

    Sleep(10000)

    Log("πŸ”„ Attempting to reconnect...")

    mqtt.Connect2(mo)

End Sub


not that in client app you must add these library ( AS_FloatingActionMenu , AS_Badges, Jxui , JRandomaccesfiles , Jnetwork,Jmqtt)
and in server app ( Jxui , JRandomaccesfiles , Jnetwork,Jmqtt)

this is label click even ( you can do it with button or any other b4xview)


Label even:
Private Sub Labelpushnotif_MouseClicked (EventData As MouseEvent)
    DigitalFont3 = xui.CreateFont(fx.LoadFont(File.DirAssets, DigitalFontTTF, 12), 12)
    FloatingActionMenu.Initialize(Me, "FloatingActionMenu", MainForm.RootPane) ' Adjust parent view as needed
    FloatingActionMenu.Color = xui.Color_White
    FloatingActionMenu.ItemProperties.SeperatorVisible = True
    FloatingActionMenu.ItemProperties.xFont=DigitalFont3
    FloatingActionMenu.TextColor = xui.Color_Black     ' Add messages to the menu
    If PushMessages.IsInitialized = False Or PushMessages.Size = 0 Then
        FloatingActionMenu.AddItem("no push message ",<<icon as you want >> , -1)
    Else
        Dim maxMessages As Int = Min(5, PushMessages.Size)
        For i = PushMessages.Size - 1 To PushMessages.Size - maxMessages Step -1
            Dim msg As Map = PushMessages.Get(i)
            Dim msgt As String = msg.Get("msgt")
            Dim msgb As String = msg.Get("msgb")
            Dim isRead As Boolean = msg.Get("read")
            Dim displayText As String = msgb
            If displayText.Length > 30 Then
                displayText = displayText.SubString2(0, 30) & "..."
            End If
            If Not(isRead) Then
                displayText = "πŸ”΄ " & displayText
            Else
                displayText = "βšͺ " & displayText
            End If
            FloatingActionMenu.AddItem(displayText,<<icon as you want >> , i)
        Next
       FloatingActionMenu.AddItem("make all readed ",<<icon as you want >>,  -2)
    End If
    Dim Height As Float = FloatingActionMenu.ItemProperties.Height * FloatingActionMenu.Size
    Dim Left As Float = Labelpushnotif.Left
    Dim Top As Float = Labelpushnotif.Top + Labelpushnotif.Height
    FloatingActionMenu.ShowPicker(Left, Top, 250dip, Height)
    FloatingActionMenu.OpenOrientation = FloatingActionMenu.OpenOrientation_BottomTop
    Wait For FloatingActionMenu_ItemClicked(Item As AS_FloatingActionMenu_Item)
    Select Item.Value
        Case -1 ' No notifications
            Log("No notifications")
        Case -2 ' Mark all as read
            MarkAllMessagesAsRead
        Case Else ' Specific message clicked
            If Item.Value >= 0 And Item.Value < PushMessages.Size Then
                Dim msg As Map = PushMessages.Get(Item.Value)
                msg.Put("read", True) ' Mark as read
                Dim msgt As String = msg.Get("msgt")
                Dim msgb As String = msg.Get("msgb")
                xui.MsgboxAsync(msgb,msgt)
                UpdateBadgeCount
            End If
    End Select
End Sub



also you must add textfield or button as name in code or change it in code , i've use as badge in label named Labelpushnotif ,
- image is from my app
* you can test it and any quastion i'm here ..
* you must subscribe to any broker service .
* you must create a layout as you want using name in code or change it .


Next Topic : using mqtt chat with imogies in message and send imeges between users in room whithout affecting broker
 

thetrueman

Active Member
Thanks so much for sharing your nice efforts as a thanksgiving which is really appreciated to teach and learn for beginners. Looking forward for upcoming posts.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…