iOS Question Firebase notifications (background)

andyr00d

Member
Licensed User
Longtime User
Hello,

Just wondering if anyone can shed some light on this. I've followed the Firebase push notifications tutorial and it's working fine, my device is receiving a msgbox dialog notification when the app is running in the foreground, and a push notification when in the background - no problems at all.

@Erel confirmed in this post (https://www.b4x.com/android/forum/t...-notification-clarification.93283/post-590196) "If the application is in the foreground then RemoteNotification event is raised. If the app is in the background or not running then a notification is shown."

My question is how does this notification in the background get displayed? From the code, the only thing I can see is the messagebox (when in foreground)
B4X:
Msgbox(Message, "Push message!")
whereas B4A tutorial has a notification object defined... so how is it displaying in iOS like that if there is no notification defined? If I go ahead and define a new notification on the message received event in B4i, will that override the current one or will there be two displayed?

Thanks!
 

andyr00d

Member
Licensed User
Longtime User
Your app doesn't start. It is the OS that shows the notification.
OK - but how can we handle that notification? For example if the body text equals "test" then show XXX in notification, else....

Or is it explicitly locked to whatever comes through in the map object?

in B4A I'm doing this:
B4X:
Sub fm_MessageArrived (Message As RemoteMessage)   
    If Message.From = "/topics/general" Then
        Log($"Message data: ${Message.GetData}"$)
        Dim n As Notification
        n.Initialize
        n.Icon = "icon"
        n.AutoCancel = True
        n.SetInfo("General Message", Message.GetData.Get("body"), Main)
        n.Notify(1)
        Return
    Else
    ...
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
If your original requirements are
  1. Always grant that a notification will be shown to the user
  2. Always be able to customize it
, but can be relaxed to
  1. Always grant that a notification will be shown to the user
  2. Be able to customize it in as many cases as possible

, since iOS 13 and leaving appart Notification Service Extension (not possible at this moment with B4i), the best working solution I found is:
  • Send a normal push where the iosalert map keys, "title" and "body" have no personalized values. For instance "New message arrived", "You have one alert", ...
  • Add "content-available=true" to the notification with the user-specific data (as it is done with the silent push notifications, but not removing the iosalert.).
  • The behaviour will be:
    • If your app is in foreground (or in backgroud but not expicitly killed by the user) the "normal" Title-Body notification will be shown, At some moment (nearly immediately in foreground, can take longer in background, depending on the state) the notification will be delivered to the app. Once it is delivered to the app, it can kill it and place another with customized content based on the additional data (as you did until now)
    • If the app is killed, your user will still know that something has happeded (this was a strong requirement in my case). Only when he opens the app, the notification can be processed (or the app connect to the server to check for news, whatever...)
 
Upvote 0

andyr00d

Member
Licensed User
Longtime User
Hello,

Thanks for your suggestion, I've added the content-available=true and changed the title & body values to be dummy strings. I'm not sure how I can kill the notification once it is delivered to the app - are you referring to doing that within the RemoteNotification sub? Do you have any code I can try for your below suggestion?

Once it is delivered to the app, it can kill it and place another with customized content based on the additional data (as you did until now)

Thanks!
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
Wherever they are delivered immediately or not, the way I remove them is (note that this solution removes all of them, not individually, which can lead to info loss if there is more than one pending...). More info HERE

Remove local notifications:
Private Sub Application_RemoteNotification (Message As Map, CompletionHandler As CompletionHandler)

    'Log($"Message arrived: ${Message}"$)   

    ' This will remove them all. Still struggling to remove individually
    Dim no As NativeObject = Me
    no.RunMethod("removeNotif", Null)
    Sleep(300)
    'processRemoteNotification(Message) '<- do your processing here.
    
    CompletionHandler.Complete
End Sub

#if OBJC
#import <UserNotifications/UserNotifications.h>

-(void)removeNotif {
    
    // Remove all notifications.
    [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
}
#end if

It's curious because, at least now, even when the app is killed I'm receiving these notifications and they are immediately delivered to the app. So they are processed even in this case. But we can't rely that this will be always the behavior.
 
Upvote 0

andyr00d

Member
Licensed User
Longtime User
Interesting, I cannot get that code to work at all... It's not removing the notification that comes through from Firebase - it still displays, and also when I'm setting a new local notification after removeNotif, it is not appearing. Have tried it on a real device in debug + release, same result. :(

B4X:
Sub TestGetMessage As String
    Dim msg As String = "hi there!"
    Return msg
End Sub

Private Sub Application_RemoteNotification (Message As Map, CompletionHandler As CompletionHandler)
    'Log($"Message arrived: ${Message}"$)
    'Msgbox(Message, Message.Get("body"))
 
    Dim no As NativeObject = Me
    no.RunMethod("removeNotif", Null)
    Sleep(300)
 
    Dim ln As Notification
    ln.Initialize(DateTime.Now + 10 * DateTime.TicksPerSecond)
    'ln.IconBadgeNumber = 1
    ln.AlertBody = TestGetMessage
    ln.PlaySound = True
    ln.Register
 
    CompletionHandler.Complete
End Sub

#if OBJC
#import <UserNotifications/UserNotifications.h>

-(void)removeNotif {
 
    // Remove all notifications.
    [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
}
#end if
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
It's strange, it works perfectly in my app.😕

Can you confirm that the Application_RemoteNotification Sub is being called?

Assuming this is the case, you must check wether your app is in foreground or background. If in foreground, local notifications won't appear. Check THIS in order to make them appear in foreground.
 
Upvote 0

andyr00d

Member
Licensed User
Longtime User
So Application_RemoteNotification is being called when running in the foreground and works correctly (the firebase notification doesn't appear and then it triggers my local notification 10 seconds later) however when I send the app to the background and send a FCM, Application_RemoteNotification is being called there too however it is not killing the firebase notification, but it is showing the scheduled local notification 10 seconds later as I intended... all I need to do is just stop the first FCM appearing and then it's good! I wonder if there are any other ways to kill it
 
Upvote 0

andyr00d

Member
Licensed User
Longtime User
It's posted 3 posts above (https://www.b4x.com/android/forum/threads/firebase-notifications-background.118152/post-739605) ^

The only thing I've changed has been in the B4J sending tool, I changed "content-available" to "content_available" (based on another post I read) and that caused the Application_RemoteNotification sub to fire when in background. If I have it set to "content-available" the FCM message appears but Application_RemoteNotification sub doesn't fire (I can't see it in the log).
 
Last edited:
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
Glad to have helped :) --> so the first delivered message is again silent or still something is shown before being processed?

Regarding your previous question, I'm exploring a way to kill only the received message. Will be good if there is more than one queued. Will post the code when I get something reliable
 
Upvote 0

andyr00d

Member
Licensed User
Longtime User
Yeah, the first delivered message is now silent - nothing is being shown. Then 6 seconds later my notification appears.

So that "removeAllDeliveredNotifications" Objective-C code... does that remove ALL notifications from any app which are in the notification try, or only ALL notifications related to my app?
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
Only those from your app. Although a single message can also be removed.

Whatever method we use, I've seen that the removal part doesn't always work properly with iOS 12 devices (seems that it does with iOS 13), and sometimes the original notification remains there. There are some SO posts talking about it and possible workarounds. Must still test them.
 
Upvote 0
Top