Fcm Notification Channel Save

All in One Firebase push notification channel for Laravel :bell:

Project README

FCM Notification Channel for Laravel

Packagist GitHub-tag License Downloads GH-Actions codecov

Send Firebase push notifications with Laravel php framework.

Highlights

  • Using the latest Firebase HTTP v1 API
  • Send message to a topic or condition :wink:
  • Send message to a specific device or multiple devices (Multicast)
  • Send additional RAW data with notification
  • Supports multiple Firebase projects in single Laravel app:fire:
  • Invalid token handling with event and listeners
  • Fully tested package with automated test cases
  • Powered by battle tested Firebase php SDK :rocket:

Installation

You can install this package via composer:

composer require "ankurk91/fcm-notification-channel"

Configuration

This package relies on laravel-firebase package to interact with Firebase services. Here is the minimal configuration you need in your .env file

# relative or full path to the Service Account JSON file
FIREBASE_CREDENTIALS=firebase-credentials.json

You will need to create a service account and place the JSON file in your project root.

Additionally, you can update your .gitignore file

/firebase-credentials*.json

Usage

You can use the FCM channel in the via() method inside your Notification class:

<?php
namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use NotificationChannels\FCM\FCMChannel;
use Kreait\Firebase\Messaging\CloudMessage;

class ExampleNotification extends Notification implements ShouldQueue
{
    use Queueable;

    public function via($notifiable): array
    {
        return [FCMChannel::class];
    }

    public function toFCM($notifiable): CloudMessage
    {
        return CloudMessage::new()
            ->withDefaultSounds()
            ->withNotification([
                'title' => 'Order shipped',
                'body' => 'Your order for laptop is shipped.',
            ])         
            ->withData([
                'orderId' => '#123'
            ]);
    }    
}

Prepare your Notifiable model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;
       
    /**
    * Assuming that you have a database table which stores device tokens.
    */
    public function deviceTokens(): HasMany
    {
        return $this->hasMany(DeviceToken::class);
    }
    
    public function routeNotificationForFCM($notification): string|array|null
    {
         return $this->deviceTokens->pluck('token')->toArray();
    }
    
    /**
    * Optional method to determine which message target to use
    * We will use TOKEN type when not specified
    * @see \Kreait\Firebase\Messaging\MessageTarget::TYPES
    */
    public function routeNotificationForFCMTargetType($notification): ?string
    {
        return \Kreait\Firebase\Messaging\MessageTarget::TOKEN;
    }
    
    /**
    * Optional method to determine which Firebase project to use
    * We will use default project when not specified
    */
    public function routeNotificationForFCMProject($notification): ?string
    {
        return config('firebase.default');
    }   
}

Send to a topic or condition

This package is not limited to sending notification to tokens.

You can use Laravel's on-demand notifications to send push notification to a topic or condition or multiple tokens.

<?php

use Illuminate\Support\Facades\Notification;
use Kreait\Firebase\Messaging\MessageTarget;
use App\Notification\ExampleNotification;

Notification::route('FCM', 'topicA')
    ->route('FCMTargetType', MessageTarget::TOPIC)
    ->notify(new ExampleNotification());

Notification::route('FCM', "'TopicA' in topics")
    ->route('FCMTargetType', MessageTarget::CONDITION)
    ->notify(new ExampleNotification());

Notification::route('FCM', ['token_1', 'token_2'])
    ->route('FCMTargetType', MessageTarget::TOKEN)
    ->notify(new ExampleNotification());

Events

You can consume Laravel's inbuilt notification events

<?php

namespace App\Providers;

use Illuminate\Notifications\Events;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        Events\NotificationSent::class => [
            //\App\Listeners\FCMNotificationSent::class,
        ],
        Events\NotificationFailed::class => [
            \App\Listeners\FCMNotificationFailed::class,
        ],
    ];    
}

Here is the example of the failed event listener class

<?php

namespace App\Listeners;

use App\Models\User;
use Illuminate\Support\Arr;
use NotificationChannels\FCM\FCMChannel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Kreait\Laravel\Firebase\Facades\Firebase;
use Illuminate\Notifications\Events\NotificationFailed;

class FCMNotificationFailed implements ShouldQueue
{
    public function handle(NotificationFailed $event)
    {
        if ($event->channel !== FCMChannel::class) {
            return;
        }

        /** @var User $user */
        $user = $event->notifiable;
        
        $invalidTokens = $this->findInvalidTokens($user);
        if (count($invalidTokens)) {           
            $user->deviceTokens()->whereIn('token', $invalidTokens)->delete();
        }
    }
    
    protected function findInvalidTokens(User $user): array
    {
        $tokens = Arr::wrap($user->routeNotificationFor('FCM'));
        if (! count($tokens)) {
            return [];
        }

        $project = $user->routeNotificationFor('FCMProject');
        $response = Firebase::project($project)->messaging()->validateRegistrationTokens($tokens);

        return array_unique(array_merge($response['invalid'], $response['unknown']));
    }
}

Read more about validating device tokens here

Then; you may want to ignore this exception in your app/Exceptions/Handler.php

protected $dontReport = [
    \NotificationChannels\FCM\Exception\InvalidRecipientException::class,
];

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

composer test

Security

If you discover any security issue, please email pro.ankurk1[at]gmail[dot]com instead of using the issue tracker.

Attribution

The package is based on this rejected PR

License

This package is licensed under MIT License.

Open Source Agenda is not affiliated with "Fcm Notification Channel" Project. README Source: ankurk91/fcm-notification-channel

Open Source Agenda Badge

Open Source Agenda Rating