laravel-notification-channels / fcm

Firebase Cloud Messaging (FCM) notifications channel for Laravel
https://laravel-notification-channels.com/
MIT License
491 stars 126 forks source link

Prevent sending to device tokens that no longer exist #91

Closed sts-ryan-holton closed 2 years ago

sts-ryan-holton commented 3 years ago

I'm experiencing a common issue with this channel whereby users will register their device with my app and then their device token may change. I store the token on the device, and in the database users table so that I can send them a notification.

The issue is that the project is still appearing to send notifications to device tokens that no longer exist and I'm getting:

GuzzleHttp\Exception\ClientException: Client error: POST https://fcm.googleapis.com/v1/projects/project-beacon-7aa08/messages:send resulted in a 404 Not Found response: (truncated...) in /var/www/project-beacon-api/shared/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113

How do I prevent this behaviour?

ankurk91 commented 2 years ago

You can listen to the NotificationFailed event and remove token from your database

rbresjer commented 2 years ago

I fixed it with this event listener:

<?php

namespace App\Listeners;

use App\Models\User;
use Illuminate\Notifications\Events\NotificationFailed;
use Kreait\Firebase\Exception\Messaging\NotFound;

class NotificationFailedListener
{
    /**
     * Handle the event.
     *
     * @param  NotificationFailed  $event
     * @return void
     */
    public function handle(NotificationFailed $event)
    {
        if (empty($event->data['exception'])) {
            return;
        }
        $exception = $event->data['exception'];

        if ($event->notifiable instanceof User) {
            /** @var User */
            $user = $event->notifiable;

            if ($exception instanceof NotFound)  {
                $user->fcm_token = null;
                $user->save();
            }
        }
    }
}

Register it in your EventServiceProvider as follows:

    protected $listen = [
        // ...
        NotificationFailed::class => [
            NotificationFailedListener::class,
        ],
    ];