2

I need to send FCM push notifications to multiple devices. I cannot use "topics" for that because I need to send it to specific and multiple tokens.

In the legacy method, I used "register_ids" for this purpose, but Google announced on June 20, 2023, that the legacy method will end on June 20, 2024. In the new v1 API, "register_ids" is no longer supported.

What I need is a solution to send push notifications to multiple tokens using cURL and PHP.

On this website, someone asked a similar question to mine:

FCM batch messages URL

@Frank van Puffelen said:

"In this new, versioned API, you can send multiple messages by sending a multi-part request to the regular endpoint. This process is fully documented in the section on sending a batch of messages and is also supported by most of the available Admin SDKs."

Frank von Puffelen provided a link:

https://firebase.google.com/docs/cloud-messaging/send-message#send-a-batch-of-messages

However, there is now a note on this website stating:

"The batch send methods described in this section were deprecated on June 21, 2023, and will be removed in June 2024. Instead, use the standard HTTP v1 API send method by implementing your own batch send logic, iterating through the list of recipients and sending to each recipient's token. For Admin SDK methods, make sure to update to the next major version."

Further up on that website, there is a section titled "Send messages to multiple devices." However, this section only provides solutions for node.js, Java, Python, Go, C#, and REST. I need a solution for PHP and cURL.

What I have tried so far is as follows, but it is not working because of error with the schema:

$tokens = array(
"token 1",
"token 2"
);

foreach ($tokens as $token) {
$data = json_encode(array(
"message" => array(
"token" => $token,
"notification" => array(
"title" => "New Message",
"body" => "New Text",
"image" => "https://example.com/test.jpg"
),
"data" => array(
"website_link" => "https://example.com/",
"icon" => "https://example.com/test.jpg"
)
)
));

$accessToken = file_get_contents("access_token.txt");

curl_setopt_array($curl, array(
CURLOPT_URL => 'https://fcm.googleapis.com/v1/projects/myapp/messages:send',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Authorization: Bearer ' . $accessToken
),
));
}

$response = curl_exec($curl);

I know I can loop the cURL code for each token, but I believe this is not a good practice because it would trigger the "https://fcm.googleapis.com/v1/projects/myapp/messages:send" multiple times in a row.

I would prefer to collect all the tokens and send them at once. Is there a solution?

Thank you very much.

labu77
  • 605
  • 1
  • 9
  • 30

1 Answers1

1

I have found a solution and I hope it will save someone's time.

Edit: Sorry to say, but this solution will also be deprecated next year. See this topic with a new solution:

Firebase HTTP v1 API and no batch send anymore?

Please check the section "Send messages to multiple devices" on this website:

https://firebase.google.com/docs/cloud-messaging/send-message#send-messages-to-multiple-devices

Focus on the REST part.

Using this example, I have implemented a foreach loop in the same REST API schema. In this case, you don't need a batch_request.txt file for cURL.

The only things you need for the code are your array of device tokens and the bearer access token. To obtain the access token, I found this PHP function from Peter Bruins:

Generating access token for Firebase Messaging

Make sure to change the following part of the code to match your app name:

$request .= "POST /v1/projects/your-app/messages:send\r\n";

Here is the PHP cURL FCM v1 API solution:

$deviceTokens = 'yourarrayoftokens';

foreach ($deviceTokens as $token) {
  $request .= "\r\n--subrequest_boundary\r\n";
  $request .= "Content-Type: application/http\r\n";
  $request .= "Content-Transfer-Encoding: binary\r\n\r\n";
  $request .= "POST /v1/projects/your-app/messages:send\r\n";
  $request .= "Content-Type: application/json\r\n";
  $request .= "accept: application/json\r\n\r\n";
  $request .= '{
    "message":{
       "token":"' . $token . '",
       "notification":{
         "title":"FCM Push Test",
         "body":"This is only a test",
         "image":"http://example.com/1.jpg"
       }
    }
}';
}

$request .= "\r\n\r\n--subrequest_boundary--";

$curl = curl_init();

$accessToken = file_get_contents("bearer_token.txt");

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://fcm.googleapis.com/batch',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => $request,
  CURLOPT_HTTPHEADER => array(
    'Content-Type: multipart/mixed; boundary="subrequest_boundary"',
    'Authorization: Bearer ' . $accessToken 
  ),
));

$response = curl_exec($curl);
echo $response . '<br />';

I hope that "https://fcm.googleapis.com/batch" will not be deprecated in the near future. From my understanding, the only change required is replacing "https://fcm.googleapis.com/send" with "/v1/projects/your-app/messages:send", while "https://fcm.googleapis.com/batch" can still be used. Please correct me if I am wrong. Google recommends this solution and has provided it as a recommended approach in their official documentation. (see the url at the end of the following line)

curl --data-binary @batch_request.txt -H 'Content-Type: multipart/mixed; boundary="subrequest_boundary"' -H 'Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA' https://fcm.googleapis.com/batch

If someone need a data foreach instead of notification, take this foreach:

foreach ($deviceTokens as $token) {
  $request .= "\r\n--subrequest_boundary\r\n";
  $request .= "Content-Type: application/http\r\n";
  $request .= "Content-Transfer-Encoding: binary\r\n\r\n";
  $request .= "POST /v1/projects/my-app/messages:send\r\n";
  $request .= "Content-Type: application/json\r\n";
  $request .= "accept: application/json\r\n\r\n";
  $request .= '{
    "message":{
       "token":"' . $token . '",
       "data":{
         "message_title":"Test",
         "message_body":"Test",
         "website_link":"example.com", 
         "notification_type":"message",
         "image":"example.com/1.jpg"
       }
    }
}';
}
labu77
  • 605
  • 1
  • 9
  • 30
  • Did you can add data field with batch request? I'm looking for FCM Admin SDK the other choice https://firebase-php.readthedocs.io/en/stable/cloud-messaging.html#send-multiple-messages-at-once – Cristian Jun 23 '23 at 10:42
  • Yes, data field is also possible. I have it running with a data field but I thought most others need notification. I will update my answer for data aswell. – labu77 Jun 23 '23 at 12:17
  • Hi labu77 I'm Cristian, I read your solution about REST batch call, I see in firebase.google.com/support/faq#fcm-23-deprecation and Batch Send API fcm.googleapis.com/batch will start failing after 6/21/2024, I'm very confused! Does your method work after that? – Cristian Jul 21 '23 at 10:55
  • Hello Christian. I have found out the same. My solution does work but I do not recommend the solution because it will fail after 2024. I found a better solution from jeromegomez and its working very well. If you need help, let me know. See this link: https://stackoverflow.com/questions/76563436/firebase-http-v1-api-and-no-batch-send-anymore/76568887 – labu77 Aug 05 '23 at 10:46
  • Hi labu, when I wrote to you I discussed with Elad Nava, you can see my edited solution in PHP at https://stackoverflow.com/questions/76525522/fcm-http-v1-api-and-multicasting-messages-in-php/76545442?noredirect=1#comment135297791_76545442 the only way to do multiple messages is to use HTTP/2 and CURLPIPE_MULTIPLEX as suggested by firebase documentation – Cristian Aug 06 '23 at 07:34