Send Firebase push notifications with Laravel php framework.
- Using the latest Firebase HTTP v1 API
- Send message to a topic or condition π
- 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 π
You can install this package via composer:
composer require "ankurk91/fcm-notification-channel"
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
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');
}
}
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());
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,
];
Please see CHANGELOG for more information what has changed recently.
composer test
If you discover any security issue, please email pro.ankurk1[at]gmail[dot]com
instead of using the issue tracker.
The package is based on this rejected PR
This package is licensed under MIT License.