We use "Google firebase" for that. You (or your client) first need a Google firebase account.
In our case Firebase is the connection between a Symfony backend in php and a mobile PWA (Progressive web app) written in another language (for us that is Vue javascript).
It is a service specially for handling messaging. Like they say themselves "Firebase Cloud Messaging | Cross-Platform Messaging"
I'm only going to focus on the Symfony part in my answer.
The other side (the Vue app) will also have to implement firebase but that is another story.
In Symfony install a bundle that connects firebase with Symfony, we took kreait/firebase-bundle
Follow the documentation and you will get this line in your composer.json
"kreait/firebase-bundle": "^2.0"
app/config.yml
kreait_firebase:
projects:
some_client_name_pwa:
credentials: '%kernel.root_dir%/config/google/some-client-name-firebase-adminsdk-123456-some-code.json'
The json file as mentioned in the previous code block is automatically created by doing what this person says: https://stackoverflow.com/a/40799378/5418514
This file then contains the credentials from firebase and some more stuff
htdocs/app/config/google/some-client-name-firebase-adminsdk-123456-some-code.json
{
"type": "service_account",
"project_id": "some-client-name",
"private_key_id": "12345some_id",
"private_key": "-----BEGIN PRIVATE KEY-----\n_some_private_key_\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-123456_some-code@some-client-name.iam.gserviceaccount.com",
"client_id": "12345_some_client_id",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-123456_some-code%40some-client-name.iam.gserviceaccount.com"
}
App\CoreBundle\Service
<?php
namespace App\CoreBundle\Service;
use App\UserBundle\Entity\User;
use Kreait\Firebase\Messaging;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class WebPushNotificationService implements LoggerAwareInterface
{
/**
* @var Messaging
*/
private $messaging;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var LoggerInterface
*/
private $logger;
/**
* WebPushNotificationService constructor.
*
* @param Messaging $messaging
* @param RequestStack $requestStack
*/
public function __construct(Messaging $messaging, RequestStack $requestStack)
{
$this->messaging = $messaging;
$this->requestStack = $requestStack;
}
public function sendMessageToUser(User $user, string $title, string $body)
{
if (!$user->getWebPushToken()) {
return;
}
try {
$icon = $this->requestStack->getCurrentRequest()->getSchemeAndHttpHost() . ($user->getLocale() === 'fr' ? '/images/logo_fr.jpg' : '/images/logo.jpg');
$message = Messaging\CloudMessage::withTarget('token', $user->getWebPushToken())
->withNotification(Messaging\Notification::create($title, $body, $icon));
// Example from https://firebase.google.com/docs/cloud-messaging/admin/send-messages#webpush_specific_fields
$config = Messaging\WebPushConfig::fromArray([
'notification' => [
'title' => $title,
'body' => $body,
'icon' => $icon,
],
]);
$message = $message->withWebPushConfig($config);
$this->messaging->send($message);
} catch (\Throwable $throwable) {
$this->logger->error(sprintf('Error sending webpush notification to user "%s" with error "%s"', $user->getId(), $throwable->getMessage()));
return false;
}
return true;
}
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
Register it as a service:
SomeBundle/Resources/config/services.yml
App\CoreBundle\Service\WebPushNotificationService:
autowire: true
autoconfigure: true
arguments:
$messaging: '@kreait_firebase.some_client_name_pwa.messaging'
calls:
- ['setLogger', ['@monolog.logger']]
In your User object add
/**
* @var string|null
*
* @ORM\Column(type="string", nullable=true)
*/
private $webPushToken;
/**
* @return string|null
*/
public function getWebPushToken(): ?string
{
return $this->webPushToken;
}
/**
* @param string|null $webPushToken
*/
public function setWebPushToken(?string $webPushToken): void
{
$this->webPushToken = $webPushToken;
}
To use it:
$this->webPushNotificationService->sendMessageToUser($recipient, $title, $body);
PS: There is probably some more to be done but this should help you on your way. Remember to also implement firebase into your mobile app. Depending on the language it is written in you should look for documentation for implementing "Google firebase" in that programming language.