Ich habe versucht, die Firebase-Push-Benachrichtigung in Java zu implementieren

Was du machen willst

Verordnung

Einführung danke

Um ehrlich zu sein, hatte ich unter iOS nicht viel Referenzmaterial, also ich habe es selbst implementiert, aber für Android dieser Artikel war sehr hilfreich. Ich brauchte jedoch einige zusätzliche Kenntnisse darüber, was ich dieses Mal implementieren wollte, daher enthält dieser Artikel auch diese.

Implementierungspunkte

Initialisierung in Aktivität

Zuallererst die Hauptaktivität. Dies ist ** nur eine Zeile, Themenzusatz ** für die FCM-Initialisierung. ** Wenn Sie es nicht einmal brauchen, brauchen Sie nichts **, aber dann können Sie keine Benachrichtigungen separat zwischen hier und der iOS-Versions-App senden.

MainActivity.java


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        FirebaseMessaging.getInstance().subscribeToTopic("TOPICNAME");

        // other initializing...
    }

Holen Sie sich Geräte-Token

Holen Sie sich als Nächstes das generierte / aktualisierte Geräte-Token. Dies ist wichtig, wenn Sie unterschiedliche Benachrichtigungen für unterschiedliche Geräte wünschen [^ 1], aber die genaue Zeit, zu der Sie dies tun können, ist "FirebaseInstanceIdService # onTokenRefresh". Sie können dies überschreiben und das Gerätetoken zu diesem Zeitpunkt an Ihren eigenen Server senden.

Diesmal muss ich jedoch nur Benachrichtigungen an alle Benutzer gleichzeitig senden können, und ich bin mir nicht sicher, ob ich den Dienst "FirebaseInstanceIdService" noch benötige. Wenn Sie es nicht brauchen, wird es wieder ** "Sie müssen nichts tun" ** sein. Da ich mich jedoch etwas unwohl fühlte, entschied ich mich, nur den Dienst laufen zu lassen, und stellte ihn so ein, dass die Superklasse direkt als Dienst gestartet wurde, ohne eine Unterklasse zu erstellen. Ist das okay?

AndroidManifest.xml


    <service android:name="com.google.firebase.iid.FirebaseInstanceIdService">
      <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
      </intent-filter>
    </service>

Korrespondenz der Rezeption im Vordergrund

Sogar in FCM GCM-Artikel, den ich in meinem vorherigen Job geschrieben habe (Kapitel "Tag, das Android-Benachrichtigungen automatisch überschreiben und aktualisieren kann") -2.html) hat die Aktualisierungsspezifikation nicht geändert ** "Wenn Sie Standardbenachrichtigungen unter Android / nur im Hintergrund erhalten, müssen Sie keinen Code schreiben" **. Diesmal müssen Sie aber auch die Benachrichtigung im Vordergrund behandeln. Dazu können Sie "FirebaseMessagingService # onMessageReceived" überschreiben und dies tun. Unter diesen können Sie denselben Inhalt wie die im Hintergrund angezeigte Benachrichtigung generieren und als ausstehende Absicht registrieren.

Ich meine, das ist @ kirimins Artikel Es ist fast dasselbe. Es ist nur ein dankbarer Regensturm (totes Wort). Es wird jedoch nur die Generierung der Absicht geändert, wenn auf die von diesem Code angezeigte Benachrichtigung getippt wird. Grundsätzlich ist diese Absicht in den In-Prozess gerutscht, oh, COM brain (und aus irgendeinem Grund, wenn Sie dies eingeben) Da es nur in der eigenen Anwendung verwendet wird und nicht im Pro-Less-Gehirn, in dem der Finger rutscht und nicht weniger schlägt, frage ich mich außerdem, ob die Zeichenkettenkonstante in "MainActivity" definiert und verwendet werden sollte. Das sind "MainActivity.ARG_FRAGMENT" und "MainActivity.PUSH_NOTIFICATION_ACTION".

FirMessagingService.java


public class FirMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Map<String, String> data = remoteMessage.getData();
        if (data == null) {
            return;
        }
        String fragment = data.get(MainActivity.ARG_FRAGMENT);
        if (fragment == null) {
            return;
        }

        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
        builder.setSmallIcon(R.drawable.notification);
        builder.setContentTitle(remoteMessage.getNotification().getTitle());
        builder.setContentText(remoteMessage.getNotification().getBody());
        builder.setDefaults(Notification.DEFAULT_SOUND
                | Notification.DEFAULT_VIBRATE
                | Notification.DEFAULT_LIGHTS);
        builder.setAutoCancel(true);

        //Ausstehende Absicht erstellen
        Intent intent = new Intent(this, MainActivity.class);
        intent.setAction(MainActivity.PUSH_NOTIFICATION_ACTION);
        intent.putExtra(MainActivity.ARG_FRAGMENT, fragment);
        PendingIntent contentIntent = PendingIntent.getActivity(
                getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(contentIntent);

        //Benachrichtigungsanzeige
        NotificationManagerCompat manager = NotificationManagerCompat.from(getApplicationContext());
        manager.notify(0, builder.build());
    }
}

Vergessen Sie natürlich nicht, diese Unterklasse als Dienst zu registrieren.

AndroidManifest.xml


    <service android:name=".FirMessagingService">
      <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
      </intent-filter>
    </service>

Verarbeitung beim Tippen auf Benachrichtigung

Diesbezüglich funktioniert die Regelung "Startmodus ist Einzelaufgabe" äußerst effektiv, und es gibt nur zwei Muster, die beim Tippen auf eine Benachrichtigung auftreten können. (Beachten Sie, dass diese Regelung nichts mit FCM zu tun hat. Es ist eine übliche Methode, immer nur eine eigene Anwendung auf Android zu starten, und sie ist sehr verbreitet [^ 2].)

Aktivität Wird beim Tippen aufgerufen
AppCompatActivityMethode von
Wie man eine Absicht bekommt
Während des Startvorgangs onNewIntent onNewIntentArgumente von
Nicht angefangen onCreate getIntentMethode

In beiden Fällen können Sie eine Absicht erhalten, die genau dieselben Informationen enthält, sodass Sie sie mit einer gängigen Methode verarbeiten können.

MainActivity.java


    public static final String PUSH_NOTIFICATION_ACTION = "FCM";
    public static final String ARG_FRAGMENT = "fragment";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        FirebaseMessaging.getInstance().subscribeToTopic("TOPICNAME");
        int fragmentId = onIntent(getIntent());
        if (fragmentId == 0) {
            //Ruft den ID-Wert des zuletzt angezeigten Fragments ab
            fragmentId = PreferenceManager.getDefaultSharedPreferences(this).getInt(PreferenceKey.RECENT_FRAGMENT_POSITION, 0);
        }

        // other initializing

        changeFragment(fragmentId, true);
    }

    @Override
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        changeFragment(onIntent(intent), false);
    }

    //Rufen Sie die ID des Fragments, das Sie anzeigen möchten, aus der Benachrichtigungsabsicht ab
    //In dieser Implementierung für Benachrichtigungen{"fragment":"info"}Wenn der KV enthalten ist, versuche ich, den Infobildschirm anzuzeigen
    //Wenn Sie Reflektion verwenden, benötigen Sie keine bedingte Verzweigung.(^^ゞ
    private int onIntent(Intent intent) {
        if (intent != null && "info".equals(intent.getStringExtra(ARG_FRAGMENT))) {
            return R.id.info;
        } else {
            return 0;
        }
    }

    //Einzigartige Methode zum Wechseln zu Fragment, angegeben durch fragmentId, falls vorhanden
    //Wenn isFirst true ist, wird das Standardfragment angezeigt, wenn fragmentId 0 ist
    //Wenn falsch, nichts tun
    private void changeFragment(int fragmentId, boolean isFirst) {
        //Geben wir unser Bestes
    }

Stellen Sie dann den Absichtsfilter richtig ein, damit "MainActivity" die Absicht der Benachrichtigung empfangen kann. Der Grund wird später erklärt, aber der Aktionsname "FCM" muss dieselbe Zeichenfolge sein wie "MainActivity.PUSH_NOTIFICATION_ACTION" **.

AndroidManifest.xml


    <activity android:label="@string/app_name" android:name=".MainActivity"
        android:taskAffinity="com.wsf_lp.oritsubushi.map" android:launchMode="singleTask">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      <intent-filter>
        <action android:name="FCM" />
        <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
    </activity>

Die wichtigste Geschichte: Die Bedeutung verschiedener String-Literale verstehen

Wenn Sie dies nicht nur auf der Anwendungsseite, sondern auch auf Ihrer eigenen Serverseite nicht richtig machen, werden Sie tatsächlich irgendwo in der Reihe der Bewegungen "Senden und Empfangen von Benachrichtigungen und Umschalten der Anzeige" stolpern.

Daher habe ich die Liste der Zeichenfolgenliterale, die bisher in der Codeserie veröffentlicht wurden, und ihre Bedeutung zusammengefasst.

String Erscheinungsort Bedeutung Wo anwendbar
"FCM" Manifest
Hauptaktivität
Absichtsaktionsname Von der FCM-Benachrichtigungsnutzlastclick_actionDer Wert des
onMessageReceivedAbsicht erstellt mit
onNewIntentAbsicht weitergegeben an
onCreateIm InnerengetIntentAbsicht durch Anruf erhalten
"fragment" FirebaseMessagingService
Hauptaktivität
Name des Benutzerdatenschlüssels Schlüsselname in der FCM-Datennutzlast
onMessageReceivedSchlüsselname in entfernten Daten, die mit abgerufen werden können
"info" FirebaseMessagingService
Hauptaktivität
Benutzerdatenwert Von der FCM-Datennutzlast"fragment"Der Wert der
onMessageReceivedで取得できるリモートデータ内Der Wert der

Es ist einfach zusammenzufassen, aber "FCM-Nutzdaten" werden in allen Elementen in der Tabelle angezeigt. In der Tat ist es am wichtigsten, die Nutzdaten auf Ihrem eigenen Server zu verstehen, die die an FCM zu sendenden Daten weiterleiten. Mit anderen Worten bedeutet dies auch, dass ** beim Verknüpfen des Betriebs der App mit Push-Benachrichtigungen das Auslassen von "Einfache Eingabe des Benachrichtigungsinhalts über den Benachrichtigungsbildschirm der Firebase-Konsole und Klicken (totes Wort)" nicht zulässig ist **. (In Anbetracht des später beschriebenen Symbolproblems ist die aktuelle Konsole natürlich von Anfang an unbrauchbar.)

In Bezug auf die FCM-Nutzlast ist sie im offiziellen Dokument aufgeführt, aber es reicht nicht aus, nur diese [alle Formate] zu verwenden. Es scheint wichtig zu sein, (https://firebase.google.com/docs/cloud-messaging/http-server-ref) richtig zu lesen.

FCM-Nutzlast

In diesem Sinne sind hier die JSONs, die ich von meinem eigenen Server an den FCM-Server sende.

{
  "to": "In der App registrierter Themenname",
  "notification": {
    "title": "Benachrichtigungstitel",
    "body": "Benachrichtigungsstelle",
    "click_action": "FCM",
    "icon": "notification"
  },
  "data": {
    "fragment": "info"
  }
}

Das Wichtigste in FCM ist die "Benachrichtigung", die Benachrichtigungsnutzlast. Neben "title" und "body" ist "click_action" einer der Schlüssel. Dies ist genau der Wert der Aktion, die in der Android-Push-Benachrichtigungsabsicht enthalten ist [^ 3]. Und mit dem Wert dieser Aktion ist es die Einstellung des Absichtsfilters im Manifest, die verhindert, dass die Aktivität der App zusätzliche Absichten erhält. Daher müssen * die "click_action" der an den FCM-Server gesendeten Benachrichtigungsnutzdaten und der Aktionsname des im Manifest festgelegten Absichtsfilters mit * und * der vom Benutzer generierten Absicht übereinstimmen, die Benachrichtigung auch im Vordergrund anzuzeigen. Aktionsnamen müssen ebenfalls identisch sein *.

Andererseits sind die "Daten", die in FCM optional sind, dh die Datennutzlast, ein normales Wörterbuch. Und dies ist diejenige, die an die "RemoteMessage" übergeben wird, die vom Argument "FirebaseMessagingService # onMessageReceived" übergeben wird, und die auch durch das Argument "getIntent" oder "onNewIntent" erhalten wird, das in "onCreate" der Aktivität aufgerufen wird. Dies ist der Wert, der als Extra der beabsichtigten Absicht festgelegt wird. Also * müssen diese Schlüsselnamen übereinstimmen * und * Sie müssen denselben Wert als Extra mit demselben Schlüsselnamen in Ihre eigene generierte Absicht kopieren, um die Benachrichtigung auch im Vordergrund anzuzeigen. *.

Da es diesmal nicht internationalisiert wird, ist es außerdem so, als würde man Japanisch schreiben, wie es in "Titel" und "Körper" steht, aber wenn Internationalisierung notwendig ist GCM-Artikel in meinem vorherigen Job geschrieben (: //www.mate-en.com/techblog/google-cloud-messaging-2.html) sollte hilfreich sein.

Benachrichtigungssymbol

Und wieder, obwohl nicht direkt mit dem Code verbunden. Unter Android kann ein Symbol in der Benachrichtigungsanzeige angezeigt werden. Und in älteren Versionen von GCM vor FCM wird "GCMListenerService # onMessageReceived" * immer * aufgerufen *, unabhängig davon, ob sich die App im Vordergrund oder im Hintergrund befindet * (daher muss "GCM ListerService" ein Dienst sein. (Ich habe es nicht getan), und ich habe die Benachrichtigungen immer selbst erstellt (nur im Prozess selbst in "onMessageReceived" im Vordergrund im aktuellen FCM). Natürlich konnte ich dort das Benachrichtigungssymbol setzen. Das neue GCM danach, das fast das aktuelle FCM ist, führte jedoch die Spezifikation ein, dass * im Hintergrund "onMessageReceived" nicht * genannt wird. Infolgedessen können Sie das Symbol nicht im Hintergrund einstellen. Um dies zu vermeiden, wurde der Schlüsselname "icon" zur Benachrichtigungsnutzlast von GCM hinzugefügt und auf den aktuellen FCM übertragen.

{
  "notification": {
    "icon": "notification"
  }
}

Und dies ist auch eine Metamorphose, aber nehmen wir an, Sie setzen den Wert "Benachrichtigung" wie oben auf "Symbol". Dieser Wert von "Benachrichtigung" wurde auf der App-Seite "R.drawable.notification" zugeordnet. Natürlich ist dieses Symbol ein ID-Wert, und wenn das Symbol eine Bilddatei ist, insbesondere eine Datei mit dem Namen "res / drawable / notification.png " (natürlich wurde der Stoff durch Auflösung / SDK-Version / lokal usw. geteilt). (In Ordnern verteilt) wird als Symbol verwendet. Der Punkt ist, dass ** der Dateiname (ohne die Erweiterung) des PNG-Bildes für das Symbol der Wert des Symbols "Schlüssel" der Benachrichtigungsnutzlast ist **. Mit anderen Worten, um das Benachrichtigungssymbol anzuzeigen, können Sie normalerweise (viele!) Symbolbilder erstellen, diese entsprechend unter res / drawable / platzieren und den Dateinamen an den FCM-Server übergeben. Natürlich muss dasselbe Symbol in "onMessageReceived" gesetzt sein, damit die Benachrichtigung auch im Vordergrund angezeigt wird.

Dieses Gefühl, dass "die Zeichenfolge des Dateinamens im Java-Code zu einem Symbolnamen und beim Verweisen zu einem ganzzahligen Wert wird, beim Aufrufen vom Server jedoch mit einer Zeichenfolge angegeben wird", geht um und kehrt zum ursprünglichen Gefühl zurück .. Wie erwartet ist es Android (verbrannte Brust) [^ 4].

Fazit

Hinweis

[^ 1]: Wenn es sich um eine SNS- oder Chat-App handelt, hängt der zu benachrichtigende Inhalt vom Benutzer ab. Daher werden die Gerätetoken des Benutzers und des Terminals (natürlich kann derselbe Benutzer mehrere Geräte verwenden, sodass RDB sie in der Tabelle n: m verwaltet) auf der eigenen Serverseite verknüpft, um einen bestimmten Benutzer zu benachrichtigen. Das Senden nur an alle Geräte dieses Benutzers ist erforderlich. Für die Benachrichtigung nur des Geräts dieses bestimmten Benutzers ist ein Geräte-Token erforderlich, und Android kann dieses Geräte-Token ändern. Bei jeder Änderung wird der eigene Server informiert. Muss sein. [^ 2]: Ah, in der Win32-Ära wurde dies mit einem benannten Mutex durchgeführt ... Frühe Windows-Version Eclipse hat einfach zu oft auf das Symbol geklickt und mehrmals gestartet, um den Arbeitsbereich, einen dedizierten Launcher, nicht zu beschädigen Ich habe es mit CreateMutex geschrieben ... (Aufgrund alter Augen, entfernter Augen) [^ 3]: Übrigens ist "click_action", eine Schaltfläche, die angezeigt wird, wenn Sie eine Benachrichtigung unter iOS durchwischen (sofern die App dies unterstützt) = mit einer benutzerdefinierten Aktion verknüpft. Es ist ein Schlüssel, der von GCM geerbt wurde, aber es ist erstaunlich, dass er mit beiden Betriebssystemen kompatibel ist! Es ist ein Lob. [^ 4]: Natürlich wäre es bei älteren Androiden, die über sehr schlechte Ressourcen verfügten, notwendig gewesen, Symbole in ganzzahlige Werte umzuwandeln und zu bauen. Und selbst in der heutigen Zeit, in der dies nicht der Fall ist, besteht der Vorteil, dass die Code-Vervollständigung von IDE problemlos funktioniert (selbst in früheren Zeiten wurde sie als schlechtes Know-how von VC ++ missbraucht, indem alles in eine mysteriöse Klasse gestopft wurde). Nein, aber ich bin auch der Meinung, dass ein wesentlicher Teil der Unangemessenheit der Win32-API darin besteht, dass sie von Win16 zu stark in Mitleidenschaft gezogen wurde, um den Code der OLE-Steuerelemente, die das Unternehmen intern für VB erstellt hat, kompatibel (oder eher böse) zu machen. Die Wurzel kann VB älter als Win16 sein ??), Android wird auch durch verschiedene Dinge wie die Einschränkung der Methode 64k gezogen (was zu einer Scala-Konvertierung führt, ist sehr schwierig) ... Ist es etwas, das auf jeden Fall eine Geschichte hat? ..

Recommended Posts

Ich habe versucht, die Firebase-Push-Benachrichtigung in Java zu implementieren
Ich habe versucht, die Methode der gegenseitigen Teilung von Eugrid in Java zu implementieren
Ich habe versucht, polymorph in Nogizaka zu implementieren.
Ich habe versucht, neunundneunzig in Java auszugeben
Ich habe versucht, Alexa-Fähigkeiten mit Java zu erstellen
Ich habe versucht, Metaprogrammierung mit Java
Ich habe versucht, TCP / IP + BIO mit JAVA zu implementieren
# 2 [Anmerkung] Ich habe versucht, neunundneunzig mit Java zu berechnen.
Ich habe versucht, eine Clova-Fähigkeit in Java zu erstellen
Ich habe versucht, eine Anmeldefunktion mit Java zu erstellen
Ich habe versucht, Sterling Sort mit Java Collector zu implementieren
[Java] Ich habe versucht, die Yahoo API-Produktsuche zu implementieren
~ Ich habe jetzt versucht, funktionale Programmierung mit Java zu lernen ~
Ich habe versucht herauszufinden, was sich in Java 9 geändert hat
Ich habe versucht, mit Java zu interagieren
Ich habe versucht, JWT in Java zu verwenden
Ich habe versucht, das Java-Lernen zusammenzufassen (1)
Versuchen Sie, Yuma in Java zu implementieren
Ich habe jetzt versucht, Java 8 zusammenzufassen
Ich habe versucht, in Java von einer Zeichenfolge in einen LocalDate-Typ zu konvertieren
Ich habe versucht, Dapr in Java zu verwenden, um die Entwicklung von Mikroservices zu erleichtern
Ich habe versucht, eine Webanwendung voller Fehler mit Kotlin zu implementieren
Ich habe einen RESAS-API-Client in Java erstellt
Ich habe versucht, die Elasticsearch-API in Java zu verwenden
So implementieren Sie die Datumsberechnung in Java
So implementieren Sie den Kalman-Filter mit Java
Ich habe versucht, die Ajax-Verarbeitung der ähnlichen Funktion in Rails zu implementieren
Versuchen Sie, n-ary Addition in Java zu implementieren
Ich habe versucht, Java-Lambda-Ausdrücke zusammenzufassen
Ich habe das neue Yuan-Problem in Java ausprobiert
Ich habe versucht, Java-Anfänger so einzustellen, dass sie Tastenkombinationen in Eclipse verwenden
Ich habe versucht, das Iterator-Muster zu implementieren
So erzwingen Sie Codierungskonventionen in Java
Ich habe versucht, mit AI "A3RT" eine Talk-App in Java zu erstellen.
Ich habe versucht, eine Standardauthentifizierung mit Java durchzuführen
Ich möchte eine E-Mail in Java senden.
Ich habe versucht, die Sitzung in Rails zu organisieren
Java Ich habe versucht, einen einfachen Block zu brechen
Senden Sie Push-Benachrichtigungen über Notification Hubs in Java
Ich wollte (a == 1 && a == 2 && a == 3) in Java wahr machen
rsync4j - Ich möchte rsync in Java berühren.
Ich habe versucht, eine Anwendung in 2 Sprachen zu entwickeln
Ich habe versucht, einen Server mit Netty zu implementieren
Ich habe versucht, den Block mit Java zu brechen (1)
Versuchte Mastodons Toot- und Streaming-API in Java
Ich habe versucht, das Hochladen von Dateien mit Spring MVC zu implementieren
Ich möchte so etwas wie "cls" in Java machen
[Java 11] Ich habe versucht, Java auszuführen, ohne mit Javac zu kompilieren
[Java] Ich habe versucht, Paizas B-Rang-Problem zu lösen
Ich habe versucht, SQS mit AWS Java SDK zu betreiben
Ich möchte ES2015 auch in Java verwenden! → (´ ・ ω ・ `)
Ich habe versucht, die erweiterte for-Anweisung in Java zu verwenden
Zusammenfassung der Implementierung von Standardargumenten in Java
Ich habe versucht, Java Silver in 2 Wochen zu bestehen, ohne Java zu kennen