fcm icon indicating copy to clipboard operation
fcm copied to clipboard

Sending notification to the topic without FCM registration token.

Open roshanproductions opened this issue 2 months ago • 7 comments

Hello,

Is it possible to send a notification to topics only? Currently, when I register routeNotificationForFcm in a Notifiable model and return empty string, it throws an error:

{
    "message": "No registration tokens provided",
    "exception": "Kreait\\Firebase\\Exception\\Messaging\\InvalidArgument",
    "file": "/home/forge/pashtostories.org/vendor/kreait/firebase-php/src/Firebase/Messaging/RegistrationTokens.php",
    "line": 61,

roshanproductions avatar Apr 07 '24 12:04 roshanproductions

No, not at this stage. Happy to review any ideas or PRs that implement this.

dwightwatson avatar Apr 07 '24 21:04 dwightwatson

I had the same problem and fixed by overriding send function in FcmChannel.php.

    public function send(mixed $notifiable, Notification $notification): ?Collection
    {
        // Firstly we create the message class
        /** @var \NotificationChannels\Fcm\FcmMessage */
        $fcmMessage = $notification->toFcm($notifiable);

        // If message has a topic then send it directly
        if (!is_null($fcmMessage->topic)) {
            return collect(($fcmMessage->client ?? $this->client)->send($fcmMessage));
        }

        // Otherwise collect tokens from the notifiable model
        $tokens = Arr::wrap($notifiable->routeNotificationFor('fcm', $notification));

        if (empty($tokens)) {
            return null;
        }

        return Collection::make($tokens)
            ->chunk(self::TOKENS_PER_REQUEST)
            ->map(fn ($tokens) => ($fcmMessage->client ?? $this->client)->sendMulticast($fcmMessage, $tokens->all()))
            ->map(fn (MulticastSendReport $report) => $this->checkReportForFailures($notifiable, $notification, $report));
    }

@dwightwatson Is this behaviour correct?

mrcrg avatar May 02 '24 08:05 mrcrg

I'm personally not familiar with sending notifications to topics without a token.

If it's as simple if checking if $fcmMessage->topic exists and then sending it and ignoring any user tokens I'm fine with that. (Although, it does almost feel like an anonymous notification at that point).

Like I said above, happy to look at any PRs that introduce this behaviour.

I think we should still do sendMulticast and check reports for failures like we do with FCM tokens as well for consistency.

dwightwatson avatar May 02 '24 12:05 dwightwatson

Checking if $fcmMessage->topic exists was a simple solution based on our specific use case.

We need to notify an indefinite number of users with the bare minimum load on the server. In our APP every user has the option to subscribe/unsubscribe to a list of topics and then we send push notifications via the Topic model using the Notifiable trait, so it is not anonymous.

Another way to implement this could be: if routeNotificationForFcm returns a \Kreait\Firebase\Messaging\Topic class then we ignore tokens.

I can write a PR, just let me know how do you want to integrate it.

mrcrg avatar May 02 '24 14:05 mrcrg

Would it only ever return a single \Kreait\Firebase\Messaging\Topic or could it return a collection? Or should we use something like routeNotificationForFcmTopic to make it distinct?

Or does it make sense to have a separate channel for this - so you use FcmChannel for token based messages and FcmTopicChannel for other ones? That might be the cleanest option, but would it make sense from your point of view?

A few people liked your earlier comment - perhaps they can share their 2 cents/use cases so we can work out what a good implementation would look like.

dwightwatson avatar May 02 '24 23:05 dwightwatson