Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android device group not receiving messages

I didn't change anything in my app since several months but starting from 11th June I'm not able to receive any message sent by Firebase cloud messaging. It has been reported by several customers and I can confirm that it doesn't work anymore. No firmware change or anything at least on my phone. I used exactly the same code you find here. The message is sent, the callback onMessageSent in the FirebaseMessagingService is called correctly, but I'm not able to receive anything using the same account on another phone. Is there any big change I miss it? My configuration doesn't use a server so I can't check any log server side. Any tips?

like image 680
greywolf82 Avatar asked Jul 13 '19 11:07

greywolf82


2 Answers

The official reply I've gotten from Firebase is: they simply don't support the no-server configuration anymore.

So after 30 emails with Firebase support here's the surprise: there's nothing wrong with my code/project, and the funny thing is that they don't know why and how it worked before! Unfortunately, they didn't advise anyone about this big change, so any app based on Android device groups without a server doesn't work anymore.

like image 178
greywolf82 Avatar answered Nov 08 '22 18:11

greywolf82


Here is a possible answer to your question -

Firstly, you say that 'But I'm not able to receive anything using the same account on another phone'. Device Messaging via FCM uses the device registration token as the point of contact and not the account. Therefore, you might not receive messages from FCM with the same account on a different device.

Secondly, you can only have 20 devices registered to each token group. The Firebase Docs also mention that you usually need an app server to do device to device messaging.

Remember that this kind of device to device messaging is used only for notifications, not for sending chat messages or anything of that kind. If you want to implement notifications without an app server, try this -

import android.app.IntentService;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.legacy.content.WakefulBroadcastReceiver;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;

public class NotificationIntentService extends IntentService {

    private static int NOTIFICATION_ID = 1;
    private static final String ACTION_START = "ACTION_START";
    private static final String ACTION_DELETE = "ACTION_DELETE";

    public NotificationIntentService() {
        super(NotificationIntentService.class.getSimpleName());
    }

    public static Intent createIntentStartNotificationService(Context context) {
        Intent intent = new Intent(context, NotificationIntentService.class);
        intent.setAction(ACTION_START);
        return intent;
    }

    public static Intent createIntentDeleteNotification(Context context) {
        Intent intent = new Intent(context, NotificationIntentService.class);
        intent.setAction(ACTION_DELETE);
        return intent;
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.w(String.valueOf(new NotificationIntentService()), "onHandleIntent, started handling a notification event");
        try {
            String action = intent.getAction();
            if (ACTION_START.equals(action)) {
                processStartNotification();
            }
            if (ACTION_DELETE.equals(action)) {
                processDeleteNotification(intent);
            }
        } finally {
            WakefulBroadcastReceiver.completeWakefulIntent(intent);
        }
    }

    private void processDeleteNotification(Intent intent) {
        // Log something?
    }

    private void processStartNotification() {

        // Do something. For example, fetch fresh data from backend to create a rich notification?

        NOTIFICATION_ID += 1;

        Intent intent = new Intent(NotificationIntentService.this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(NotificationIntentService.this, 0 /* Request code */, intent,
                                        PendingIntent.FLAG_UPDATE_CURRENT);

         String channelId = getString(R.string.default_notification_channel_id);
         Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
         NotificationCompat.Builder notificationBuilder =
                                        new NotificationCompat.Builder(NotificationIntentService.this, channelId)
                                                .setSmallIcon(R.drawable.chat)
                                                .setContentTitle("Title")
                                                .setContentText("Text")
                                                .setAutoCancel(true)
                                                .setSound(defaultSoundUri)
                                                .setContentIntent(pendingIntent);

                                notificationBuilder.setContentIntent(pendingIntent);
                                notificationBuilder.setDeleteIntent(NotificationEventReceiver.getDeleteIntent(NotificationIntentService.this));

                                NotificationManager notificationManager =
                                        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

                                // Since android Oreo notification channel is needed.
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                    NotificationChannel channel = new NotificationChannel(channelId,
                                            "channel_id",
                                            NotificationManager.IMPORTANCE_DEFAULT);
                                    notificationManager.createNotificationChannel(channel);
                                }

                                notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());

    }
}
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import androidx.legacy.content.WakefulBroadcastReceiver;

import java.util.Calendar;
import java.util.Date;

public class NotificationEventReceiver extends WakefulBroadcastReceiver {

    private static final String ACTION_START_NOTIFICATION_SERVICE = "ACTION_START_NOTIFICATION_SERVICE";
    private static final String ACTION_DELETE_NOTIFICATION = "ACTION_DELETE_NOTIFICATION";
    private static final int NOTIFICATIONS_INTERVAL_IN_FIFTEEN_MINUTES = 0;

    public static void setupAlarm(Context context) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent alarmIntent = getStartPendingIntent(context);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                getTriggerAt(new Date()),
                600000,
                alarmIntent);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Intent serviceIntent = null;
        if (ACTION_START_NOTIFICATION_SERVICE.equals(action)) {
            Log.w(getClass().getSimpleName(), "onReceive from alarm, starting notification service");
            serviceIntent = NotificationIntentService.createIntentStartNotificationService(context);
        } else if (ACTION_DELETE_NOTIFICATION.equals(action)) {
            Log.w(getClass().getSimpleName(), "onReceive delete notification action, starting notification service to handle delete");
            serviceIntent = NotificationIntentService.createIntentDeleteNotification(context);
        }

        if (serviceIntent != null) {
            startWakefulService(context, serviceIntent);
        }
    }

    private static long getTriggerAt(Date now) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);
        //calendar.add(Calendar.HOUR, NOTIFICATIONS_INTERVAL_IN_HOURS);
        return calendar.getTimeInMillis();
    }

    private static PendingIntent getStartPendingIntent(Context context) {
        Intent intent = new Intent(context, NotificationEventReceiver.class);
        intent.setAction(ACTION_START_NOTIFICATION_SERVICE);
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    public static PendingIntent getDeleteIntent(Context context) {
        Intent intent = new Intent(context, NotificationEventReceiver.class);
        intent.setAction(ACTION_DELETE_NOTIFICATION);
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public final class NotificationServiceStarterReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        NotificationEventReceiver.setupAlarm(context);
    }
}

I'm sorry, but I won't be able to tell you much more without seeing the code.

Hope this helps.

Sources -

  • Firebase Docs - https://firebase.google.com/docs/cloud-messaging/concept-options#senderid
  • Firebase Docs - https://firebase.google.com/docs/cloud-messaging/android/device-group#managing-device-groups-on-android-client-apps
like image 31
Gamemaker Avatar answered Nov 08 '22 17:11

Gamemaker