0

I'm trying to integrate Firebase Cloud Messaging (I use this code, which is mirrored here) with my existing app.

Relevant codes:

service.php

$msg_id = $_POST['id'];
$title = $_POST['title'];
$content = $_POST['content'];
$msg_date = $_POST['date'];
$author = $_POST['author'];

// insert the message into DB               
$sql = "INSERT INTO tbl_message(msg_id, title, content, msg_date, author) VALUES ('$msg_id','$title','$content','$msg_date','$author')";

if ($result = mysqli_query($db, $sql)){

    $firebase = new Firebase();
    $push = new Push();

    $payload = array();
    $payload['foo'] = '123';
    $payload['bar'] = 'xyz';

    $push->setTitle($title);
    $push->setMessage($content);
    $push->setAuthor($author);
    $push->setDate($msg_date);
    $push->setImage('');
    $push->setPayload($payload);
    $push->setIsBackground(FALSE);
    $resp = '';
    $response = '';
    $resp = $push->getPush();
    $response = $firebase->sendToTopic('global', $resp);

    echo $response;
}

Firebase.php

<?php


class Firebase {

    // sending push message to single user by firebase reg id
    public function send($to, $message) {
        $fields = array(
            'to' => $to,
            //'data' => $message,
            'data' => array("message" => $message));

        return $this->sendPushNotification($fields);
    }

    // Sending message to a topic by topic name
    public function sendToTopic($to, $message) {
        $fields = array(
            'to' => '/topics/' . $to,
            //'data' => $message,
            'data' => array("message" => $message)
        );
        return $this->sendPushNotification($fields);
    }

    // sending push message to multiple users by firebase registration ids
    public function sendMultiple($registration_ids, $message) {
        $fields = array(
            'to' => $registration_ids,
            //'data' => $message,
            'data' => array("message" => $message)
        );

        return $this->sendPushNotification($fields);
    }

    // function makes curl request to firebase servers
    private function sendPushNotification($fields) {

        require_once 'config.php';

        // Set POST variables
        $url = 'https://fcm.googleapis.com/fcm/send';

        $headers = array(
            'Authorization: key=' . FIREBASE_API_KEY,
            'Content-Type: application/json'
        );
        // Open connection
        $ch = curl_init();

        // Set the url, number of POST vars, POST data
        curl_setopt($ch, CURLOPT_URL, $url);

        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // Disabling SSL Certificate support temporarly
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));

        // Execute post
        $result = curl_exec($ch);
        if ($result === FALSE) {
            die('Curl failed: ' . curl_error($ch));
        }

        // Close connection
        curl_close($ch);

        return $result;
    }
}

?>

MainActivity.java

package studio.emcorp.monitoringsiswa;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.google.firebase.messaging.FirebaseMessaging;


public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    private static final String TAG = MainActivity.class.getSimpleName();
    private BroadcastReceiver mRegistrationBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
;

        mRegistrationBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {

                // checking for type intent filter
                if (intent.getAction().equals(NotificationConfig.REGISTRATION_COMPLETE)) {
                    // gcm successfully registered
                    // now subscribe to `global` topic to receive app wide notifications
                    FirebaseMessaging.getInstance().subscribeToTopic(NotificationConfig.TOPIC_GLOBAL);

                    displayFirebaseRegId();

                } else if (intent.getAction().equals(NotificationConfig.PUSH_NOTIFICATION)) {
                    // new push notification is received

                    String message = intent.getStringExtra("message");

                    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();

                    //txtMessage.setText(message);
                }
            }
        };



    @Override
    protected void onResume() {
        super.onResume();

        // register GCM registration complete receiver
        LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
                new IntentFilter(NotificationConfig.REGISTRATION_COMPLETE));

        // register new push message receiver
        // by doing this, the activity will be notified each time a new message arrives
        LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
                new IntentFilter(NotificationConfig.PUSH_NOTIFICATION));

        // clear the notification area when the app is opened
        NotificationUtil.clearNotifications(getApplicationContext());
    }

    @Override
    protected void onPause() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
        super.onPause();
    }
}

Sending messages directly from Firebase Console works fine. Now the problem is sending messages via PHP script. Somewhow the server manages to send the message successfuly, e.g:

{"message_id":4732936739964848111}

, and the device receive it:

06-19 09:26:21.590 18604-19560/net.anta40.app.firebasetest E/MyFirebaseMessagingService: From: /topics/global 06-19 09:26:21.590 18604-19560/net.anta40.app.firebasetest E/MyFirebaseMessagingService: Data Payload: {message={"data":{"image":"","is_background":false,"payload":{"bar":"xyz","foo":"123"},"title":"test","message":"mehehehe","timestamp":"2017-06-19 2:26:21"}}} 06-19 09:26:21.600 18604-19560/net.anta40.app.firebasetest E/MyFirebaseMessagingService: push json: {"message":{"data":{"timestamp":"2017-06-19 2:26:21","message":"mehehehe","payload":{"bar":"xyz","foo":"123"},"image":"","title":"test","is_background":false}}} 06-19 09:26:21.600 18604-19560/net.anta40.app.firebasetest E/MyFirebaseMessagingService: Json Exception: No value for data 06-19 09:26:21.720 1098-1098/? D/wpa_supplicant: RX ctrl_iface - hexdump(len=11): 53 49 47 4e 41 4c 5f 50 4f 4c 4c 06-19 09:26:21.720 1098-1098/? D/wpa_supplicant: wlan0: Control interface command 'SIGNAL_POLL'

but not displayed via notifications. What goes wrong here?

AL.
  • 36,815
  • 10
  • 142
  • 281
anta40
  • 6,511
  • 7
  • 46
  • 73

1 Answers1

1

You are sending a data-only payload in your PHP:

public function send($to, $message) {
    $fields = array(
        'to' => $to,
        //'data' => $message,
        'data' => array("message" => $message));

    return $this->sendPushNotification($fields);
}

Your other methods are also sending the same.

If you're going to use a notification-only payload, you could simply structure it like so:

public function send($to, $message) {
    $fields = array(
        'to' => $to,
        'notification' => array("title" => $title,
            "body" => $body));

    return $this->sendPushNotification($fields);
}

The difference from sending a message from the Firebase Console is that messages from the console are considered as notification messages.

In Android, each message type is handled differently (see Handling Messages).

Some useful posts:

AL.
  • 36,815
  • 10
  • 142
  • 281
  • Hmm I see. Just did some Google search and found this: https://firebase.google.com/docs/cloud-messaging/android/receive#handling_messages. So, it seems that I have to use "Notification message". Correct? – anta40 Jun 19 '17 at 09:10
  • Same link for Handling Messages I linked. If you want the same behavior when sending a message from the console, then yes. :) – AL. Jun 19 '17 at 09:13
  • Hi AL, pardon me. I'm still confused. It seems the problem is I'm sending a data-only payload (which will be handled by my app). What I actually want is sending notification messages, which will be displayed in Android system tray. How should I code the message? Then how to send it? Previously I've followed the steps in Handling Messages, including registering MyFirebaseMessagingService in Android manifest. – anta40 Jun 20 '17 at 08:37
  • Hi anta40. Sure. Unlike the `data` message where you could specify custom key-value pairs, the `notification` message only has [specific parameters that you could use](https://firebase.google.com/docs/cloud-messaging/http-server-ref#notification-payload-support). I'll edit my answer to show a sample. – AL. Jun 20 '17 at 09:11
  • Hi AL, Tried you suggestion. I got this: {"multicast_id":7175672324389225124,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]} Hmmm.... – anta40 Jun 20 '17 at 09:53
  • `InvalidRegistration` indicates that the token you're targeting is invalid, make sure that it isn't modified in anyway. – AL. Jun 20 '17 at 11:11
  • Hmm which token? Is that the device's Firebase registration ID? No, it's not changed/invoked anywhere in the code. Or maybe the topic? In the MainActivity, I already have FirebaseMessaging.getInstance().subscribeToTopic("news") And on the PHP side, I have $response = $firebase->send('news', $title, $content); – anta40 Jun 21 '17 at 07:35
  • Hi anta40. Sorry I'm a bit confused. Are you receiving the `InvalidRegistrationError` when sending to a topic (`news`)? – AL. Jun 21 '17 at 08:31
  • Hi AL. Yes indeed. I already checked the Firebase registration ID and server key. Both were correct. – anta40 Jun 22 '17 at 08:21
  • Odd. The change that I suggested was only with the message type. Could you print out the JSON payload that is used to sending the message? – AL. Jun 22 '17 at 08:28
  • The JSON payload is still the same. You can see it in my first post: $payload = array(); $payload['foo'] = '123'; $payload['bar'] = 'xyz'; $push->setPaylod($payload); – anta40 Jun 22 '17 at 10:28
  • Yes I see. But I'm thinking maybe the value `to` parameter is being modified somehow, causing the `InvalidRegistration` error. – AL. Jun 22 '17 at 12:03
  • Hmmm... I checked the $fields variable, which is used in sendPushNotification function. Pretty-printed it, and turns out the value of 'to' is 'news'. Any else you want to know? – anta40 Jun 22 '17 at 15:42
  • You mean just `news`? Without the `/topics/`? – AL. Jun 23 '17 at 00:37
  • Yes. just `news`, and not `/topic/news` – anta40 Jul 02 '17 at 14:57
  • I see. When sending to *topics*, you should always include a prefix of `/topics/`. If you add that in, the `InvalidRegistration` error should disappear. – AL. Jul 03 '17 at 03:07
  • Well, I got this: `{"multicast_id":8331713500529146798,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}` when calling `$firebase->sendNews('/topic/news', $title, $content);`. Here's my latest [firebase.php](https://gist.github.com/anta40/659eedbdd672c4ef745ce83d565fe4ea) – anta40 Jul 04 '17 at 08:20
  • It should be `/topics/` with an `s`. Same way in your code when you call `sendToTopic`. – AL. Jul 04 '17 at 08:31
  • I did the change like you suggested. The PHP code gave this output: `{"message_id":4925507014726462759} `. If that's correct, strangely while debugging the Android app I didn't see any Firebase-related entries. Hmmm. Let me check my Android code.... – anta40 Jul 07 '17 at 08:48
  • I started a new poject, just for testing Firebase. Sending **data** message works fine. What I actually want is **notification** message. It's implemented as `sendNotification()` in [service.php](https://github.com/anta40/anta40firebasedemo/blob/master/backend/firebase.php) Well, I still got the same InvalidRegistration. Anyway, the repo linked above contains both full code of Android app and the PHP backend. – anta40 Jul 13 '17 at 04:00