Firebase Cloud Messaging via Laravel
Bài đăng này đã không được cập nhật trong 2 năm
I. Giới thiệu
- Sau nhiều lần mình làm về Fcm, mà chẳng thấy bài nào ns đến Laravel với FCM, có thì toàn bảo dùng package này nọ (sad).
- Vậy nên như tiêu đề, bài viết này mình sẽ giới thiệu cách gửi notification sử dụng Firebase và Laravel, có thể
subscribe topic
được nhiềudevice token qua
đó nâng cao hiệu năng gửi notification, (một vấn đề mình đã gặp trong dự án vừa qua), sử dụng queue... - Đã có nhiều bài viết đã hướng dẫn cách
subscribe topic
theo từng device token,subscribe topic
khi vào một action nào đó nhưng ở bài viết này mình sẽ hướng dẫn theo từng case, từng logic trong dự án... khi muốn push vào một thời gian nhất định với lượng device token nhất định.
II. Hướng dẫn cách làm
1. Cách lấy server key
- Có rất nhiều bài viết hướng dẫn tạo app trên firebase và bạn có thể làm theo và lấy key trong tab Cloud Messaging (Project Setting) có dạng
Server key: AAA..xyz
2. Setup trong Laravel
- Tạo một interface NotificationService
<?php
namespace App\Services\Notification;
interface NotificationService
{
public function sendBatchNotification($deviceTokens, $data);
public function sendNotification($data);
public function subscribeTopic($deviceTokens, $topicName);
public function unsubscribeTopic($deviceTokens, $topicName);
}
- Tạo Một FcmService như sau
<?php
namespace App\Services\Notification;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Exception;
class FcmService implements NotificationService
{
/**
* @param $deviceTokens
* @param $data
* @throws GuzzleException
*/
public function sendBatchNotification($deviceTokens, $data = [])
{
self::subscribeTopic($deviceTokens, $data['topicName']);
self::sendNotification($data, $data['topicName']);
self::unsubscribeTopic($deviceTokens, $data['topicName']);
}
/**
* @param $data
* @param $topicName
* @throws GuzzleException
*/
public function sendNotification($data, $topicName = null)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$data = [
'to' => '/topics/' . $topicName,
'notification' => [
'body' => $data['body'] ?? 'Something',
'title' => $data['title'] ?? 'Something',
'image' => $data['image'] ?? null,
],
'data' => [
'url' => $data['url'] ?? null,
'redirect_to' => $data['redirect_to'] ?? null,
],
'apns' => [
'payload' => [
'aps' => [
'mutable-content' => 1,
],
],
'fcm_options' => [
'image' => $data['image'] ?? null,
],
],
];
$this->execute($url, $data);
}
/**
* @param $deviceToken
* @param $topicName
* @throws GuzzleException
*/
public function subscribeTopic($deviceTokens, $topicName = null)
{
$url = 'https://iid.googleapis.com/iid/v1:batchAdd';
$data = [
'to' => '/topics/' . $topicName,
'registration_tokens' => $deviceTokens,
];
$this->execute($url, $data);
}
/**
* @param $deviceToken
* @param $topicName
* @throws GuzzleException
*/
public function unsubscribeTopic($deviceTokens, $topicName = null)
{
$url = 'https://iid.googleapis.com/iid/v1:batchRemove';
$data = [
'to' => '/topics/' . $topicName,
'registration_tokens' => $deviceTokens,
];
$this->execute($url, $data);
}
/**
* @param $url
* @param array $dataPost
* @param string $method
* @return bool
* @throws GuzzleException
*/
private function execute($url, $dataPost = [], $method = 'POST')
{
$result = false;
try {
$client = new Client();
$result = $client->request($method, $url, [
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'key=' . $keyInHere,
],
'json' => $dataPost,
'timeout' => 300,
]);
$result = $result->getStatusCode() == Response::HTTP_OK;
} catch (Exception $e) {
Log::debug($e)
}
return $result;
}
}
- Ý nghĩa từng hàm
-subscribeTopic
: Hàm này thực hiện để subscribe topic trên firebase và thực hiện được với nhiều device token.
-unsubscribeTopic
: Hàm này thực hiện để unsubscribe topic (cancel topic) trên firebase và thực hiện được với nhiều device token.
-sendNotification
: Dựa trên topic name và device token đã đươc đăng ký, hàm này thực hiên gửi notification dựa vào topic đã được gửi qua hàm subscribeTopic
, ý nghĩa của các attrubte
+to: để biết push notification đến topic nafo
+notification: tieu đề và nội dung của notification
+apns (for IOS): các option định sẵn như image chẳng hạn.
+data: thêm các custom attribute.
-sendBatchNotification
: Hàm này sẽ thực hiện tuần tự subscribeTopic -> sendNotification -> unsubscribeTopic.
- Tạo file PushNotificationJob như sau:
<?php
namespace App\Jobs;
use App\Services\Notification\NotificationService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class PushNotificationJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $serviceMethod;
protected $methodParams;
/**
* Notification constructor.
* @param $serviceMethod
* @param $methodParams
* @param string $methodHttp
*/
public function __construct($serviceMethod, $methodParams = [[]])
{
$this->serviceMethod = $serviceMethod;
$this->methodParams = $methodParams;
}
/**
* @param NotificationService $notificationService
*/
public function handle(NotificationService $notificationService)
{
call_user_func_array(
[
$notificationService,
$this->serviceMethod,
],
$this->methodParams
);
}
}
- Giờ thì xem cách nó hoạt động thôi !!!
Giả sử có một bài toán như sau:
Gửi notification đến những device có ngày sinh nhật vào ngày 25-10
(Vơi device token được lưu trong bảng User)
$deviceTokens = User::whereDay('birthday', now()->format('d'))
->whereMonth('birthday', now()->format('m'))
->pluck('device_token')
->toArray();
PushNotificationJob::dispatch('sendBatchNotification', [
$deviceTokens,
[
'topicName' => 'birthday',
'title' => 'Chúc mứng sinh nhật',
'body' => 'Chúc bạn sinh nhật vui vẻ',
'image' => 'https://picsum.photos/536/354',
],
]);
III. Kết thúc
Trên đây là cách gửi push notification được setup trên server sử dụng laravel, mình nghĩ n rất hiệu quả với những project có từng trừng hợp, theo từng rule rõ ràng mà k để bị phí tài nguyên của sản phẩm, Hi vọng có thể giúp ích được cho các bạn trong qua trình phát triển sản phẩm \m/
All rights reserved