Cordova-plugin-firebase: (Android) Klick auf Benachrichtigung löst nicht aufNotificationOpen Callback aus

Erstellt am 21. Sept. 2016  ·  28Kommentare  ·  Quelle: arnesson/cordova-plugin-firebase

Cordova 6.3.1
Phonegap Firebase-Plugin 0.1.12
Gerät: LG G5 mit Android 6.0.1

Dies ist der Code, den ich verwende:
`var-App = {
// Anwendungskonstruktor
initialisieren: Funktion () {
this.bindEvents();
},
// Ereignislistener binden
//
// Alle beim Start erforderlichen Ereignisse binden. Häufige Ereignisse sind:
// 'load', 'deviceready', 'offline' und 'online'.
bindEvents: Funktion () {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// gerätebereiter Event-Handler
//
// Der Geltungsbereich von 'this' ist das Ereignis. Um das 'receivedEvent' aufzurufen
// Funktion, wir müssen explizit 'app.receivedEvent(...);'
onDeviceReady: Funktion () {
console.log ("Estamos en onDeviceReady");
if (navigator.connection.type == Connection.NONE) {
navigator.notification.alert('Se requiere conexión a Internet');
} anders {
window.FirebasePlugin.onNotificationOpen(Funktion(Benachrichtigung) {
console.log (Benachrichtigung);
navigator.notification.alert ("Recibido");
}, Funktion (Fehler) {
Konsole.log(Fehler);
});
}
},

};
app.initialize();`

Ich erhalte Benachrichtigungen in der Taskleiste des Systems in allen Situationen: App im Hintergrund, Vordergrund und geschlossen und wenn ich auf Benachrichtigung klicke, ist die App in den drei Fällen geöffnet, aber der Rückruf wird nicht ausgelöst.

Stimmt etwas im Code nicht?

Vielen Dank im Voraus.

Hilfreichster Kommentar

Ich habe das gesamte onNotificationOpen Handling neu geschrieben und es funktioniert fast so, wie ich es erwarten würde, nämlich:

  • Benachrichtigung kommt mit Client im Vordergrund, offene Benachrichtigung und onNotificationOpen wird im aktuellen Client aufgerufen (ohne Reload)
  • Benachrichtigung kommt mit Client im Hintergrund, offene Benachrichtigung und Client wird in den Vordergrund geholt und onNotificationOpen wird mit aktuellem Client aufgerufen (ohne Reload)

Es bleibt nur noch, die Benachrichtigung, wenn überhaupt (noch nicht nachgesehen) ohne Öffnen sofort an den Auftraggeber zustellen zu lassen.

Ich bin ein bisschen ein Android-Noob, daher können einige Verbesserungen vorgenommen werden, aber es scheint gut zu funktionieren, also dachte ich, ich würde es teilen.

OnNotificationOpe nReceiver:onReceive ruft jetzt einfach an

FirebasePlugin.onBroadcastReceive(context, intent);

FirebasePlugin wie folgt geändert

  • Entfernen Sie WeakReference aus callbackContext
  • add onBroadcastReceive-Methode, übergibt Absichtsdaten an onNotificationOpen
  • add onNewIntent-Methode, übergibt Absichtsdaten an onNotificationOpen
  • alte Version von onNotificationOpen wiederhergestellt und wie folgt geändert

    • entfernte WeakReference-Zeile

    • Ändern Sie Callbacks, um ein PluginResult zu verwenden, und rufen Sie setKeepCallback(true) für das Ergebnis auf, um zu verhindern, dass der Callback nach dem ersten Aufruf entfernt wird

    private static CallbackContext callbackContext;
    // ...
    private void registerOnNotificationOpen(final CallbackContext callbackContext) {
        FirebasePlugin.callbackContext = callbackContext;
    }

    // called when in foreground
    public static void onBroadcastReceive(Context context, Intent intent) {
        Log.d("FirebasePlugin", "onBroadcastReceive");
        Bundle data = intent.getExtras();
        FirebasePlugin.onNotificationOpen(data);
    }

    // called when in background
    <strong i="32">@Override</strong>
    public void onNewIntent(Intent intent) {
        Log.d(TAG, "new intent " + intent);
        super.onNewIntent(intent);
        FirebasePlugin.onNotificationOpen(intent.getExtras());
    }

    public static void onNotificationOpen(Bundle bundle) {
        if (FirebasePlugin.callbackContext == null ) {
            Log.d("FirebasePlugin", "no callback context, onNotificationOpen ignored");
            return;
        }
        if (callbackContext != null && bundle != null) {
            JSONObject json = new JSONObject();
            Set<String> keys = bundle.keySet();
            for (String key : keys) {
                try {
                    json.put(key, bundle.get(key));
                } catch (JSONException e) {
                    Log.d("FirebasePlugin", "onNotificationOpen: json exception");
                    PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);
                    return;
                }
            }
            Log.d("FirebasePlugin", "onNotificationOpen: send notification to javascript");
            PluginResult result = new PluginResult(PluginResult.Status.OK, json);
            result.setKeepCallback(true);
            callbackContext.sendPluginResult(result);
        }
    }

Alle 28 Kommentare

gleiches Problem, auf Android kommen Benachrichtigungen an, aber innerhalb der App wird kein Rückruf aufgerufen.
v. 0.1.12

@voidbrain @Kibukita Bitte

@BugsBunnyBR Ich habe gerade versucht, auf die neueste Version des

@superheroben , könnten Sie ein Repo mit einem Beispiel dafür

Selbes Problem hier.
getInstanceId() Callback wird aufgerufen, Benachrichtigung kommt an, aber onNotificationOpen() wird nie aufgerufen.

Kundencode:

if (window.FirebasePlugin)
{
  window.FirebasePlugin.getInstanceId(
    function(token) {
        thiss.saveToken(token);
    }, 
    function(error) {
        console.log(error);
    }
  );

  window.FirebasePlugin.onNotificationOpen(
    function(notification) {                  
      alert("Yeah!!!");                  
    }, 
    function(error) {
      alert("Error!");
      console.error(error);
    }
  );

  window.FirebasePlugin.grantPermission();
}

Meine Benachrichtigungsdatenstruktur:

(
    [to] => (device token)
    [notification] => Array
        (
            [title] => Title
            [text] => Test message
            [sound] => default
            [vibrate] => 1
            [badge] => 2
        )
)

Mein serverseitiger Code (PHP):

$jsonData = json_encode($data);

$ch     = curl_init("https://fcm.googleapis.com/fcm/send");
$header = array(
    'Content-Type: application/json',
    "Authorization: key=".MY_GCM_API_KEY
);

curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, true);
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);

$result = curl_exec($ch);
curl_close($ch);

Arbeiten mit Cordova Android 5.2.2. Auf dem zum Testen verwendeten Gerät läuft Android 4.4.2. Plugin-Version 0.1.12.

@arivanbastos , haben Sie versucht, auf das Github-Repository zu verweisen?

Die Installation von github hat das Problem teilweise gelöst. Danke schön.

cordova plugin remove cordova-plugin-firebase
cordova plugin add https://github.com/arnesson/cordova-plugin-firebase/

Jetzt wird der onNotificationOpen()-Callback aufgerufen, wenn sich die App im Hintergrund befindet.
Wenn sich die App im Vordergrund befindet, kommt die Benachrichtigung statt der Dokumentation an, und onNotificationOpen() wird nicht aufgerufen:

App steht im Vordergrund:
Der Benutzer erhält die Benachrichtigungsdaten im JavaScript-Callback ohne Benachrichtigung auf dem Gerät selbst (dies ist das normale Verhalten von Push-Benachrichtigungen, es liegt an Ihnen, dem Entwickler, den Benutzer zu benachrichtigen)

Wenn Sie einen Push vom Typ "Benachrichtigung" (ohne Datenkörper) senden, sollte die Benachrichtigung nicht angezeigt werden, wenn die App im Vordergrund ist.

Entschuldigung, ich habe es nicht verstanden. Soll ich meinen Benachrichtigungsdaten einfach einen Abschnitt "Daten" hinzufügen?

(
    [to] => (device token)
    [notification] => Array
        (
            [title] => Title
            [text] => Test message
        )
    [data] => Array
        (
            [test] => 1
        )
)

Dies hat das Problem nicht behoben.

Das Umbenennen des Abschnitts "Benachrichtigung" in "Daten" führt zum Absturz der App ("App wurde gestoppt"), wenn eine Benachrichtigung eintrifft:

(
    [to] => (device token)
    [data] => Array
        (
            [title] => Title
            [text] => Test message
        )
)

https://firebase.google.com/docs/cloud-messaging/android/receive
Hier ist es sehr gut beschrieben.
Ihre Benachrichtigung geht in den System-Tray, wenn die App im Hintergrund ist und in onMessageReceived(), wenn die App im Vordergrund ist.
Wenn Ihre Nachricht Daten enthält, werden diese immer an onMessageReceived() übergeben.

Ich denke, dass es ein Problem bei der Implementierung von onMessageReceived() gibt.
Wenn ich mir den Code ansehe, den ich interpretiere, ist Folgendes:

  • Daten extrahieren
  • Erstellen einer Benachrichtigung mit NotificationBuilder
  • über NotificationManager benachrichtigen

NotificationManager.notify(id, notification) postet die in der Statusleiste anzuzeigende Benachrichtigung.

Für mich scheint dies jedoch zu erwarten, dass jedes Mal, wenn ich eine Nachricht von FCM erhalte, eine Benachrichtigung in der Statusleiste angezeigt wird.
Ich sehe keine Überprüfung, ob die App im Vordergrund ist und ich sehe keinen Anruf beim Rückruf. Ich bin kein Android-Entwickler, also liege ich vielleicht falsch, aber das beschriebene Verhalten passt dazu.

OK, ich habe den Code gefunden, der den Rückruf aufruft.
Beim letzten Commit von BugsBunnyBR gab es eine Änderung im OnNotificationOpenReceiver, die erklärt, dass arivanbastos seinen Callback ausgeführt bekommt, wenn er auf das Github-Repository zeigt.

Trotzdem wird die Benachrichtigung nur gesendet (an den OnNotificationOpenReceiver und den NotificationManager), wenn entweder ein Text oder ein Titel (in der Benachrichtigung oder in den Daten) vorhanden ist. Das bedeutet, dass es nicht möglich ist, Daten an Ihre App zu senden, ohne dass die Benachrichtigung an den NotificationManager gesendet wird, der sie in der Statusleiste anzeigt.

@arivanbastos
Ich habe etwas Falsches zu dir gesagt. Das tut mir leid.
Haben Sie versucht, auf diese Repo-Version zu verweisen?

@packowitz und @robertarnesson . Ok, meine Implementierung wird IMMER* versuchen, die Benachrichtigung anzuzeigen. Oder die automatisch angezeigte Firebase-Benachrichtigung oder der Build in onMessageReceived wird angezeigt.
Der onNotificationOpen Callback wird aufgerufen, wenn onMessageReceived aufgerufen wird oder wenn die Benachrichtigung gleichzeitig Daten- und Benachrichtigungstexte enthält. In meiner PR , die das onNotificationOpen ich versucht zu erklären, dass Push-Benachrichtigungen vom Typ Benachrichtigung den Rückruf nicht auslösen. Es wird empfohlen, immer einen Daten- und einen Benachrichtigungstext einzuschließen, damit das Plugin den Rückruf erkennen und auslösen kann.

Ich weiß, dass das ständige Anzeigen der Benachrichtigung nicht das Standardverhalten von Firebase-Benachrichtigungen ist.

Die meisten Android-App-Entwickler möchten, dass ihre Benachrichtigung in der Taskleiste angezeigt wird, auch wenn die App im Vordergrund ist. Ich weiß, dass es in Chat-Apps Fälle gibt, in denen dieses Verhalten nicht gut ist.
Als ich die Android-Benachrichtigungsfunktion entwickelte, waren mir die Anforderungen an Chat-Apps oder die Einhaltung von Firebase egal.

Was getan werden kann ist:
1) Entwickeln Sie ein Flag, das gesetzt wird, wenn die App geöffnet ist und sagt "Hey, ich möchte, dass Sie die Benachrichtigung auch dann anzeigen, wenn die App geöffnet ist" und verwenden Sie es, um das Verhalten zu steuern. Es müsste nicht in einem Speicher gespeichert werden, wenn die App beim Öffnen immer das Flag setzen würde.

2) Kommentieren Sie einfach diese Zeile und deaktivieren Sie die Benachrichtigung, wenn sich die App im Vordergrund befindet.

_Immer_ -> Wenn das Plugin einen "Text" oder "Titel" im Benachrichtigungstext findet.

@BugsBunnyBR Ich mag die Idee, eine Flagge zu haben, um das Verhalten auszuwählen.
Ich würde den NotificationManager vom OnNotificationOpenReceiver entkoppeln und deinen JS-Callback zurückrufen. Meine Empfehlung ist, eine Prüfung einzuführen, ob Daten in der Nachricht sind und wenn ja, dann den Rückruf mit den Daten aufrufen.
Für die Benachrichtigung wäre es gut, die Flagge zu haben.
Danke schön.

@BugsBunnyBR Ich habe gerade getestet, um zum Github-
Aber der Rückruf funktioniert jetzt ;)

Auch hier verursacht die Version 0.1.13 für mich einen Neustart meiner App, nur wenn sie im Vordergrund ist. Version 0.1.12 funktioniert einwandfrei.

Benachrichtigungen funktionieren in der Repo-Version einfach nicht sinnvoll. Der Grund ist meiner Meinung nach, wenn onNotificationOpen aufgerufen wird, bevor eine Benachrichtigung geöffnet wurde, wird sie ignoriert.

https://github.com/arnesson/cordova-plugin-firebase/blob/master/src/android/FirebasePlugin.java#L123

In registerOnNotificationOpen wird der Rückruf nur registriert, wenn ein notificationBundle wartet

Außerdem scheint der Grund, warum die App neu geladen wird, wenn sie bereits geöffnet ist, in OnNotificationOpenReceiver , heißt es ausdrücklich

launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);

https://github.com/arnesson/cordova-plugin-firebase/blob/master/src/android/OnNotificationOpenReceiver.java#L17

was den Client zum Neuladen zwingt, wenn notificationBundle verfügbar ist, wenn onNotificationOpen Rückruf registriert ist, damit der Client dann die Benachrichtigung erhält.

Ich habe das gesamte onNotificationOpen Handling neu geschrieben und es funktioniert fast so, wie ich es erwarten würde, nämlich:

  • Benachrichtigung kommt mit Client im Vordergrund, offene Benachrichtigung und onNotificationOpen wird im aktuellen Client aufgerufen (ohne Reload)
  • Benachrichtigung kommt mit Client im Hintergrund, offene Benachrichtigung und Client wird in den Vordergrund geholt und onNotificationOpen wird mit aktuellem Client aufgerufen (ohne Reload)

Es bleibt nur noch, die Benachrichtigung, wenn überhaupt (noch nicht nachgesehen) ohne Öffnen sofort an den Auftraggeber zustellen zu lassen.

Ich bin ein bisschen ein Android-Noob, daher können einige Verbesserungen vorgenommen werden, aber es scheint gut zu funktionieren, also dachte ich, ich würde es teilen.

OnNotificationOpe nReceiver:onReceive ruft jetzt einfach an

FirebasePlugin.onBroadcastReceive(context, intent);

FirebasePlugin wie folgt geändert

  • Entfernen Sie WeakReference aus callbackContext
  • add onBroadcastReceive-Methode, übergibt Absichtsdaten an onNotificationOpen
  • add onNewIntent-Methode, übergibt Absichtsdaten an onNotificationOpen
  • alte Version von onNotificationOpen wiederhergestellt und wie folgt geändert

    • entfernte WeakReference-Zeile

    • Ändern Sie Callbacks, um ein PluginResult zu verwenden, und rufen Sie setKeepCallback(true) für das Ergebnis auf, um zu verhindern, dass der Callback nach dem ersten Aufruf entfernt wird

    private static CallbackContext callbackContext;
    // ...
    private void registerOnNotificationOpen(final CallbackContext callbackContext) {
        FirebasePlugin.callbackContext = callbackContext;
    }

    // called when in foreground
    public static void onBroadcastReceive(Context context, Intent intent) {
        Log.d("FirebasePlugin", "onBroadcastReceive");
        Bundle data = intent.getExtras();
        FirebasePlugin.onNotificationOpen(data);
    }

    // called when in background
    <strong i="32">@Override</strong>
    public void onNewIntent(Intent intent) {
        Log.d(TAG, "new intent " + intent);
        super.onNewIntent(intent);
        FirebasePlugin.onNotificationOpen(intent.getExtras());
    }

    public static void onNotificationOpen(Bundle bundle) {
        if (FirebasePlugin.callbackContext == null ) {
            Log.d("FirebasePlugin", "no callback context, onNotificationOpen ignored");
            return;
        }
        if (callbackContext != null && bundle != null) {
            JSONObject json = new JSONObject();
            Set<String> keys = bundle.keySet();
            for (String key : keys) {
                try {
                    json.put(key, bundle.get(key));
                } catch (JSONException e) {
                    Log.d("FirebasePlugin", "onNotificationOpen: json exception");
                    PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);
                    return;
                }
            }
            Log.d("FirebasePlugin", "onNotificationOpen: send notification to javascript");
            PluginResult result = new PluginResult(PluginResult.Status.OK, json);
            result.setKeepCallback(true);
            callbackContext.sendPluginResult(result);
        }
    }

Hmm... Ich habe festgestellt, dass Benachrichtigungen nicht (an das Gerät) gesendet werden, wenn der Client nicht ausgeführt wird (gekillt wurde).

Versuchen Sie, eine von Firebase angezeigte Benachrichtigung direkt zu öffnen und das Verhalten zu sehen. Ich denke, sie starten die Hauptaktivität neu, was meiner Meinung nach das richtige Verhalten ist.

Entschuldigung für die Verspätung. Ich habe es mit 0.1.13 versucht, aber meine App wird neu gestartet, nachdem die Benachrichtigung geöffnet wurde.

irgendwelche Neuigkeiten ?

Ich kann keinen onNotificationOpen-Rückruf erfolgreich oder fehlschlagen auf Android mit 0.1.17 erhalten. Weder das Senden über die API noch die GUI mit einer Nutzlast funktioniert. Irgendwelche Vorschläge?

Warum erstellen wir keine Pull-Anfrage mit diesem Code, den @Mehuge gepostet hat? Es funktioniert für mich wie ein Zauber auf Android.

Ich musste onNewIntent in FirebasePlugin aktualisieren, um normale Startabsichten herauszufiltern, daher sieht mein onNewIntent-Code jetzt so aus

<strong i="6">@Override</strong>
public void onNewIntent(Intent intent) {
  Log.d(TAG, "new intent " + intent);
  super.onNewIntent(intent);
  Bundle data = intent.getExtras();
  if (data != null) {
    String id = data.getString("id");
    if (null != id) {
      FirebasePlugin.handleNotificationBundle(data);
    } else {
      Log.d(TAG, "Not a notification intent, ignored");
    }
  }
}

Ich bin damit nicht ganz zufrieden. Es funktioniert, indem nach einer ID-Eigenschaft im Intent-Bundle gesucht wird, die mein Servercode immer sendet. Es scheint nichts zu geben, was GCM oder FBM zuverlässig zum Bundle hinzufügen, um die Absicht als Benachrichtigung/Nachricht zu identifizieren. Manchmal werden einige Google-Eigenschaften hinzugefügt (wenn wir eine Benachrichtigung über die Taskleiste öffnen), aber für Nachrichten und Benachrichtigungen, die direkt an den Client gesendet werden, wenn er im Vordergrund ist, gibt es nichts anderes als die Daten in der Nachricht, die Ihnen sagen, dass es sich um eine Startabsicht handelt wegen einer Benachrichtigung, die ich zumindest sehen konnte.

Es gibt wahrscheinlich einen besseren Weg, damit umzugehen.

@Mehuge würde es Ihnen etwas ausmachen, mit allen Dateien, die Sie haben, Gists zu erstellen?

Ok, hier ist es https://gist.github.com/Mehuge/374ee24d9e18a6c7ccc171d3e521b7ad

Beachten Sie jedoch, dass es einige Besonderheiten unserer App gibt. Am Ende habe ich den Code in unser Projekt verschoben, weil ich ihn so stark verändert habe. Im Nachhinein hätte ich das Plugin wahrscheinlich forken und so modifizieren sollen, aber zu diesem Zeitpunkt war ich weit hinter dem Zeitplan zurück und hatte das Ganze ziemlich satt, also ging ich den schnellsten Weg, um etwas zum Laufen zu bringen. Die benutzerdefinierten Bits sind ziemlich offensichtlich und sollten daher leicht auszuschließen sein.

Beachten Sie auch, dass ich das Plugin so implementiert habe, dass es wissen muss, wann der Client pausiert (oder genauer gesagt nicht pausiert) ist, damit er entscheiden kann, ob eine Benachrichtigung erstellt oder die Nachricht direkt übermittelt werden soll. Sie können diese Funktionalität benötigen oder auch nicht, aber in unserem Fall wollten wir nicht, dass Benachrichtigungen, die gesendet wurden, wenn der Client im Vordergrund war, Android-Benachrichtigungen erstellen, sondern direkt an den Client zur Bearbeitung gesendet werden. Um das Plugin über den Pausenzustand des Clients zu informieren, fügen Sie den folgenden Code zu Ihrer Hauptaktivität hinzu.

<strong i="9">@Override</strong>
protected void onResume() {
    FirebasePlugin.setPaused(false);
    super.onResume();
}

<strong i="10">@Override</strong>
protected void onPause() {
    FirebasePlugin.setPaused(true);
    super.onPause();
}

Es gibt ein weiteres Problem, mit dem Sie möglicherweise fertig werden müssen. Wenn im Hintergrund eine Benachrichtigung eingeht, der Benutzer die App jedoch direkt startet, anstatt die Android-Benachrichtigung zu öffnen, müssen Sie möglicherweise auf irgendeine Weise damit umgehen. In unserem App-Fall könnte ich einfach alle ungeöffneten Benachrichtigungen löschen. Ihre Situation kann anders sein.

Ich bin mit dem Endergebnis nicht ganz zufrieden, einige der zusätzlichen Tasten zum Beispiel waren experimentell und werden nicht wirklich verwendet, ich bin einfach nicht dazu gekommen, sie zu entfernen.

Wäre an Feedback, Verbesserungsvorschlägen oder Hinweisen auf Mängel interessiert. Ich wäre besonders daran interessiert, einen Weg zu finden, eine Startabsicht mit einer GCM-Nutzlast von einem normalen Start besser zu erkennen. Ich habe festgestellt, dass die Google-Eigenschaften nur unter bestimmten Umständen hinzugefügt werden. Auch meine Versuche, die verschiedenen Arten von Benachrichtigungen (is_push, is_notify, Broadcast) zu erkennen, funktionieren nicht wirklich.

siehe #108

Für mich könnte ich lösen, die Anfrage wie folgt zu stellen:

{
  "registration_ids": [...tokens],
  "notification" : {
        "title": "Notf title",
        "body": "Notification body"
     },
     "data": {
        "click_action": "/call/dwEugLJ9PTVdcFb064CX"
     }
}

Aber ich musste die click_action als Parameter nehmen und die Umleitung manuell durchführen (ich habe Cordova mit der React-App verwendet).

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen