Ikona powiadomień z nowym systemem Firebase Cloud Messaging


139

Wczoraj Google zaprezentował na Google I / O nowy system powiadomień oparty na nowym Firebase. Wypróbowałem ten nowy FCM (Firebase Cloud Messaging) z przykładem na Github.

Ikoną powiadomienia jest zawsze ic_launcher, mimo że zadeklarowałem konkretny wyciąg

Czemu ? Poniżej oficjalny kod do obsługi wiadomości

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 nie ma nic wspólnego z tym, jak TY tworzysz powiadomienie, prosimy o przesłanie obrazu tego, co widzisz
tyczj

1
dokładny. ten kod pochodzi bezpośrednio z Firebase, a metoda sendNotification () jest dokładnie taka sama dla każdego powiadomienia. Ten kod działa dobrze z GCM, ale z FCM nie. zawsze pozostaje ic_launcher, używając nowego interfejsu internetowego do wysyłania wiadomości
marco

ustawiasz małą ikonę, ale nie dużą ikonę, chyba że wysyłasz push z tagiem powiadomienia w ładunku push, nie ma to nic wspólnego z FCM
tyczj

Czy pokazuje Twoją niestandardową ikonę powiadomienia, gdy aplikacja jest na pierwszym planie? To działa dla mnie. Jednak gdy aplikacja działa w tle, musi używać jakiegoś domyślnego programu obsługi FCM, ponieważ wszystkie ustawienia powiadomień są ignorowane (ikony, dźwięk, światła, wibracje itp. Nie mogą być dostosowywane).
shinypenguin

Odpowiedzi:


274

Niestety było to ograniczenie Powiadomień Firebase w SDK 9.0.0-9.6.1. Gdy aplikacja działa w tle, dla wiadomości wysyłanych z konsoli używana jest ikona programu uruchamiającego z manifestu (z wymaganym podbarwieniem systemu Android).

Jednak dzięki SDK 9.8.0 możesz zastąpić ustawienie domyślne! W pliku AndroidManifest.xml możesz ustawić następujące pola, aby dostosować ikonę i kolor:

<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" />

Zwróć uwagę, że jeśli aplikacja jest na pierwszym planie (lub zostanie wysłana wiadomość z danymi), możesz całkowicie użyć własnej logiki, aby dostosować wyświetlacz. Możesz także zawsze dostosować ikonę, jeśli wysyłasz wiadomość z interfejsów API HTTP / XMPP.


1
@Ian Barber: masz plan w Google, aby zmienić to zachowanie w najbliższej przyszłości?
skylve

1
Zespół jest świadomy problemu i pracuje nad jego rozwiązaniem.
Arthur Thompson

1
Czy to ma jakieś aktualizacje? Pomyślałem, że zapytam, ponieważ zdarzały się sytuacje, gdy inżynier Google po prostu zapomniał wypchnąć łatkę.
CQM

7
Ach, mam to do pracy z 9.8.0. Aby pomóc innym, pamiętaj, że ikona paska stanu musi spełniać wymagania: developer.android.com/guide/practices/ui_guidelines/… . Mój nie zrobił i dlatego firebase domyślnie używa standardowego whitesquare zamiast używać ikony określonej w manifeście.
zaifrun

3
Jeśli zdarzy ci się to wypróbować i okaże się, że ikona jest mniejsza niż inne powiadomienia, upewnij się, że używasz wektora do rysowania (a nie png). To mnie rozwiązało.
bardziej dojrzałe

36

Użyj implementacji serwerowej, aby wysyłać wiadomości do klienta i używać typów danych wiadomości zamiast typów powiadomień .

Pomoże Ci to uzyskać oddzwonienie onMessageReceivedniezależnie od tego, czy Twoja aplikacja działa w tle, czy na pierwszym planie, a następnie możesz wygenerować niestandardowe powiadomienie


2
Jest to również sugerowane rozwiązanie w dokumentach Firebase. Możesz wyświetlić powiadomienie w dowolny sposób, jeśli korzystasz z przesyłania danych zamiast powiadomienia.
wyścigi

1
tak, zgadzam się. należy to zaznaczyć jako poprawną odpowiedź. lub moja odpowiedź poniżej :)
Developine

3
Nie, nie jest to wykonalne dla osób, które muszą zachować zgodność z innymi klientami / starszymi wersjami, które oczekują powiadomienia.
Gabor

Mamy aplikacje w produkcji, które już oczekują typu powiadomienia typu push i rozszerzyliśmy ten (złożony) komponent zaplecza, aby dodawać dane dla nowych klientów. Nie możemy jednak usunąć obsługi starszych wersji naszej aplikacji.
Gabor

Och, zgadzam się. To kolejny problem. Sugerowałbym dokładne przeczytanie dokumentów przed integracją. Również do dokładnego przetestowania przed wydaniem do produkcji. Problemu można było uniknąć, gdyby aplikacja została dobrze przetestowana przed uruchomieniem. W każdym razie musiałeś się czegoś nauczyć.
geekoraul

9

atm, że pracują nad tym problemem https://github.com/firebase/quickstart-android/issues/4

gdy wysyłasz powiadomienie z konsoli Firebase, domyślnie używa ikony Twojej aplikacji, a system Android zmieni tę ikonę na biało na pasku powiadomień.

Jeśli nie jesteś zadowolony z tego wyniku, zaimplementuj FirebaseMessagingService i utwórz powiadomienia ręcznie po otrzymaniu wiadomości. Pracujemy nad sposobem, aby to poprawić, ale na razie to jedyny sposób.

edytuj: za pomocą SDK 9.8.0 dodaj do AndroidManifest.xml

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

jak wyświetlić niestandardową tacę powiadomień o ikonach w marshmallow
Harsha

6

Moje rozwiązanie jest podobne do rozwiązania ATom, ale jest łatwiejsze do wdrożenia. Nie musisz tworzyć klasy, która całkowicie przesłania FirebaseMessagingService, możesz po prostu zastąpić metodę, która odbiera Intent (która jest publiczna, przynajmniej w wersji 9.6.1) i pobrać informacje, które mają być wyświetlane z dodatków. „Hacky” część polega na tym, że nazwa metody jest rzeczywiście zaciemniona i będzie się zmieniać za każdym razem, gdy zaktualizujesz pakiet SDK Firebase do nowej wersji, ale możesz ją szybko sprawdzić, sprawdzając usługę FirebaseMessagingService w Android Studio i szukając metody publicznej, która wymaga intencja jako jedyny parametr. W wersji 9.6.1 nazywa się zzm. Oto jak wygląda moja usługa:

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 dla nazwy klucza jest w 100% bezpieczny dla wszystkich wersji?
pedroooo

3

Po prostu ustaw targetSdkVersion na 19. Ikona powiadomienia będzie kolorowa. Następnie poczekaj, aż Firebase rozwiąże ten problem.


7
: D Wow, więc gdzie jest lista skutków ubocznych?
Eugen Pechanec,

@EugenPechanec tak, kompromisem jest to, że możesz nie być w stanie korzystać z niektórych API, które są dostępne w wersji 20+
benleung

3

Jest też jeden brzydki, ale działający sposób. Zdekompiluj FirebaseMessagingService.class i zmodyfikuj jego zachowanie. Następnie po prostu umieść klasę w odpowiednim pakiecie w aplikacji yout i dex użyj jej zamiast klasy w samej bibliotece wiadomości. Jest to dość łatwe i działa.

Jest metoda:

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));
}

Ten kod pochodzi z wersji 9.4.0, metoda będzie miała różne nazwy w różnych wersjach z powodu zaciemnienia.


3

jeśli Twoja aplikacja działa w tle, ikona powiadomienia zostanie ustawiona na metodę odbioru wiadomości, ale jeśli aplikacja jest na pierwszym planie, ikona powiadomienia będzie tą, którą zdefiniowałeś w manifeście

wprowadź opis obrazu tutaj


2

Uruchamiam powiadomienia z konsoli FCM i przez HTTP / JSON ... z tym samym wynikiem.

Potrafię obsłużyć tytuł, pełną wiadomość, ale ikona jest zawsze domyślnym białym kółkiem:

Zrzut ekranu powiadomienia

Zamiast mojej niestandardowej ikony w kodzie (setSmallIcon lub setSmallIcon) lub domyślnej ikony z aplikacji:

 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
Rozumiem! moje tagi <service> są poza tagiem <application> w AndroidManifest.xml Tutaj przedstawiam odpowiedź stackoverflow.com/a/37352142/6366150
Gonzalo

Działa tylko z uruchomioną aplikacją na pierwszym planie ... w tle nadal uzyskuje to samo poprzednie zachowanie
Gonzalo,

kiedy aplikacja jest na forground, ta niestandardowa ikona powiadomienia nadchodzi i działa dobrze, ale w tle aplikacji pojawia się biała kwadratowa ikona, pomóż mi
Harsha

1

Napisz to

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

w dół <application.....>

wprowadź opis obrazu tutaj


0

Pomyślałem, że dodam odpowiedź do tego, ponieważ mój problem był prosty, ale trudny do zauważenia. W szczególności podczas tworzenia com.google.firebase.messaging.default_notification_iconpliku my skopiowałem / wkleiłem istniejący element metadanych , który używał android:valueznacznika do określenia jego wartości. To nie zadziała dla ikony powiadomienia, a gdy ją zmieniłem, android:resourcewszystko działało zgodnie z oczekiwaniami.


To samo dotyczy default_notification_colormeta, musi to być android:resource- ustawienie, android:valuektóre nie zadziała
flochtililoch
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.