Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Show Push Notifications, while my app is in the background



  • Hi, at the beginning I work with QT Firebase
    I have following problem:
    If my application is closed, the messages are only displayed in the message bar. And when I press the message, my application starts, but it does not receive the message itself. What can I do to see the message in my application?

    If I receive a message while my app is in the background and I click on it, then "void MessageListener :: OnMessage (const messaging :: Message & message)" will be started, but "message.notification" will be "0x0". Only "message.notification_opened" is true, whereupon the string "launchnotification" is passed, but that is useless.

    I already have learned that this problem is in other Qt Firebase projects did not occur. I do not know where should I search.

    I think, that in qtfirebasemessaging.cpp or in Main.java is a bug.

    This is the file: "qtfirebasemessaging.cpp"

    //#include "qtfirebasemessaging.h"
    
    #include <QGuiApplication>
    #include <QQmlParserStatus>
    
    #include <stdint.h>
    #include "firebase/app.h"
    #include "firebase/internal/common.h"
    #include "firebase/messaging.h"
    #include "firebase/util.h"
    
    namespace messaging = ::firebase::messaging;
    
    QtFirebaseMessaging *QtFirebaseMessaging::self = nullptr;
    
    QtFirebaseMessaging::QtFirebaseMessaging(QObject* parent)
        : QObject(parent)
        , g_listener(new MessageListener())
    {
        __QTFIREBASE_ID = QString().sprintf("%8p", this);
    
        if(!self) {
            self = this;
            qDebug() << self << "::QtFirebaseMessaging" << "singleton";
        }
    
        _ready = false;
        _initializing = false;
    
        if(qFirebase->ready()) {
            //Call init outside of constructor, otherwise signal readyChanged not emited
            QTimer::singleShot(100, this, &QtFirebaseMessaging::init);
        } else {
            connect(qFirebase,&QtFirebase::readyChanged, this, &QtFirebaseMessaging::init);
            qFirebase->requestInit();
        }
    
        connect(qFirebase,&QtFirebase::futureEvent, this, &QtFirebaseMessaging::onFutureEvent);
    }
    
    QtFirebaseMessaging::~QtFirebaseMessaging()
    {
        if(_ready) {
            messaging::Terminate();
        }
    }
    
    void QtFirebaseMessaging::classBegin()
    {
    }
    
    void QtFirebaseMessaging::componentComplete()
    {
        // Connect on componentComplete so the signals are emited in the correct order
        connect(g_listener, &MessageListener::onMessageReceived, this, &QtFirebaseMessaging::getMessage);
        connect(g_listener, &MessageListener::onTokenReceived, this, &QtFirebaseMessaging::getToken);
    }
    
    bool QtFirebaseMessaging::checkInstance(const char *function)
    {
        const bool b = (QtFirebaseMessaging::self != nullptr);
        if (!b)
            qWarning("QtFirebaseMessaging::%s: Please instantiate the QtFirebaseMessaging object first", function);
        return b;
    }
    
    void QtFirebaseMessaging::init()
    {
        if(!qFirebase->ready()) {
            qDebug() << self << "::init" << "base not ready";
            return;
        }
    
        if(!_ready && !_initializing) {
            _initializing = true;
            messaging::Initialize(*qFirebase->firebaseApp(), g_listener);
            _initializing = false;
            setReady(true);
        }
    }
    
    void QtFirebaseMessaging::onFutureEvent(const QString &eventId, const firebase::FutureBase &future)
    {
        if(!eventId.startsWith(__QTFIREBASE_ID))
            return;
    
        qDebug() << self << "::onFutureEvent" << eventId;;
    
        if(future.status() != firebase::kFutureStatusComplete)
        {
            qDebug() << this << "::onFutureEvent initializing failed." << "ERROR: Action failed with error code and message: " << future.error() << future.error_message();
            _initializing = false;
            return;
        }
        qDebug() << this << "::onFutureEvent initialized ok";
        _initializing = false;
    }
    
    void QtFirebaseMessaging::getMessage()
    {
        setData(g_listener->data());
    }
    
    void QtFirebaseMessaging::getToken()
    {
        setToken(g_listener->token());
    }
    
    bool QtFirebaseMessaging::ready()
    {
        return _ready;
    }
    
    void QtFirebaseMessaging::setReady(bool ready)
    {
        if (_ready != ready) {
            _ready = ready;
            emit readyChanged();
        }
    }
    
    QVariantMap QtFirebaseMessaging::data()
    {
        return _data;
    }
    
    void QtFirebaseMessaging::setData(const QVariantMap &data)
    {
        if (_data != data) {
            _data = data;
            emit dataChanged();
            emit messageReceived();
        }
    }
    
    QString QtFirebaseMessaging::token()
    {
        return _token;
    }
    
    void QtFirebaseMessaging::setToken(const QString &token)
    {
        if (_token != token) {
            _token = token;
            emit tokenChanged();
        }
    }
    
    MessageListener::MessageListener(QObject* parent)
        : QObject(parent)
    {
    }
    
    void MessageListener::OnMessage(const messaging::Message &message)
    {
        // When messages are received by the server, they are placed into an
        // internal queue, waiting to be consumed. When ProcessMessages is called,
        // this OnMessage function is called once for each queued message.
    
        QVariantMap data;
    
        if (message.notification) {
            if (!message.notification->title.empty()) {
                const QString key = QStringLiteral("nTitle");
                const QString value = QString::fromStdString(message.notification->title.c_str());
                data.insert(key, value);
            }
            if (!message.notification->body.empty()) {
                const QString key = QStringLiteral("nBody");
                const QString value = QString::fromStdString(message.notification->body.c_str());
                data.insert(key, value);
            }
            if (!message.notification->icon.empty()) {
                const QString key = QStringLiteral("nIcon");
                const QString value = QString::fromStdString(message.notification->icon.c_str());
                data.insert(key, value);
            }
            if (!message.notification->tag.empty()) {
                const QString key = QStringLiteral("nTag");
                const QString value = QString::fromStdString(message.notification->tag.c_str());
                data.insert(key, value);
            }
            if (!message.notification->color.empty()) {
                const QString key = QStringLiteral("nColor");
                const QString value = QString::fromStdString(message.notification->color.c_str());
                data.insert(key, value);
            }
            if (!message.notification->sound.empty()) {
                const QString key = QStringLiteral("nSound");
                const QString value = QString::fromStdString(message.notification->sound.c_str());
                data.insert(key, value);
            }
            if (!message.notification->click_action.empty()) {
                const QString key = QStringLiteral("nClickAction");
                const QString value = QString::fromStdString(message.notification->click_action.c_str());
                data.insert(key, value);
            }
        }
    
        if (message.notification_opened) {
            const QString key = QStringLiteral("launchnotification");
            data.insert(key, true);
        }
    
        for (const auto& field : message.data)
        {
            const QString key = QString::fromStdString(field.first);
            const QString value = QString::fromStdString(field.second);
    
            data.insert(key, value);
        }
    
        setData(data);
    }
    
    void MessageListener::OnTokenReceived(const char *token)
    {
        setToken(QString::fromUtf8(token));
    }
    
    void MessageListener::connectNotify(const QMetaMethod &signal)
    {
        if (signal == QMetaMethod::fromSignal(&MessageListener::onMessageReceived)) {
            _messageReceivedConnected = true;
    
            if(_notifyMessageReceived) {
                emit onMessageReceived();
                _notifyMessageReceived = false;
            }
        }
    
        if (signal == QMetaMethod::fromSignal(&MessageListener::onTokenReceived)) {
            _tokenReceivedConnected = true;
    
            if(_notifyTokenReceived) {
                emit onTokenReceived();
                _notifyTokenReceived = false;
            }
        }
    }
    
    QVariantMap MessageListener::data()
    {
        return _data;
    }
    
    void MessageListener::setData(const QVariantMap &data)
    {
        if (_data != data) {
            _notifyMessageReceived = true;
            _data = data;
    
            if(_messageReceivedConnected) {
                emit onMessageReceived();
                _notifyMessageReceived = false;
            }
        }
    }
    
    QString MessageListener::token()
    {
        return _token;
    }
    
    void MessageListener::setToken(const QString &token)
    {
        if (_token != token) {
            _notifyTokenReceived = true;
            _token = token;
    
            if(_tokenReceivedConnected) {
                emit onTokenReceived();
                _notifyTokenReceived = false;
            }
        }
    }
    
    

    This is the file: "Main.java"

    //package com.blackgrain.android.firebasetest;
    
    import org.qtproject.qt5.android.bindings.QtApplication;
    import org.qtproject.qt5.android.bindings.QtActivity;
    
    import android.util.Log;
    import android.support.v7.app.AppCompatActivity;
    
    import android.view.WindowManager;
    
    // Messaging support
    import android.os.Bundle;
    import android.content.Intent;
    import com.google.firebase.messaging.MessageForwardingService;
    
    public class Main extends QtActivity {
    
        /** Called when the activity is first created. */
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    
        }
    
    
        /**
           * Messaging example
           */
        // The key in the intent's extras that maps to the incoming message's message ID. Only sent by
        // the server, GmsCore sends EXTRA_MESSAGE_ID_KEY below. Server can't send that as it would get
        // stripped by the client.
        private static final String EXTRA_MESSAGE_ID_KEY_SERVER = "message_id";
    
        // An alternate key value in the intent's extras that also maps to the incoming message's message
        // ID. Used by upstream, and set by GmsCore.
        private static final String EXTRA_MESSAGE_ID_KEY = "google.message_id";
    
        // The key in the intent's extras that maps to the incoming message's sender value.
        private static final String EXTRA_FROM = "google.message_id";
    
        /**
           * Workaround for when a message is sent containing both a Data and Notification payload.
           *
           * When the app is in the foreground all data payloads are sent to the method
           * `::firebase::messaging::Listener::OnMessage`. However, when the app is in the background, if a
           * message with both a data and notification payload is receieved the data payload is stored on
           * the notification Intent. NativeActivity does not provide native callbacks for onNewIntent, so
           * it cannot route the data payload that is stored in the Intent to the C++ function OnMessage. As
           * a workaround, we override onNewIntent so that it forwards the intent to the C++ library's
           * service which in turn forwards the data to the native C++ messaging library.
           */
        @Override
        protected void onNewIntent(Intent intent) {
            // If we do not have a 'from' field this intent was not a message and should not be handled. It
            // probably means this intent was fired by tapping on the app icon.
    
            // TODO
            Bundle extras = intent.getExtras();
            String from = extras.getString(EXTRA_FROM);
            String messageId = extras.getString(EXTRA_MESSAGE_ID_KEY);
    
            if (messageId == null) {
                messageId = extras.getString(EXTRA_MESSAGE_ID_KEY_SERVER);
            }
    
            if (from != null && messageId != null) {
                Intent message = new Intent(this, MessageForwardingService.class);
                message.setAction(MessageForwardingService.ACTION_REMOTE_INTENT);
                message.putExtras(intent);
                startService(message);
            }
            setIntent(intent);
    
        }
    
    }
    
    

    In additional here it calls that they have a solution for that. " ... As a workaround, we override onNewIntent so that it forwards the intent to the C++ library's service which in turn forwards the data to the native C++ messaging library."
    It may be that the function is simply not called?

    Please urgently for an answer. Thank you



  • @Robin-Hood

    You might want to follow this thread


Log in to reply