netosts / laravel-fcm-notifications
A robust and secure Firebase Cloud Messaging (FCM) notification system for Laravel applications
Requires
- php: ^8.1
- illuminate/cache: ^10.0|^11.0
- illuminate/console: ^10.0|^11.0
- illuminate/events: ^10.0|^11.0
- illuminate/http: ^10.0|^11.0
- illuminate/log: ^10.0|^11.0
- illuminate/notifications: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
README
A robust and secure Firebase Cloud Messaging (FCM) notification system for Laravel applications. This package provides a comprehensive solution for sending push notifications with automatic token management, cleanup, and support for all FCM message types.
Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- Usage
- Testing
- Configuration Options
- Troubleshooting
- Support
Features
- ๐ Easy Integration - Drop-in Laravel notification channel
- ๐ Secure Authentication - JWT-based Google OAuth2 authentication
- ๐ฑ Multiple Message Types - Support for notification-only, data-only, and combined messages
- ๐ Automatic Token Cleanup - Removes invalid tokens automatically
- ๐ Batch Sending - Send to multiple devices efficiently
- ๐ ๏ธ Platform Specific - Android and iOS specific configurations
- ๐ Comprehensive Logging - Detailed logging for debugging
- โก Performance Optimized - Token caching and efficient API calls
- ๐งช Testing Commands - Built-in commands for testing functionality
Requirements
- PHP 8.1 or higher
- Laravel 10.0 or higher
- Firebase project with FCM enabled
Installation
You can install the package via Composer:
composer require netosts/laravel-fcm-notifications
Publish the configuration file:
php artisan vendor:publish --tag=fcm-notifications-config
Quick Start
Get up and running in minutes:
1. Set up your Firebase credentials
Add these environment variables to your .env
file:
FCM_PROJECT_ID=your-firebase-project-id FCM_CLIENT_EMAIL=your-service-account@your-project.iam.gserviceaccount.com FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYour-Private-Key-Here\n-----END PRIVATE KEY-----"
2. Add FCM token to your User model
// Add to your users table migration Schema::table('users', function (Blueprint $table) { $table->string('fcm_token')->nullable(); }); // Make it fillable in your User model class User extends Model { protected $fillable = ['fcm_token']; }
3. Send your first notification
use LaravelFcmNotifications\Notifications\FcmNotification; $notification = new FcmNotification( title: 'Welcome!', body: 'Thanks for joining our app' ); $user->notify($notification);
That's it! Your notification will be sent to the user's device.
Configuration
๐ก Tip: If you just want to get started quickly, check the Quick Start section above.
1. Firebase Setup
To use FCM, you need a Firebase project with proper credentials:
- Go to the Firebase Console
- Create a new project or select an existing one
- Navigate to Project Settings โ Service Accounts
- Click Generate New Private Key to download the service account JSON file
2. Environment Variables
Add the following variables to your .env
file:
# Required - Firebase Credentials FCM_PROJECT_ID=your-firebase-project-id FCM_CLIENT_EMAIL=your-service-account@your-project.iam.gserviceaccount.com FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYour-Private-Key-Here\n-----END PRIVATE KEY-----" # Optional - API Settings FCM_TIMEOUT=30 FCM_DEFAULT_MODE=data_only # Optional - Token Management FCM_TOKEN_COLUMN=token FCM_AUTO_CLEANUP_TOKENS=true
โ ๏ธ Important: The private key must include
\n
characters for line breaks.
3. Database Setup
Choose one of the following approaches for storing FCM tokens:
Option A: Multiple Tokens per User (Recommended)
For users with multiple devices, create a dedicated tokens table:
// Create migration: php artisan make:migration create_notification_tokens_table Schema::create('notification_tokens', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained()->onDelete('cascade'); $table->string('token')->unique(); $table->string('device_type')->nullable(); // 'android', 'ios', 'web' $table->timestamps(); });
Option B: Single Token per User
Add a token column to your existing users table:
// Add to your users table migration Schema::table('users', function (Blueprint $table) { $table->string('fcm_token')->nullable(); });
4. Token Management
Configure how the package discovers FCM tokens from your models:
For Multiple Tokens (Option A)
class User extends Model { public function notificationTokens() { return $this->hasMany(NotificationToken::class); } } // Optional: Create a NotificationToken model class NotificationToken extends Model { protected $fillable = ['user_id', 'token', 'device_type']; public function user() { return $this->belongsTo(User::class); } }
For Single Token (Option B)
class User extends Model { protected $fillable = ['fcm_token']; // Optional: Custom method name public function getFcmToken() { return $this->fcm_token; } }
Usage
Basic Usage
There are two main ways to send FCM notifications:
Method 1: Using FcmNotification Directly (Simple)
use LaravelFcmNotifications\Notifications\FcmNotification; // Simple notification $notification = new FcmNotification( title: 'New Message', body: 'You have a new message from John' ); $user->notify($notification);
Method 2: Custom Notification Class (Recommended)
Create a custom notification class for better organization:
php artisan make:notification PushNotification
Extend the FcmNotification
class:
<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use LaravelFcmNotifications\Notifications\FcmNotification; class PushNotification extends FcmNotification implements ShouldQueue { use Queueable; // Add custom logic here if needed }
Use your custom notification:
use App\Notifications\PushNotification; $notification = new PushNotification( title: 'New Message', body: 'You have a new message from John', image: 'https://example.com/avatar.jpg', data: ['message_id' => '123', 'sender_id' => '456'] ); $user->notify($notification);
Direct Service Usage
For more control, use the FCM service directly:
use LaravelFcmNotifications\Facades\Fcm; use LaravelFcmNotifications\Services\FcmMessage; // Create a detailed message $message = FcmMessage::create( title: 'Direct Message', body: 'This message was sent directly via the service' ) ->addData('custom_key', 'custom_value') ->addData('user_action', 'view_profile') ->setAndroidPriority('high') ->setIosBadge(1); // Send to a specific device $result = Fcm::sendToDevice($deviceToken, $message); // Handle the result if ($result['success']) { echo "Message sent successfully!"; } else { echo "Failed to send: " . $result['error']; }
Message Types
FCM supports different message types for different use cases:
1. Notification + Data (Default)
Shows a system notification and passes custom data to your app:
$notification = new FcmNotification( title: 'New Order', body: 'You received a new order #1234', data: ['order_id' => '1234', 'action' => 'view_order'] );
2. Data Only
Sends data silently to your app without showing a notification:
$notification = (new FcmNotification( title: 'Background Sync', // Not shown to user body: 'Data updated', // Not shown to user data: ['sync' => 'true', 'timestamp' => time()] ))->dataOnly();
3. Notification Only
Shows only a system notification without custom data:
$notification = (new FcmNotification( title: 'System Maintenance', body: 'Our systems will be down for maintenance tonight' ))->notificationOnly();
Batch Sending
Send the same message to multiple devices efficiently:
$deviceTokens = ['token1', 'token2', 'token3']; $message = FcmMessage::create( title: 'System Announcement', body: 'Important update for all users' ); $result = Fcm::sendToMultipleDevices($deviceTokens, $message); // Check results echo "Successfully sent to: {$result['summary']['success']} devices\n"; echo "Failed to send to: {$result['summary']['failure']} devices\n"; // Handle individual failures foreach ($result['details'] as $detail) { if (!$detail['success']) { echo "Failed for token: {$detail['token']}, Error: {$detail['error']}\n"; } }
Platform-Specific Configuration
Customize notifications for different platforms:
Android Specific Settings
$message = FcmMessage::create('Android Notification', 'Optimized for Android devices') ->setAndroidChannel('important_notifications') ->setAndroidPriority('high') ->setAndroidSound('custom_sound.mp3') ->addData('android_specific', 'value'); $user->notify($notification);
iOS Specific Settings
$message = FcmMessage::create('iOS Notification', 'Optimized for iOS devices') ->setIosBadge(5) // Badge count ->setIosSound('custom_sound.caf') // Custom sound ->addData('ios_specific', 'value'); $user->notify($notification);
Cross-Platform Message
$message = FcmMessage::create('Universal Message', 'Works on all platforms') // Android settings ->setAndroidPriority('high') ->setAndroidChannel('notifications') // iOS settings ->setIosBadge(1) ->setIosSound('default') // Common data ->addData('universal_data', 'value');
Event Listeners
The package automatically handles token cleanup through events:
// In your EventServiceProvider protected $listen = [ \LaravelFcmNotifications\Events\UnregisteredFcmTokenDetected::class => [ \LaravelFcmNotifications\Listeners\CleanupUnregisteredFcmToken::class, ], ];
When an invalid token is detected, it's automatically removed from your database (if FCM_AUTO_CLEANUP_TOKENS=true
).
Testing
Built-in Test Commands
The package includes helpful commands for testing your FCM integration:
# Test basic FCM functionality with a real device token php artisan fcm:test --token=your-actual-device-token # Test the direct service (bypasses Laravel notifications) php artisan fcm:test --token=your-device-token --direct # Test token cleanup functionality php artisan fcm:test-cleanup your-device-token
Token Validation
Validate FCM tokens before sending notifications:
use LaravelFcmNotifications\Facades\Fcm; // Validate a single token $isValid = Fcm::validateToken($deviceToken); if ($isValid) { echo "Token is valid and ready to receive notifications"; } else { echo "Token is invalid or expired"; } // Validate multiple tokens at once $tokens = ['token1', 'token2', 'token3']; $result = Fcm::validateTokens($tokens); echo "Valid tokens: " . count($result['valid']) . "\n"; echo "Invalid tokens: " . count($result['invalid']) . "\n"; // Remove invalid tokens foreach ($result['invalid'] as $invalidToken) { // Remove from your database NotificationToken::where('token', $invalidToken)->delete(); }
Testing in Development
// Only send notifications in production if (app()->environment('production')) { $user->notify(new PushNotification('Production Alert', 'This is live!')); } else { // Log instead of sending during development Log::info('Would send notification: Production Alert'); }
Configuration Options
The config/fcm-notifications.php
file provides comprehensive configuration options:
return [ // Firebase Credentials (Required) 'project_id' => env('FCM_PROJECT_ID'), 'client_email' => env('FCM_CLIENT_EMAIL'), 'private_key' => env('FCM_PRIVATE_KEY'), // API Settings 'timeout' => env('FCM_TIMEOUT', 30), // Request timeout in seconds // Message Behavior 'default_mode' => env('FCM_DEFAULT_MODE', 'data_only'), // 'notification_only', 'data_only', 'both' // Token Management 'token_column' => env('FCM_TOKEN_COLUMN', 'token'), // Column name for single token storage 'auto_cleanup_tokens' => env('FCM_AUTO_CLEANUP_TOKENS', true), // Auto-remove invalid tokens // Performance Settings 'cache_token' => true, // Cache JWT tokens 'cache_prefix' => 'fcm_notifications_token', // Cache key prefix ];
Configuration Details
Option | Description | Default |
---|---|---|
project_id |
Your Firebase project ID | Required |
client_email |
Service account email | Required |
private_key |
Service account private key | Required |
timeout |
HTTP request timeout (seconds) | 30 |
default_mode |
Default message type | data_only |
token_column |
Single token column name | token |
auto_cleanup_tokens |
Auto-remove invalid tokens | true |
cache_token |
Cache JWT authentication tokens | true |
Troubleshooting
Common Issues
๐ Authentication Failed
Symptoms: Authentication errors, 401 responses from FCM
Solutions:
- Verify your Firebase service account credentials in
.env
- Ensure the private key includes proper line breaks (
\n
) - Check that your service account has FCM permissions
- Validate your
project_id
matches your Firebase project
# Test your credentials
php artisan fcm:test --token=test-token
๐ Tokens Not Found
Symptoms: No notifications sent, "no tokens found" errors
Solutions:
- Check your token storage implementation
- Verify the
token_column
configuration matches your database - Ensure users have FCM tokens stored
- Check relationship methods in your User model
// Debug token discovery $user = User::find(1); dd($user->notificationTokens); // For multiple tokens dd($user->fcm_token); // For single token
๐ฑ Messages Not Received
Symptoms: API calls succeed but notifications don't appear
Solutions:
- Test with the built-in test command
- Check FCM token validity
- Verify your mobile app is properly configured for FCM
- Check device notification settings
- Ensure app is not in battery optimization mode (Android)
# Validate your tokens php artisan tinker >>> Fcm::validateToken('your-device-token')
โก Performance Issues
Symptoms: Slow notification sending, timeouts
Solutions:
- Enable token caching in config
- Use batch sending for multiple recipients
- Implement queue processing for large volumes
- Increase timeout setting if needed
// Use queued notifications for better performance class PushNotification extends FcmNotification implements ShouldQueue { use Queueable; }
Debug Mode
Enable detailed logging for troubleshooting:
# In your .env file LOG_LEVEL=debug APP_DEBUG=true
This will log detailed FCM request/response information to help diagnose issues.
Getting Help
If you're still having issues:
- Check the logs - Look in
storage/logs/laravel.log
for detailed error messages - Test with the built-in commands - Use
php artisan fcm:test
to isolate issues - Validate your setup - Double-check Firebase credentials and configuration
- Review the FCM documentation - Some issues may be Firebase-specific
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security
If you discover any security-related issues, please email netostt91@gmail.com instead of using the issue tracker.
Credits
- Neto Santos - Creator and maintainer
- All Contributors - Community contributors
License
The MIT License (MIT). Please see License File for more information.
Support
Need help? Here's how to get support:
- ๐ง Email: netostt91@gmail.com
- ๐ Bug Reports: GitHub Issues
- ๐ฌ Questions & Discussions: GitHub Discussions
- ๐ Documentation: This README and inline code documentation
โญ If this package helped you, please consider giving it a star on GitHub! โญ