How to send mobile push notifications with PHP and Firebase

0
33


Stock by McLittle / Shutterstock.com

Google’s Firebase Cloud Messaging (FCM) service is a free and convenient way to distribute push notifications to mobile devices. It works with iOS, Android and web targets, eliminating differences between platforms. You send your payload once to the Firebase API and get real-time delivery to all your users.

In this article, we’ll show you how to use Firebase to send push notifications from your server-side PHP code. We are using the third php-firebase-cloud-messaging (PHP-FCM) to further simplify Firebase integration.

delineate the architecture

Successful push notification delivery requires multiple components to work together. First, you need an active Firebase account with a project that has FCM enabled. We will configure it in the following steps. You’ll be issued a server key that your PHP backend must include with your Firebase requests.

You’ll also need an app that uses the Firebase SDK to produce a client registration token. This token must be sent to your PHP backend. Remain in your database along with information that identifies the customer, such as their logged in user ID within your application.

Since this article focuses on back-end integration, we’ll assume you already have a Firebase client app that subscribes to notifications and retrieves a registration token. You can follow the documentation to create a basic Android app if you need a sample project. Within your client-side code, send the Firebase token to an API endpoint that you’ll create in your PHP service.

Once you have some client tokens available on your server, you can send push notifications by making HTTP requests to the FCM API. Firebase will mediate with the individual notification delivery platforms and push your alert to the specified devices. FCM internally maps each client token to the correct platform, such as Google Play Services for Android and Apple Push Notification Service (APNS) for iOS.

Create your Firebase project

firebase console home page image

Head over to the Firebase Console, log in, and click “Add Project” to start setting up your integration. Give your project a name and click the initial setup prompts. Click on the settings cog in the top left corner when you get to the dashboard. Choose “Project Settings” from the menu that appears.

image of the FCM configuration in the Firebase console

Go to the “Cloud Messaging” tab and make a note of your server key. Your PHP service will use this credential to send notifications to the Firebase API.

firebase console home page image

You must register your mobile apps in the Firebase console. Back on the home page, use the “Add an app” buttons to add your iOS and Android components. Follow the setup wizard to provide your app data and download your Firebase config file. This should be referenced when you initialize Firebase in your client-side code.

image of the FCM configuration in the Firebase console

If you’re building an iOS app, you need to manually link your APNS key to Firebase. Click the settings cog at the top left, choose “Project Settings” and navigate back to “Cloud Messaging”. An “Apple apps” section will appear when you have an iOS component in your project. Add an APNS key or certificate from your Apple developer account to complete the integration. This allows FCM to send notifications to APNS on your behalf.

Preparing your PHP application

Start your PHP project by adding the PHP-FCM library using Composer:

composer require sngrl/php-firebase-cloud-messaging

Within your code, create an instance of PHP-FCM Client class:

use sngrlPhpFirebaseCloudMessagingClientClient;
 
$client = new Client();
$client -> setApiKey("FCM-SERVER-KEY");
$client -> injectGuzzleHttpClient(new GuzzleHttpClient());

pass the setApiKey() method the server key you copied from your Firebase API console. In a real application, this must be stored securely and treated as a sensitive secret.

PHP-FCM relies on an injected Guzzle instance to perform its HTTP requests. Guzzle is automatically included as a dependency, so you don’t need to install it manually. We are building a new Guzzle client in the example above; you could reuse an existing instance if you already have Guzzle in your app.

The MCF Client The instance is now ready to send notifications to your FCM account.

Client Token Registration

Notifications are distributed to client tokens that represent your users’ devices. As explained above, you’ll need to expose an API endpoint in your application that allows your client applications to send their FCM token after the user signs in.

Here’s a basic example of what this might look like:

$token = $_POST["fcmToken"];
$userId = ((int) $_POST["userId"]);
 
/**
 * Call a function which persists a user/token 
 * association to your database
 */
saveUserFcmToken($userId, $token);

To send an automatic notification to each registered device, select all the tokens in your data store. You can send to a specific user by retrieving the tokens associated with their ID. This would display the notification on all devices they’re signed in to, which is usually the intended behavior.

Send notifications

PHP-FCM abstracts each notification delivery into a Message object. This wraps a Notification – which contains the text that is displayed to the user – and any delivery options you provide.

prepare your Notification first:

use sngrlPhpFirebaseCloudMessagingClientNotification;
 
$notification = new Notification(
    "Notification Title",
    "The longer text of the notification, displayed below the title."
);

Next, create a Message to represent delivery of the notification:

use sngrlPhpFirebaseCloudMessagingClientMessage;
 
$message = new Message();
$message -> setNotification($notification);

Before you send your message, add one or more recipients. the addRecipient() method takes a Device instance; this class needs one of your FCM client tokens as its constructor parameter:

use sngrlPhpFirebaseCloudMessagingClientRecipientDevice;
 
$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-1"));
$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-2"));

You are now ready to send the message using the Client previously created:

$client -> send($message);

The notification will be sent to the devices you added as recipients.

Here’s a complete example that wraps the notification handling code in a convenient function:

use sngrlPhpFirebaseCloudMessagingClientClient;
use sngrlPhpFirebaseCloudMessagingClientMessage;
use sngrlPhpFirebaseCloudMessagingClientNotification;
use sngrlPhpFirebaseCloudMessagingClientRecipientDevice;
 
$client = new Client();
$client -> setApiKey("FCM-SERVER-KEY");
$client -> injectGuzzleHttpClient(new GuzzleHttpClient());
 
function sendNotification(
    Client $client,
    string $title,
    string $body,
    string ...$clientTokens) : void {
 
    $message = new Message();
 
    $message -> setNotification(
        new Notification(
            $title,
            $body
        )
    );
 
    foreach ($clientTokens as $clientToken) {
        $message -> addRecipient(new Device($clientToken));
    }
 
    $client -> send($message);
 
}
 
sendNotification($client, "Hello World", "Test Notification", "FCM-CLIENT-TOKEN-1");

FCM Response Data Handling

the Client::send() The method returns the HTTP response object for the notification request. You can inspect the JSON-encoded response data to determine if your notifications were successfully delivered.

$message = new Message();
$message -> setNotification(new Notification("Test", "Test"));
$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-1"));
$message -> addReceipient(new Device("FCM-CLIENT-TOKEN-USER-2"));
 
$response = $client -> send($message);
$responseData = $response -> json();

The response data array has a structure similar to the following:

{
    "success": 1,
    "failure": 1,
    "results": [
        {
            "message_id": 100
        },
        {
            "error": "InvalidRegistration"
        }
    ]
}

the results array contains an object that represents the delivery status of each of the devices you tried to send to. This will match the order of recipients added to the Message Through the addRecipient() method. The example JSON above indicates that only the first device received the notification. The second delivery failed, so you need to remove the device token from your database.

$recipients = [
    "FCM-CLIENT-TOKEN-USER-1",
    "FCM-CLIENT-TOKEN-USER-2"
];
 
$message = new Message();
$message -> setNotification(new Notification("Test", "Test"));
 
foreach ($recipients as $recipient) {
    $message -> addReceipient(new Device($recipient));
}
 
$response = $client -> send($message);
$responseData = $response -> json();
 
foreach ($responseData["results"] as $i => $result) {
    if (isset($result["error"])) {
        deleteUserFcmToken($recipients[$i]);
    }
}

Adding arbitrary data to notifications

The messages can include arbitrary data that must be communicated to the client application:

$message = new Message();
$message -> setNotification(
    new Notification(
        "Breaking News!",
        "A breaking news story is available."
    )
);
$message -> setData([
    "uri" => "/news/latest-stories"
]);

Client-side code can access this data to perform different actions when a notification is received.

Setting message priorities

FCM supports a message priority system that allows you to request immediate delivery to the destination device. When using high priority mode, FCM tries to wake up idle Android devices to handle the notification, even if background activity is suppressed.

// Indicate a high-priority message
$message -> setPriority("high");

This attribute should be used with care. Sending too many priority messages that don’t result in user interactions will cause your deliveries to lose priority. The mechanism is designed for really important payloads that need to break a device’s battery saver, network throttling, and background activity restrictions.

iOS handles priorities differently. You will get an error if you try to send a high priority message to an iOS device. You can use the values normal either 5the latter indicating a high priority delivery is preferred.

time to live

A Message The time to live (TTL) of the instance determines how long it will remain relevant. FCM will not always be able to send notifications in a timely manner. The target device might be offline or in a battery-saving state. FCM will still try to deliver the notification, but this is not always desirable behavior. Some notifications, such as expiration reminders, may be irrelevant to the user at the time they are received.

Use the setTimeToLive() to define the lifetime of your messages. FCM will stop trying to deliver them once the TTL has expired.

$message = new Message();
$message -> setNotification(
    new Notification(
        "Server rotation scheduled for 12pm",
        "Cancel within the next 10 minutes."
    )
);
$message -> setTimeToLive(600);

Badges on iOS

iOS uses red badges on home screen icons to indicate the number of unread notifications available within the app. You can change the number badge of your app with the setBadge() method in a Notification object:

$message = new Message();
$notification = new Notification(
    "Server rotation scheduled for 12pm",
    "Cancel within the next 10 minutes."
);
$notification -> setBadge(1);
$message -> setNotification($notification);
$message -> setTimeToLive(600);

the Notification The class also has methods for other platform-specific behavior. You can change the notification icon on Android devices (setIcon()), assign a sound to play (setSound()), and use labels (setTag()) to control whether previous notifications are replaced by the new delivery. These properties and the quirks of their platform implementations are described in the FCM API documentation.

conclusion

FCM is an ideal way to start sending push notifications to mobile devices from a PHP backend. Handles interactions with platform-specific push implementations such as APNS and Google Play Services, reducing the amount of code you need to write.

The Firebase Cloud Messaging PHP Library wraps the FCM API in convenient PHP classes and methods. For more advanced control, you can call the FCM API directly through a PHP HTTP library like Guzzle. You may need to take this approach if you need to use notification options that are not exposed by PHP-FCM.