Handle android push notification when app is not running like whatsapp, twitter, facebook, instagram etc
Asked Answered
R

3

6

I am working on a chat application like whatsapp. When the app is running, I use a websocket connection to handle chats between two users however when the app is killed or is not running I tried using FCM push notification service to notify a user for when he gets a message, just like the way whatsapp does.

The problem now is that, FCM receives push notification when the app is in the foreground or in the background(obscured from view, but still in recent task menu), Once the app is swiped out from recent task menu or is not started at all, no notification is received.

I have been stock here for a whole week, I have searched and read through various articles and community conversations on github, stackoverflow, quora and some blog posts and I am yet to find something that works.

I tried to use background services to keep the websocket connection with the server connected but I am been unable to get the service to continue running as android kills off background services when the app is not in the foreground.

I mean how do apps like whatsapp, twitter, instagram, facebook, gmail, likee, tiktok etc handle push notification such that even though the app is closed (swiped out of recent menu or not started at all) it still notifies it's users of some updates on the server.

Here is my code... On the server

const firebase_admin = require('firebase-admin');
var service_account = require('./service_account.json');
firebase_admin.initializeApp({
    credential: firebase_admin.credential.cert(service_account),
    databaseURL: 'https://fcm_pushnotification-b9983.firebaseio.com/'
});

app.get('/sendPushNotification', (req, res) => {
    // This registration token comes from the client FCM SDKs.
    var registrationToken = 'clIilmqTRYarMF4gcrpEeH:APA91bFjkmZP7gU836ZCAzyPZaOWU4nU4SLL5OPWNkgukt0zBe0zvn5PEQ-42g60R5UXFN0tXQISjCDcbl032j2Tc81_OZ5uAJ7Aq3_OAaIz7g56oT547LnB9wiiBIKRZhc1TWGMP7lr';

    var message = {
        notification: {
            title: 'Samuel',
            body: 'This is an urgent message!',
        },
        webpush:{
            headers:{
                Urgency:'high'
            }
        },
        android:{
            priority:'high'
        },
        token: registrationToken
    };


    // Send a message to the device corresponding to the provided
    // registration token.
    firebase_admin.messaging().send(message)
      .then((response) => {
        // Response is a message ID string.
        console.log('Successfully sent message:', response);
        res.send('Successfully sent message:- '+ response);
      })
      .catch((error) => {
        console.log('Error sending message:- ', error);
        res.send('Error sending message:'+ error);
      });
});

My services class on android

public class MyFirebaseMessagingService extends FirebaseMessagingService{
    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    @Override
    public void onNewToken(@NonNull String token) {
        Log.d(TAG, "Refreshed token: " + token);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(token);
    }

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        String title = remoteMessage.getNotification().getTitle();
        String body = remoteMessage.getNotification().getBody();
        this.sendNotification(new Notification(null, title, body, 0));
    }

    private void sendNotification(Notification notification){
    // Notification channel and notification is build here.
    }

}

The manifest

<uses-permission android:name="android.permission.INTERNET" />

        <service
            android:name=".Services.MyFirebaseMessagingService"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

 <!-- Set custom default icon. This is used when no icon is set for incoming notification messages. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@drawable/ic_heart" />
        <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
             notification message. -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/red" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/notification_channel_id" />

Is there a permission that I need to request for this to work when app is not running. I even set the notification priority as high on the server as can been seen. I have been frustrated by this. Please any help is welcomed.

Roseboro answered 20/4, 2020 at 11:54 Comment(3)
Have you tried sending notifications via the firebase admin testing web interface?Basiliabasilian
Thanks for the quick response @Erich. Yes I have tried sending notifications from there and it works the same way (It sends when the app is on the foreground or background but not when the app is not running anywhere atall).Roseboro
@Double_M, Did you get any solution of this problem ? I am facing same.Herv
R
4

For anyone who might run into similar issue:

I contacted the firebase support team and they stated that it is an issue caused by a battery optimization implemented by some original equipment manufacturers (OEMs). When an app is swiped away in the app switcher, the application is treated as if it were force-stopped, which is not the default Android behavior. The unfortunate side effect of this is that it can cause the FCM service for your app to stop running.

One way to check if your app is affected by any OEM's battery management feature, is as below:

  1. Attach the OEM device to adb.
  2. Run your app on the device.
  3. Swipe the app away from the recent screen on the device.
  4. Run the command: adb shell dumpsys package MY-PACKAGE | grep stopped

If it shows stopped=true, it's safe to assume that the OEM has such a mechanism, and that your app is affected by this issue.

You can also read more about this issue and a possible way of solving it in this: https://www.freecodecamp.org/news/why-your-push-notifications-never-see-the-light-of-day-3fa297520793/.

Roseboro answered 25/12, 2020 at 10:4 Comment(1)
I checked this on a Nothing CMF Phone One in India and what you say does appear to be true in the Sample app that I've built myself to test this. But on the same device, Whatsapp too is also battery optimised, and when I swipe it away from recent apps, it still manages to get push notifications.Rheims
A
0

the problem is that you are sending fcm data notification but in android side you have code for the normal notification.

Make the below change in onMessageReceived method

Map<String, String> data = remoteMessage.getData().get("data");
String title = data.getOrDefault("title", "");
String body = data.getOrDefault("body", "");

pass this title and body string value to show notification block code to set title and message text

Ably answered 20/4, 2020 at 18:15 Comment(2)
Thanks for the response @Swapnil, but as you can see from the server, I am sending a notification message. I have also tried sending data message where I got the title and body as you described.Roseboro
This is the problem, when app is in the foreground, onMessageReceived is called once a notification is received, when the app is in the background and a notification message is sent, the message is sent to the notification tray. However, when the app is not running, nothing happens. This is exactly what I am trying to accomplish, push notification when app is not running. When app is running, I can use my socket connection.Roseboro
R
0

I have used OneSignal push service for a similar project and I did not have any problem nor needed to implement any additional logic to be able to receive notifications while on background or terminated. You will still need to have a firebase project associated with your app to get the Firebase Server Key and Sender Id. If there is no specific reason you need to use Firebase Push Service, I would suggest you try OneSignal.

Free plan includes unlimited mobile, up to 10K web push subscribers, email, SMS & 1 in-app message. No credit card required.

Repeal answered 25/12, 2020 at 10:11 Comment(1)
I think I tried oneSignal then and I had same result, it depends on the phone used. As explained by the firebase support team, battery optimization implemented by some OEM manufacturers often times affect applications. I have seen complains on the reviews of apps like pintrest, linkedIn etc where users complain of not receiving notifications or messages until they go the message page and refresh. I have also noticed that with my twitter app.Roseboro

© 2022 - 2024 — McMap. All rights reserved.