Frage zu Firebase Cloud Messaging

  • Antworten:4
mc4735
  • Forum-Beiträge: 3

05.08.2018, 18:54:48 via Website

Hallo,

ich versuche gerade ein kleines Projekt zu verwirklichen und bin bei einem der letzten Punkte angekommen, die ich nicht hinbekomme. Bei der Suche danach bin ich auf dieses Forum gestoßen.

Ich habe eine Admin-App, in der ich Daten verwalte und auf einen Server lade, und eine Client-App in der ich die Daten vom Server runterlade und betrachte.

Die Client-App habe ich so eingerichtet, dass sie per Firebase versendete Nachrichten empfängt. Ich würde es jetzt gerne hinbekommen, dass ich mit der Admin-App Nachrichten per FCM verschicken kann, die dann in der Admin-App angezeigt werden.

Hier (h***s://firebase.google.com/docs/admin/setup) steht erklärt, wie man das einrichten kann. Leider scheint es so zu sein, dass man einer Android-App keine Adminrechte geben kann. Verschiedene Schritte dieser Anleitung funktioniere leider nicht und das habe ich als Erklärung gefunden.

Hat jemand eine Idee, wie ich es hinbekommen kann, dass ich FCM-Nachrichten über eine Android-App verschicke?

Viele Grüße und vielen Dank im Voraus
MC

— geändert am 05.08.2018, 18:55:24

Kommentieren
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

05.08.2018, 20:38:54 via Website

Hallo mc,

Herzlich wilkommen hier im Forum :)

Es gibt meherere Möglichkeiten FCMs aus einer App zu senden.
Die einfachste wird wohl die FCM Admin API sein: https://firebase.google.com/docs/cloud-messaging/admin/send-messages

Wie speicherst du deine RegistrationIDs der Client Apps? In einer eigenen DB oder in einer Firebase DB?
Du kannst nämlich per Firebase Database die IDs auslesen und dann per Firebase Admin die message senden.

Wenn du das senden lieber manuell vornehmen möchtest, bietet sich auch die HTTP Variante an:
https://firebase.google.com/docs/cloud-messaging/send-message

LG Pascal //It's not a bug, it's a feature. :) ;)

Hilfreich?
Ludy
Kommentieren
Ludy
  • Admin
  • Forum-Beiträge: 7.957

05.08.2018, 20:42:31 via Website

Hallo mc4735 und herzlich Willkommen hier im Forum (*)

Das ist ganz einfach, erst die Klasse für SSL:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;


public class NoSSLv3SocketFactory extends SSLSocketFactory {
    private final SSLSocketFactory delegate;

    public NoSSLv3SocketFactory() {
        this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
    }

    public NoSSLv3SocketFactory(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    private Socket makeSocketSafe(Socket socket) {
        if (socket instanceof SSLSocket) {
            socket = new NoSSLv3SSLSocket((SSLSocket) socket);
        }
        return socket;
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return makeSocketSafe(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return makeSocketSafe(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort));
    }

    private class NoSSLv3SSLSocket extends DelegateSSLSocket {

        private NoSSLv3SSLSocket(SSLSocket delegate) {
            super(delegate);

        }

        @Override
        public void setEnabledProtocols(String[] protocols) {
            if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {

                List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
                if (enabledProtocols.size() > 1) {
                    enabledProtocols.remove("SSLv3");
                    System.out.println("Removed SSLv3 from enabled protocols");
                } else {
                    System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
                }
                protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
            }

            super.setEnabledProtocols(protocols);
        }
    }

    public class DelegateSSLSocket extends SSLSocket {

        protected final SSLSocket delegate;

        DelegateSSLSocket(SSLSocket delegate) {
            this.delegate = delegate;
        }

        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }

        @Override
        public String[] getEnabledCipherSuites() {
            return delegate.getEnabledCipherSuites();
        }

        @Override
        public void setEnabledCipherSuites(String[] suites) {
            delegate.setEnabledCipherSuites(suites);
        }

        @Override
        public String[] getSupportedProtocols() {
            return delegate.getSupportedProtocols();
        }

        @Override
        public String[] getEnabledProtocols() {
            return delegate.getEnabledProtocols();
        }

        @Override
        public void setEnabledProtocols(String[] protocols) {
            delegate.setEnabledProtocols(protocols);
        }

        @Override
        public SSLSession getSession() {
            return delegate.getSession();
        }

        @Override
        public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
            delegate.addHandshakeCompletedListener(listener);
        }

        @Override
        public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
            delegate.removeHandshakeCompletedListener(listener);
        }

        @Override
        public void startHandshake() throws IOException {
            delegate.startHandshake();
        }

        @Override
        public void setUseClientMode(boolean mode) {
            delegate.setUseClientMode(mode);
        }

        @Override
        public boolean getUseClientMode() {
            return delegate.getUseClientMode();
        }

        @Override
        public void setNeedClientAuth(boolean need) {
            delegate.setNeedClientAuth(need);
        }

        @Override
        public void setWantClientAuth(boolean want) {
            delegate.setWantClientAuth(want);
        }

        @Override
        public boolean getNeedClientAuth() {
            return delegate.getNeedClientAuth();
        }

        @Override
        public boolean getWantClientAuth() {
            return delegate.getWantClientAuth();
        }

        @Override
        public void setEnableSessionCreation(boolean flag) {
            delegate.setEnableSessionCreation(flag);
        }

        @Override
        public boolean getEnableSessionCreation() {
            return delegate.getEnableSessionCreation();
        }

        @Override
        public void bind(SocketAddress localAddr) throws IOException {
            delegate.bind(localAddr);
        }

        @Override
        public synchronized void close() throws IOException {
            delegate.close();
        }

        @Override
        public void connect(SocketAddress remoteAddr) throws IOException {
            delegate.connect(remoteAddr);
        }

        @Override
        public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
            delegate.connect(remoteAddr, timeout);
        }

        @Override
        public SocketChannel getChannel() {
            return delegate.getChannel();
        }

        @Override
        public InetAddress getInetAddress() {
            return delegate.getInetAddress();
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return delegate.getInputStream();
        }

        @Override
        public boolean getKeepAlive() throws SocketException {
            return delegate.getKeepAlive();
        }

        @Override
        public InetAddress getLocalAddress() {
            return delegate.getLocalAddress();
        }

        @Override
        public int getLocalPort() {
            return delegate.getLocalPort();
        }

        @Override
        public SocketAddress getLocalSocketAddress() {
            return delegate.getLocalSocketAddress();
        }

        @Override
        public boolean getOOBInline() throws SocketException {
            return delegate.getOOBInline();
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return delegate.getOutputStream();
        }

        @Override
        public int getPort() {
            return delegate.getPort();
        }

        @Override
        public synchronized int getReceiveBufferSize() throws SocketException {
            return delegate.getReceiveBufferSize();
        }

        @Override
        public SocketAddress getRemoteSocketAddress() {
            return delegate.getRemoteSocketAddress();
        }

        @Override
        public boolean getReuseAddress() throws SocketException {
            return delegate.getReuseAddress();
        }

        @Override
        public synchronized int getSendBufferSize() throws SocketException {
            return delegate.getSendBufferSize();
        }

        @Override
        public int getSoLinger() throws SocketException {
            return delegate.getSoLinger();
        }

        @Override
        public synchronized int getSoTimeout() throws SocketException {
            return delegate.getSoTimeout();
        }

        @Override
        public boolean getTcpNoDelay() throws SocketException {
            return delegate.getTcpNoDelay();
        }

        @Override
        public int getTrafficClass() throws SocketException {
            return delegate.getTrafficClass();
        }

        @Override
        public boolean isBound() {
            return delegate.isBound();
        }

        @Override
        public boolean isClosed() {
            return delegate.isClosed();
        }

        @Override
        public boolean isConnected() {
            return delegate.isConnected();
        }

        @Override
        public boolean isInputShutdown() {
            return delegate.isInputShutdown();
        }

        @Override
        public boolean isOutputShutdown() {
            return delegate.isOutputShutdown();
        }

        @Override
        public void sendUrgentData(int value) throws IOException {
            delegate.sendUrgentData(value);
        }

        @Override
        public void setKeepAlive(boolean keepAlive) throws SocketException {
            delegate.setKeepAlive(keepAlive);
        }

        @Override
        public void setOOBInline(boolean oobinline) throws SocketException {
            delegate.setOOBInline(oobinline);
        }

        @Override
        public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
            delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
        }

        @Override
        public synchronized void setReceiveBufferSize(int size) throws SocketException {
            delegate.setReceiveBufferSize(size);
        }

        @Override
        public void setReuseAddress(boolean reuse) throws SocketException {
            delegate.setReuseAddress(reuse);
        }

        @Override
        public synchronized void setSendBufferSize(int size) throws SocketException {
            delegate.setSendBufferSize(size);
        }

        @Override
        public void setSoLinger(boolean on, int timeout) throws SocketException {
            delegate.setSoLinger(on, timeout);
        }

        @Override
        public synchronized void setSoTimeout(int timeout) throws SocketException {
            delegate.setSoTimeout(timeout);
        }

        @Override
        public void setTcpNoDelay(boolean on) throws SocketException {
            delegate.setTcpNoDelay(on);
        }

        @Override
        public void setTrafficClass(int value) throws SocketException {
            delegate.setTrafficClass(value);
        }

        @Override
        public void shutdownInput() throws IOException {
            delegate.shutdownInput();
        }

        @Override
        public void shutdownOutput() throws IOException {
            delegate.shutdownOutput();
        }

        @Override
        public String toString() {
            return delegate.toString();
        }

        @Override
        public boolean equals(Object o) {
            return delegate.equals(o);
        }
    }
}

und dann die Klasse:

import android.os.AsyncTask;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

public class FCMSSL extends AsyncTask<String, String, String> {

    private String _postParam = "{\"to\":\"FCM_ID_VOM_EMPFAENGER\",\"data\":{\"title\":\"Nachrichtensystem\"}}";
    private String _url = "https://fcm.googleapis.com/fcm/send";
    private boolean _debug = false;
    private String _contentType = "application/json";
    private int _timeout = 7000;
    private String TAG = FCMSSL.class.getSimpleName();


    @Override
    protected String doInBackground(String... params) {
        URL url;
        try {
            Log.e(TAG, _postParam);
            SSLContext sslcontext = SSLContext.getInstance("TLSv1");
            sslcontext.init(null, null, null);
            SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());
            HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory);
            url = new URL(_url);
            HttpsURLConnection con = (HttpsURLConnection) url.openConnection();

            con.setReadTimeout(_timeout);
            con.setConnectTimeout(_timeout);
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setInstanceFollowRedirects(false);
            con.setRequestMethod("POST");
            if (_postParam != null)
                con.setFixedLengthStreamingMode(_postParam.getBytes().length);
            else
                Log.d(TAG + " - postParam", "Empty");
            con.setRequestProperty("Content-Type", _contentType);
            con.setRequestProperty("Authorization", "key=DEIN_SERVER_KEY");
            // Send
            PrintWriter out = new PrintWriter(con.getOutputStream());
            if (_postParam != null)
                out.print(_postParam);
            else
                Log.d(TAG + " - postParam", "Empty");
            out.close();

            con.connect();
            BufferedReader in = null;
            if (con.getResponseCode() != 200) {
                in = new BufferedReader(new InputStreamReader(con.getErrorStream()));
                Log.d(TAG, "!=200: " + in.readLine());
                return in.readLine();
            } else {
                in = new BufferedReader(new InputStreamReader(con.getInputStream()));
                Log.d(TAG, "POST request send successful: " + in.readLine());
            }
        } catch (IOException e) {
            Log.e(TAG + " - IOException", e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG + " - NoSuchAlgorithm", e.getMessage());
        } catch (KeyManagementException e) {
            Log.e(TAG + " - KeyManagement", e.getMessage());
        }
        return null;
    }
}

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

Hilfreich?
Kommentieren
mc4735
  • Forum-Beiträge: 3

05.08.2018, 21:44:51 via Website

Pascal P.

Hallo mc,

Herzlich wilkommen hier im Forum :)

Es gibt meherere Möglichkeiten FCMs aus einer App zu senden.
Die einfachste wird wohl die FCM Admin API sein: h**ps://firebase.google.com/docs/cloud-messaging/admin/send-messages

Wie speicherst du deine RegistrationIDs der Client Apps? In einer eigenen DB oder in einer Firebase DB?
Du kannst nämlich per Firebase Database die IDs auslesen und dann per Firebase Admin die message senden.

Wenn du das senden lieber manuell vornehmen möchtest, bietet sich auch die HTTP Variante an:
h**ps://firebase.google.com/docs/cloud-messaging/send-message

Danke für die schnellen Antworten. Die Lösung die du verlinkt hast, hatte ich auch versucht. Bisher scheitere ich da aber an der technischen Umsetzung. Da sind bei zwei größere Probleme aufgetreten.

1) Man muss nach dieser Anleitung ja zunächst die Firebase AdminSDK zur seinem Server hinzufügen. DAs habe ich versucht, hatte aber ein paar Probleme.

Wenn ich versuche den Eintrag

dependencies { implementation
'com.google.firebase:firebase-admin:6.3.0' }

in mein Build.Gradle-File einzufügen, bekomme ich die Meldung:

Annotation processors must be explicitly declared now. The following
dependencies on the compile classpath are found to contain annotation
processor. Please add them to the annotationProcessor configuration.
- auto-value-1.4.jar (com.google.auto.value:auto-value:1.4) Alternatively, set
android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath
= true to continue with previous behavior. Note that this option is deprecated and will be removed in the future. See
h**ps://developer.android.com/r/tools/annotation-processor-error-message.html
for more details.

Als ich im Netz nach einer Lösung gesucht habe, habe Ich einen Foreneintrag( h**ps://stackoverflow.com/questions/47581505/how-to-add-firebase-admin-to-my-android-project) gefunden, wo steht, dass es nicht möglich wäre, dass in einer Android-App zu verwenden, weil es irgendwelche Konflikte mit Paketen mit gleichen Namen gibt. Außerdem soll es wohl aus Sicherheitsgründen unterbunden werden.

2) Wenn ich den Quellcode zum versenden der Nachricht aus deinem Link in mein Projekt einfüge, dann kriege ich die Fehlermeldung "Can't resolve builder()". Ich habe bisher aber leider auch nicht rausgefunden, woran das liegt.

Die RegestrationIDs speichere ich bisher gar nicht. Zumindest nicht bewusst. Ich habe bei der Client-App einfach reingeschrieben, dass ein Topic abonniert wird, an das ich die Nachrichten sende. Bisher habe ich die Nachrichten mit dem Programm Postman per Post versendet wie es in deinem zweiten Link beschrieben ist.

Ich habe auch noch keine großen Ansprüchen. Ich will es bisher nur schaffen, Nachrichten an all Clients gleichzeitig zu verschicken.

@Ludy, dir auch Danke, deinen Beitrag schau ich mir morgen mal in Ruhe an. Dafür bin ich heute zu müde, da muss ich mich vermutlich erstmal reindenken ;).

— geändert am 05.08.2018, 21:47:14

Hilfreich?
Kommentieren
mc4735
  • Forum-Beiträge: 3

06.08.2018, 18:38:51 via Website

Pascal P.

Wenn du das senden lieber manuell vornehmen möchtest, bietet sich auch die HTTP Variante an:
h**ps://firebase.google.com/docs/cloud-messaging/send-message

Darüber habe ich es jetzt hinbekommen. Danke nochmal.

Hilfreich?
Kommentieren