KuNal
KuNal

Reputation: 39

Unable to send notification to multiple devices using FCM

I'm getting a notification only in one device that is set as the first token stored the table in mySQL DB and the notification is not sent to the rest of the token numbers. I tried a WHILE loop and stored the token numbers in an array, but it did not work.

Please suggest a solution. Thank you.

Here is my code:

enter image description here

<?php
require "init.php";
$message=$_POST['message'];
$title=$_POST['title'];
$path_to_fcm='https://fcm.googleapis.com/fcm/send';
$server_key="A*************************Q";
$sql="select token from fcm_info";
$result =mysqli_query($con,$sql);
$row=mysqli_fetch_row($result);
$key=$row[0];
$headers = array(

    'Authorization:key=' .$server_key,
    'Content-Type:application/json'
);
$fields =array('to'=>$key,  
                'notification'=>array('title'=>$title,'body'=>$message));  

$payload =json_encode($fields);
$curl_session =curl_init();
curl_setopt($curl_session,CURLOPT_URL, $path_to_fcm);
curl_setopt($curl_session,CURLOPT_POST, true);
curl_setopt($curl_session,CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl_session,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl_session,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_session,CURLOPT_IPRESOLVE, CURLOPT_IPRESOLVE);
curl_setopt($curl_session,CURLOPT_POSTFIELDS, $payload);
$result=curl_exec($curl_session);
curl_close($curl_session);
mysqli_close($con);
?>

Upvotes: 2

Views: 8672

Answers (4)

Dankyi Anno Kwaku
Dankyi Anno Kwaku

Reputation: 1293

//////////////////////    FCM  START      /////////////////////////

  $path_to_fcm = "https://fcm.googleapis.com/fcm/send";

  $server_key = "your_server_key";

  $headers = array(
    'Authorization:key=' . $server_key, 
    'Content-Type:application/json');


  $keys = ["key_1", "key_2"];

  $fields = array(
    "registration_ids" => $keys,
    "priority" => "normal",
    'notification' => array(
          'title' => "title of notification",
          'body' => "your notification goes here" 
         )
       );

   $payload = json_encode($fields);


  $curl_session = curl_init();

  curl_setopt($curl_session, CURLOPT_URL, $path_to_fcm);
  curl_setopt($curl_session, CURLOPT_POST, true);
  curl_setopt($curl_session, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($curl_session, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  curl_setopt($curl_session, CURLOPT_POSTFIELDS, $payload);

  $curl_result = curl_exec($curl_session);

//////////////////////    FCM  END      /////////////////////////

This works for me.

Upvotes: 0

Khaledonian
Khaledonian

Reputation: 2203

"Please suggest a solution"

I would like to suggest using Services. You're most recommended to read the documention by Android Studio here.

There is a lot to perceive about Services, but at the moment I believe a snippet will be most helpful to you, here is a little code,

Create a class called HelloService

and paste the following code inside with the proper imports*

public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;

// Handler that receives messages from the thread
 private final class ServiceHandler extends Handler {
  public ServiceHandler(Looper looper) {
      super(looper);
  }
  @Override
  public void handleMessage(Message msg) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          // Restore interrupt status.
          Thread.currentThread().interrupt();
      }
      // Stop the service using the startId, so that we don't stop
      // the service in the middle of handling another job
      stopSelf(msg.arg1);
  }
}

@Override
public void onCreate() {
// Start up the thread running the service.  Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block.  We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
        Process.THREAD_PRIORITY_BACKGROUND);
thread.start();

// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
   Toast.makeText(this, "servicestarting",Toast.LENGTH_SHORT).show();


  Message msg = mServiceHandler.obtainMessage();
  msg.arg1 = startId;
  mServiceHandler.sendMessage(msg);

  // If we get killed, after returning from here, restart
  return START_STICKY;
      }

@Override
public IBinder onBind(Intent intent) {
   // We don't provide binding, so return null
   return null;
          }


 @Override
 public void onDestroy() {
   Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
 }
}

"This is overhwleming" you might think to yourself. However it's but the contrary.

Example for Services + Firebase

Instead of pushing a message from Firebase, let's say you want to notify a user whenever a modification takes place in one of your databases

first, create databasereference earlier on the Oncreate

mDatabaseLike=FirebaseDatabase.getInstance().getReference().child("Likes"); 

Go to 'handleMessage Method' and add the following

      @Override
    public void handleMessage(Message msg) {



        mDatabaseLike.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {

             notifyUserOfDBupdate()


            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });




        //stopSelf(msg.arg1);
    }
}

Here is the notifyUserOfDBupdate method and how to notify a user

   private void notifyUserOfDBupdate() {
    //Intents
    Intent Pdf_view = new Intent(this, //class to throw the user when they hit on notification\\.class);
    PendingIntent pdf_view = PendingIntent.getActivity(this, 0, Pdf_view, 0);


    //Notification Manager
    NotificationManager nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);


    //The note
    Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    Notification noti = new NotificationCompat.Builder(getApplicationContext())
            .setTicker("TickerTitle")
            .setContentTitle("content title")
            .setSound(soundUri)
            .setContentText("content text")
            .setContentIntent(pdf_view).getNotification();


    //Execution
    noti.flags = Notification.FLAG_AUTO_CANCEL;
    nm.notify(0, noti);
}

Now run your application once on your real device and a second time on an emulator. Once either one of two modifies your firebase database, the other will be notified instantly.

Modify whichever method you like inside the HandleMessage method. It will be eternal, not unless you make it killable.

kindest regards

Upvotes: -1

Yogendra
Yogendra

Reputation: 2234

Use 'registration_ids' instead of 'to' and pass comma separated multiple registrations ids to use multicast in FCM. Final payload should be like:

{
"registration_ids":["id1","id2",...],
  "priority" : "normal",
  "data" : {
    "title" : "Title",
    "message" : "Message to be send",
    "icon": "icon_path"
  }
}

see https://developers.google.com/cloud-messaging/http-server-ref for more help

Upvotes: 6

Lalit Dhameliya
Lalit Dhameliya

Reputation: 348

You need to cover the notification sending logic in method and then start the loop & call that method in each iterations pass token and message to the method.

Upvotes: -1

Related Questions