Значок уведомления с новой системой обмена сообщениями Firebase Cloud

132

Вчера Google представил на Google I / O новую систему уведомлений, основанную на новом Firebase. Я попробовал этот новый FCM (Firebase Cloud Messaging) с примером на Github.

Значок уведомления всегда является ic_launcher, несмотря на то, что я объявил конкретную возможность рисования.

Зачем ? Ниже приведен официальный код для обработки сообщения.

public class AppFirebaseMessagingService extends FirebaseMessagingService {

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // If the application is in the foreground handle both data and notification messages here.
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
        sendNotification(remoteMessage);
    }
    // [END receive_message]

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param remoteMessage FCM RemoteMessage received.
     */
    private void sendNotification(RemoteMessage remoteMessage) {

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

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

// this is a my insertion looking for a solution
        int icon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? R.drawable.myicon: R.mipmap.myicon;
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(icon)
                .setContentTitle(remoteMessage.getFrom())
                .setContentText(remoteMessage.getNotification().getBody())
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

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

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

}
марко
источник
firebase не имеет ничего общего с тем, как ВЫ создаете уведомление, пожалуйста, предоставьте изображение того, что вы видите
tyczj
1
точный. этот код поступает прямо из Firebase, а метод sendNotification () точно такой же для любого уведомления. Этот код отлично работает с GCM, но с FCM нет. он всегда остается ic_launcher, используя новый веб-интерфейс для отправки сообщений
марко
вы устанавливаете маленький значок, но не большой, если только вы не отправляете push-уведомление с тегом уведомления в полезной нагрузке push, это не имеет ничего общего с FCM
tyczj
Отображает ли он ваш пользовательский значок уведомления, когда приложение находится на переднем плане? Это подходит для меня. Однако, когда приложение работает в фоновом режиме, оно должно использовать какой-то обработчик FCM по умолчанию, поскольку все настройки уведомлений игнорируются (значок, звук, свет, вибрация и т. Д. Не могут быть настроены).
shinypenguin

Ответы:

268

К сожалению, это было ограничением уведомлений Firebase в SDK 9.0.0-9.6.1. Когда приложение находится в фоновом режиме, значок запуска используется из манифеста (с необходимой тонировкой Android) для сообщений, отправленных с консоли.

Однако с SDK 9.8.0 вы можете изменить значение по умолчанию! В вашем AndroidManifest.xml вы можете установить следующие поля для настройки значка и цвета:

<meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/notification_icon" />
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/google_blue" />

Обратите внимание, что если приложение находится на переднем плане (или отправлено сообщение с данными), вы можете полностью использовать свою собственную логику для настройки отображения. Вы также всегда можете настроить значок при отправке сообщения из API HTTP / XMPP.

Ян Барбер
источник
1
@ Ян Барбер: есть ли у Google планы изменить это поведение в ближайшем будущем?
skylve 07
1
Команда знает об этой проблеме и работает над ее исправлением.
Артур Томпсон
1
какие-нибудь обновления по этому поводу? думал, что спрошу, потому что были обстоятельства, когда инженер Google просто забыл запустить патч.
CQM
7
Ах, у меня получилось работать с 9.8.0. Чтобы помогать другим, помните, что значок в строке состояния должен соответствовать требованиям: developer.android.com/guide/practices/ui_guidelines/… . У меня этого не было, и поэтому firebase по умолчанию использует стандартный белый квадрат вместо использования значка, указанного в манифесте.
zaifrun
3
Если вы попробуете это и обнаружите, что значок меньше, чем у других уведомлений, убедитесь, что вы используете вектор, который можно рисовать (а не png). Это решило проблему для меня.
riper
36

Используйте реализацию сервера для отправки сообщений на клиент и использование данных типов сообщений , а не уведомление типа сообщений.

Это поможет вам получить обратный вызов onMessageReceivedнезависимо от того, находится ли ваше приложение в фоновом режиме или на переднем плане, и вы можете сгенерировать свое собственное уведомление, а затем

geekoraul
источник
2
Это предлагаемое решение и в документации Firebase, вы можете показывать уведомление любым удобным для вас способом, если вы полагаетесь на push-данные вместо уведомления.
гонки
1
да согласен. это следует отметить как правильный ответ. или мой ответ ниже :)
Developine
3
Нет, это невозможно для людей, которым необходимо поддерживать совместимость с другими клиентами / устаревшими версиями, которые ожидают уведомления.
Габор
У нас есть приложения в производстве, которые уже ожидают push-уведомления, и мы расширили этот (сложный) серверный компонент, чтобы добавить данные для новых клиентов. Но мы не можем удалить поддержку устаревших версий нашего приложения.
Габор
О, я согласен. Это еще одна проблема. Я предлагаю внимательно прочитать документацию перед интеграцией. Также необходимо тщательно протестировать перед выпуском в производство. Этой проблемы можно было бы избежать, если бы приложение было протестировано задолго до запуска. В любом случае, тебе было чему поучиться.
geekoraul
9

atm они работают над этой проблемой https://github.com/firebase/quickstart-android/issues/4

когда вы отправляете уведомление из консоли Firebase, по умолчанию используется значок вашего приложения, а система Android будет превращать этот значок в сплошной белый цвет на панели уведомлений.

Если вы недовольны этим результатом, вам следует реализовать FirebaseMessagingService и создавать уведомления вручную при получении сообщения. Мы работаем над тем, чтобы улучшить это, но пока это единственный способ.

изменить: с SDK 9.8.0 добавить в AndroidManifest.xml

<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/my_favorite_pic"/>
Ян Хартвиг
источник
как отобразить панель уведомлений с настраиваемыми значками в зефире
Харша
6

Мое решение похоже на решение ATom, но проще в реализации. Вам не нужно создавать класс, который полностью затеняет FirebaseMessagingService, вы можете просто переопределить метод, который получает Intent (который является общедоступным, по крайней мере, в версии 9.6.1), и взять информацию, которая будет отображаться из дополнительных компонентов. «Хакерская» часть заключается в том, что имя метода действительно запутано и будет меняться каждый раз, когда вы обновляете SDK Firebase до новой версии, но вы можете быстро найти его, проверив FirebaseMessagingService с помощью Android Studio и ища общедоступный метод, который принимает Намерение как единственный параметр. В версии 9.6.1 он называется zzm. Вот как выглядит мой сервис:

public class MyNotificationService extends FirebaseMessagingService {

    public void onMessageReceived(RemoteMessage remoteMessage) {
        // do nothing
    }

    @Override
    public void zzm(Intent intent) {
        Intent launchIntent = new Intent(this, SplashScreenActivity.class);
        launchIntent.setAction(Intent.ACTION_MAIN);
        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* R    equest code */, launchIntent,
                PendingIntent.FLAG_ONE_SHOT);
        Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.ic_launcher);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_notification)
                .setLargeIcon(rawBitmap)
                .setContentTitle(intent.getStringExtra("gcm.notification.title"))
                .setContentText(intent.getStringExtra("gcm.notification.body"))
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

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

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}
Карло Консерва
источник
gcm.notification.title для имени ключа на 100% безопасен для всех версий?
pedroooo
3

Просто установите targetSdkVersion на 19. Значок уведомления будет цветным. Затем дождитесь, пока Firebase исправит эту проблему.

rattisuk
источник
7
: D Ух ты, а где список побочных эффектов?
Eugen Pechanec
@EugenPechanec: да, компромисс в том, что вы не сможете использовать какой-то API, доступный на 20+
benleung
3

Есть еще один некрасивый, но рабочий способ. Декомпилируйте FirebaseMessagingService.class и измените его поведение. Затем просто поместите класс в нужный пакет в приложении yout, и dex будет использовать его вместо класса в самой библиотеке сообщений. Это довольно просто и работает.

Есть способ:

private void zzo(Intent intent) {
    Bundle bundle = intent.getExtras();
    bundle.remove("android.support.content.wakelockid");
    if (zza.zzac(bundle)) {  // true if msg is notification sent from FirebaseConsole
        if (!zza.zzdc((Context)this)) { // true if app is on foreground
            zza.zzer((Context)this).zzas(bundle); // create notification
            return;
        }
        // parse notification data to allow use it in onMessageReceived whe app is on foreground
        if (FirebaseMessagingService.zzav(bundle)) {
            zzb.zzo((Context)this, intent);
        }
    }
    this.onMessageReceived(new RemoteMessage(bundle));
}

Это код из версии 9.4.0, метод будет иметь разные имена в разных версиях из-за обфускации.

Атом
источник
3

если ваше приложение находится в фоновом режиме, значок уведомления будет установлен в методе получения сообщения, но если ваше приложение находится на переднем плане, значок уведомления будет тем, который вы определили в манифесте

введите описание изображения здесь

ручей
источник
2

Я запускаю свои уведомления из консоли FCM и через HTTP / JSON ... с тем же результатом.

Я могу обрабатывать заголовок, полное сообщение, но значок всегда является белым кружком по умолчанию:

Скриншот уведомления

Вместо моего пользовательского значка в коде (setSmallIcon или setSmallIcon) или значка по умолчанию из приложения:

 Intent intent = new Intent(this, MainActivity.class);
    // use System.currentTimeMillis() to have a unique ID for the pending intent
    PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);

    if (Build.VERSION.SDK_INT < 16) {
        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pIntent)
                .setAutoCancel(true).getNotification();
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    } else {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setLargeIcon(bm)
                .setContentIntent(pIntent)
                .setAutoCancel(true).build();

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    }
Гонсало
источник
1
Понял! мои теги <service> находятся вне тега <application> в AndroidManifest.xml Здесь я готов ответить stackoverflow.com/a/37352142/6366150
Gonzalo
Работает только с запущенным приложением на переднем плане ... в фоновом режиме все еще ведет себя так же, как и раньше,
Гонсало
когда приложение находится в фоновом режиме, этот значок пользовательского уведомления появляется и работает нормально, но в фоновом режиме приложения появляется белый квадратный значок, пожалуйста, помогите мне
Харша,
1

напиши это

<meta-data 
         android:name="com.google.firebase.messaging.default_notification_icon"
         android:resource="@drawable/ic_notification" />

прямо вниз <application.....>

введите описание изображения здесь

dmarquina
источник
0

Подумал, что добавлю ответ на этот вопрос, так как моя проблема была простой, но трудно заметить. В частности, я скопировал / вставил существующий элемент метаданных при создании my com.google.firebase.messaging.default_notification_icon, который использовал android:valueтег для указания его значения. Это не будет работать для значка уведомления, и как только я изменил его, android:resourceвсе работало, как ожидалось.

Чарльз А.
источник
То же самое и с default_notification_colorмета, это должна быть android:resourceнастройка, поскольку android:valueона не будет работать
flochtililoch