Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Push Notification Laravel Package

davibennun/laravel-push-notification

Laravel package for sending push notifications to iOS and Android devices via APNs and GCM/FCM. Integrates with Laravel's queue, config, and service container, letting you dispatch notifications to one or many devices through a simple, unified API.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: this package is archived and its underlying transports are dead (APNs binary protocol retired Nov 2020, GCM shut down 2019). Treat the steps below as inheritance instructions — how to read, run, and safely extract value from an existing install — not as a greenfield setup.

Install (legacy constraints). The package pins old illuminate/support ranges, so on a modern Laravel app composer require davibennun/laravel-push-notification will fail dependency resolution. Options, in order of preference:

  1. Don't install it — port the call sites to kreait/laravel-firebase (FCM v1) and an HTTP/2 APNs client.
  2. If you must run the legacy app as-is, keep it on its original Laravel version, or add it via a VCS repository entry and accept that you're freezing that dependency tree.

Register it (Laravel ≤5.4, or when package discovery is disabled):

// config/app.php
'providers' => [
    Davibennun\LaravelPushNotification\LaravelPushNotificationServiceProvider::class,
],
'aliases' => [
    'PushNotification' => Davibennun\LaravelPushNotification\Facades\PushNotification::class,
],

Publish config and drop credentials:

php artisan vendor:publish --provider="Davibennun\LaravelPushNotification\LaravelPushNotificationServiceProvider"
# older versions: --tag="config"
// config/pushnotification.php
'apps' => [
    'appNameIOS' => [
        'environment' => 'development',      // 'production' for release builds
        'certificate' => base_path('storage/certs/ios/apns.pem'), // combined cert + key
        'passPhrase'  => env('APNS_PASSPHRASE'),
        'service'     => 'apns',
    ],
    'appNameAndroid' => [
        'environment' => 'production',
        'apiKey'      => env('GCM_API_KEY'), // legacy Firebase server key
        'service'     => 'gcm',
    ],
],

Where to look first. Search the codebase for PushNotification:: — every send is a fluent chain, so grep -rn "PushNotification::app" app/ gives you the complete surface area. Then read config/pushnotification.php to map app aliases to platforms.

First use case — the canonical "notify one device" call:

use PushNotification;

PushNotification::app('appNameIOS')
    ->to($deviceToken)
    ->send('Your order has shipped');

For a richer payload, build a Message instead of passing a string:

$message = PushNotification::Message('Your order has shipped', [
    'badge'        => 1,
    'sound'        => 'default',
    'custom'       => ['order_id' => $order->id, 'screen' => 'orders'],
]);

PushNotification::app('appNameIOS')->to($deviceToken)->send($message);

Implementation Patterns

Wrap it behind a domain service immediately. The single highest-value refactor on an inherited install is to hide the facade behind one interface, so the eventual migration is a one-file change:

interface PushNotifier
{
    public function toDevice(string $token, string $platform, string $title, array $data = []): void;
}

class LegacyPushNotifier implements PushNotifier
{
    public function toDevice(string $token, string $platform, string $title, array $data = []): void
    {
        $app = $platform === 'ios' ? 'appNameIOS' : 'appNameAndroid';

        PushNotification::app($app)
            ->to($token)
            ->send(PushNotification::Message($title, ['custom' => $data]));
    }
}

Then swap the binding in AppServiceProvider when you move to FCM/APNs HTTP/2 — call sites never change.

Always send from a queued job. ->send() opens a socket to Apple/Google and blocks. In a request cycle this is a latency bug waiting to happen, and with a DeviceCollection it's N sequential socket writes:

class SendPush implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(public int $userId, public string $text) {}

    public function handle(PushNotifier $push): void
    {
        UserDevice::where('user_id', $this->userId)->chunk(500, function ($devices) use ($push) {
            foreach ($devices as $device) {
                try {
                    $push->toDevice($device->token, $device->platform, $this->text);
                } catch (\Throwable $e) {
                    report($e); // never let one bad token kill the batch
                }
            }
        });
    }
}

Fan-out with DeviceCollection when you're pushing to a group (topic-ish behaviour, e.g. "all users on this order"):

$devices = PushNotification::DeviceCollection([
    PushNotification::Device($tokenA, ['badge' => 3]),
    PushNotification::Device($tokenB),
]);

PushNotification::app('appNameIOS')
    ->to($devices)
    ->send(PushNotification::Message('Flash sale starts now'));

Store tokens properly. One row per device, not per user — people have a phone and a tablet:

user_devices: id, user_id, platform ('ios'|'android'), token (unique), app_env, last_seen_at

Index on token and make it unique. Prune on delivery failures (APNs 410 Unregistered, GCM NotRegistered) — the package won't do this for you.

Multi-environment app aliases. Because APNs sandbox and production tokens are not interchangeable, define separate config entries (appNameIOS_dev, appNameIOS_prod) and pick based on app()->environment(). Same for an Android staging entry pointing at a separate Firebase project.

Testing. Bind a fake rather than hitting the network:

PushNotification::shouldReceive('app')->once()->andReturnSelf();
PushNotification::shouldReceive('to')->andReturnSelf();
PushNotification::shouldReceive('send')->once();

Better: bind a FakePushNotifier collecting toDevice() calls, and assert against that — it survives the migration.

Integrate with Laravel's notification system if you're modernizing incrementally: keep the package as the transport inside a custom NotificationChannel, so business code uses $user->notify(new OrderShipped($order)) and the legacy detail stays quarantined in one channel class.

Gotchas and Tips

The package cannot reach current endpoints. This is the blocking issue, not a footnote. Apple only serves HTTP/2 (api.push.apple.com) with .p8 token auth or modern .p12 certs; Google only serves FCM v1 (fcm.googleapis.com/v1/projects/.../messages:send) with OAuth2 service-account credentials. Any install still "working" is either pointed at a proxy, a private endpoint via the Android url config override, or silently failing. Verify with a real device before you promise anything.

Migration targets, in order of fit:

  • Android/FCM: kreait/laravel-firebase (v1 API, service account JSON).
  • iOS/APNs: edamov/pushok or laravel-notification-channels/apn.
  • Web push (if the product grew one): laravel-notification-channels/webpush.
  • Notifications-as-abstraction: laravel-notification-channels family, so via() returns ['apn', 'fcm'].

Certificate format is the #1 onboarding trap. APNs needs a single .pem containing both the certificate and the private key, plus the correct passphrase. Convert with:

openssl pkcs12 -in apns.p12 -out apns.pem -nodes -clcerts

Use an absolute path (base_path(...)) — a relative path resolves against the PHP working directory, which differs between CLI and FPM.

config:cache bites twice. Editing a cert path or passphrase after php artisan config:cache does nothing until php artisan config:clear. Same for .env values consumed at config-load time.

Environment mismatch produces silent no-ops. Sandbox tokens against production, or vice versa, return errors that are easy to swallow. The environment key must match the build that generated the token; dev/TestFlight builds are sandbox, App Store builds are production.

Payload limits and typing. The legacy binary protocol caps payloads around 256 bytes (2 KB/4 KB only for newer specs); an oversized message is rejected, not truncated. Keep badge an integer, sound a string filename on the device or 'default', and put all app data under custom — a flat top-level array will be silently dropped.

No retries, no backoff, no connection pooling. send() throws on connection failure; one dead token in a collection can abort the whole call depending on version. Always wrap per-device and report().

Token feedback/pruning is on you. Any APNs feedback capability in the underlying library is obsolete; instead, treat 410/NotRegistered responses as delete signals and log the raw response so you can inspect error codes.

Facade discovery. On Laravel 5.5+ with dont-discover configured, the alias disappears and you get Class 'PushNotification' not found at runtime — check composer.json extra.laravel.dont-discover and config/app.php before debugging anything else.

Extension points are thin by design. Message and Device are simple value objects you can keep reusing in your own adapter; the transport layer is not worth extending. The real extension point is the service binding described above — treat it as the seam you'll cut along during migration, and avoid letting PushNotification:: leak into controllers, models, or Blade.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console