firebase-php: Multicast and unexisting/expired tokens

Describe the bug We are using the libraries multicast capabilities to sent messages to the devices of a user (a user can have multiple devices, therefor we track multiple device tokens for each user). In an older version of the library it was possible to send single messages to a single device token. With the single message it was possible to identify if the device for a registration token was unregistered or if the message was delivered successfully. With the multicast implementation all messages are reported as successfully delivered - even for registration tokens which are unregistered. It seems that the subResponses are different depending on the registered / unregistered state of the device / deviceToken.

registered device: { "name": "projects/[project-name]/messages/1584562990026860" }

probably unregistered device { "name": "projects/[project-name]/messages/0:1584562990029639%3f04f5553f04f555" }

Are we missing something or is this the intended behavior?

To Reproduce item 0 = successfully delivered item 1 = old unregistered token

$report = {Kreait\Firebase\Messaging\MulticastSendReport} [1]
 items = {array} [24]
  0 = {Kreait\Firebase\Messaging\SendReport} [3]
   target = {Kreait\Firebase\Messaging\MessageTarget} [2]
   result = {array} [1]
    name = "projects/[project-name]/messages/1584566014466720"
   error = null
  1 = {Kreait\Firebase\Messaging\SendReport} [3]
   target = {Kreait\Firebase\Messaging\MessageTarget} [2]
   result = {array} [1]
    name = "projects/[project-name]/messages/0:1584566014634780%3f04f5553f04f555"
   error = null

Expected behavior It should be possible to differentiate between successfully sent messages and messages that couldn’t be sent because the device got unregistered when using multicastmessage

Environment (please complete the following information):

  • OS: webdevops/php-nginx-dev:7.2 (debian based docker-image)
  • PHP version: 7.2.26
  • Firebase SDK Version: 4.36.2

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 17 (8 by maintainers)

Most upvoted comments

This works for me. Thank you for your help. Will hit the sponsor button. This package helps me a lot.

if ($report->hasFailures()) {
    foreach ($report->failures()->getItems() as $failure) {
        /** @var SendReport $failure */
        if ($failure->messageWasSentToUnknownToken()) {
            $token = $failure->target()->value();

            PushToken::where('token', $token)
                ->delete();
        }
    }
}

@tobischulz There’s a helper that I’ve apparently forgotten about: MultiCastSendReport::unknownTokens()

This would enable you to do

foreach ($report->unknownTokens() as $token) {
	PushToken::where('token', $token)->delete();
}

without needing to check for failures yourself 🤞

In a way, that’s good! Depending on how you send messages, you could resolve this ad-hoc like this:

When sending a message to a single device

$message = CloudMessage::withTarget('token', $token = 'xxx')
	->withNotification(/* ... */)
    // etc.
; 

try {
    $messaging->send($message);
} catch (\Kreait\Firebase\Exception\Messaging\NotFound $e) {
	// Delete $token from local token storage
}

When sending multicast messages

$message = CloudMessage::new()
	->withNotification(/* ... */)
    // etc.
;

$report = $messaging->sendMulticast($message, $tokens);

foreach ($report->failures() as $failure) {
    /** @var SendReport $failure */
    if ($failure->messageWasSentToUnknownToken()) {
        $token = $failure->target()->value();
	    // Delete $token from local token storage
    }
}