إرسال Push Notifications إلى Android وiOS في Laravel باستخدام Firebase Cloud Messaging FCM
تُعتبر الإشعارات الفورية Push Notifications من أهم المكونات في تطبيقات الهواتف الذكية، فهي تسمح للـ Backend بإرسال رسائل وتنبيهات إلى أجهزة المستخدمين حتى عندما لا يكون التطبيق مفتوحاً.
إذا كنت تستخدم Laravel كـ Backend لتطبيق Android أو iOS، فيمكن الاعتماد على Firebase Cloud Messaging - FCM لإرسال الإشعارات إلى التطبيق.
في هذا الدليل سنركز على جانب Laravel، بداية من إعداد Firebase والحصول على بيانات المصادقة، مروراً بتخزين FCM Tokens، وحتى إنشاء Service احترافي لإرسال الإشعارات باستخدام FCM HTTP v1 API.
لن نتطرق بالتفصيل إلى كود استقبال الإشعارات في Flutter أو Android أو iOS؛ فهذا الجزء يقع ضمن مسؤولية تطبيق الهاتف، بينما سيكون تركيزنا هنا على إعداد الـ Backend.
ما هو Firebase Cloud Messaging؟
Firebase Cloud Messaging أو FCM هي خدمة من Google تسمح بإرسال Push Notifications ورسائل Data إلى تطبيقات:
- Android.
- iOS.
- Web.
- منصات أخرى مدعومة بواسطة Firebase.
في السيناريو المعتاد يكون التسلسل بالشكل التالي:
Laravel Backend
│
▼
Firebase Cloud Messaging
│
├────► Android Device
│
├────► iPhone
│
└────► Other DevicesLaravel لا يتصل بالهاتف مباشرة، بل يقوم بإرسال الرسالة إلى FCM، ثم تتولى Firebase عملية إيصالها إلى الجهاز المستهدف.
كيف يعمل النظام؟
بشكل مبسط:
- يقوم تطبيق الهاتف بالتسجيل لدى Firebase.
- يحصل التطبيق على FCM Registration Token خاص بنسخة التطبيق المثبتة على الجهاز.
- يرسل تطبيق الهاتف هذا Token إلى Laravel Backend.
- يقوم Laravel بتخزينه في قاعدة البيانات.
- عندما نريد إرسال إشعار، يرسل Laravel رسالة إلى FCM HTTP v1 API.
- FCM تقوم بإرسال الإشعار إلى الجهاز المقصود.
Mobile App
│
│ FCM Token
▼
Laravel API
│
│ Store Token
▼
Database
Laravel
│
│ HTTP v1
▼
Firebase FCM
│
▼
Mobile DeviceFCM HTTP v1 وليس Legacy API
قد تجد العديد من الشروحات القديمة تستخدم:
https://fcm.googleapis.com/fcm/sendوتضع Header بالشكل:
Authorization: key=SERVER_KEYهذه الطريقة تنتمي إلى Legacy FCM API وليست الطريقة التي ينبغي بناء تطبيق جديد عليها.
الطريقة الحديثة هي:
POST
https://fcm.googleapis.com/v1/projects/{PROJECT_ID}/messages:sendوتستخدم:
Authorization: Bearer ACCESS_TOKENوالـ Access Token يتم إنشاؤه باستخدام Service Account عبر OAuth 2.0.
1. إنشاء مشروع Firebase
توجه إلى:
ثم:
- اضغط على Create a project.
- اختر اسم المشروع.
- أكمل إعداد المشروع.
- أضف تطبيق Android أو iOS الخاص بك إلى المشروع.
من المهم أن يكون تطبيق الهاتف وLaravel يستخدمان نفس Firebase Project المخصص للنظام.
2. الحصول على Firebase Project ID
من Firebase Console توجه إلى:
Project Settings
→ Generalوستجد:
Project IDمثلاً:
my-mobile-app-12345سنحتاج هذه القيمة لإنشاء عنوان HTTP v1 الخاص بإرسال الرسائل:
https://fcm.googleapis.com/v1/projects/my-mobile-app-12345/messages:send3. إنشاء Service Account
بدلاً من Server Key القديم، تستخدم FCM HTTP v1 بيانات اعتماد Service Account.
من Firebase Console انتقل إلى:
Project Settings
→ Service Accountsومن هناك يمكنك إنشاء Private Key بصيغة JSON للحساب الخدمي.
سيكون الملف مشابهاً للبنية التالية:
{
"type": "service_account",
"project_id": "my-project",
"private_key_id": "...",
"private_key": "...",
"client_email": "...",
"client_id": "..."
}4. تخزين Service Account داخل Laravel
يمكن مثلاً إنشاء:
storage/app/firebase/firebase-service-account.jsonثم وضع ملف Service Account بداخله.
لا تضع الملف داخل:
public/لأن أي ملف داخل Public قد يصبح متاحاً عبر الويب إذا أخطئ إعداد الخادم.
5. إعداد ملف .env
أضف Firebase Project ID:
FIREBASE_PROJECT_ID=my-mobile-app-12345ويمكن كذلك تحديد مسار ملف Service Account:
FIREBASE_CREDENTIALS=/full/path/to/firebase-service-account.jsonأو الاحتفاظ به داخل Storage واستخدام المسار من ملف Configuration.
6. إضافة إعدادات Firebase إلى Laravel
داخل:
config/services.phpأضف:
'firebase' => [
'project_id' => env('FIREBASE_PROJECT_ID'),
'credentials' => env(
'FIREBASE_CREDENTIALS',
storage_path('app/firebase/firebase-service-account.json')
),
],بهذه الطريقة لا نحتاج إلى استدعاء env() مباشرة داخل Services أو Controllers.
7. تثبيت Google Auth Library
تحتاج FCM HTTP v1 إلى OAuth 2.0 Access Token.
يمكن استخدام مكتبة Google الرسمية لـ PHP:
composer require google/authهذه المكتبة مسؤولة عن قراءة Service Account وإنشاء Access Token يمكن استخدامه للوصول إلى Firebase Messaging API.
8. ما هو FCM Token؟
عند تثبيت التطبيق وتشغيل Firebase Messaging، يحصل التطبيق على Registration Token يمكن استخدامه لاستهداف نسخة التطبيق على الجهاز.
مثال تقريبي:
fV8D7nPq4R....:APA91b...تطبيق الهاتف هو المسؤول عن الحصول على هذا Token وإرساله إلى Laravel API.
لا يقوم Laravel بإنشاء FCM Token الخاص بالجهاز.
9. لماذا لا يفضل تخزين token داخل users مباشرة؟
أحد الأخطاء الشائعة هو إضافة:
users.fcm_tokenهذا يعمل إذا كان كل مستخدم يمتلك جهازاً واحداً فقط.
لكن في الواقع قد يسجل المستخدم الدخول من:
- هاتف Android.
- iPhone.
- Tablet.
- هاتف إضافي.
وبالتالي قد يمتلك المستخدم عدة FCM Tokens.
لهذا السبب من الأفضل إنشاء جدول منفصل للأجهزة.
10. إنشاء جدول user_devices
نفذ:
php artisan make:model UserDevice -mثم داخل Migration:
Schema::create('user_devices', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
$table->text('fcm_token')->unique();
$table->string('platform')->nullable();
$table->string('device_name')->nullable();
$table->timestamp('last_seen_at')->nullable();
$table->timestamps();
});ثم:
php artisan migrate11. لماذا نستخدم جدول أجهزة منفصلاً؟
يمكن أن تصبح العلاقة:
User
│
├── Android Phone
│ └── FCM Token
│
├── iPhone
│ └── FCM Token
│
└── Tablet
└── FCM Tokenوبالتالي نستطيع إرسال الإشعار إلى جميع أجهزة المستخدم بدلاً من جهاز واحد فقط.
12. إنشاء العلاقة داخل User Model
public function devices()
{
return $this->hasMany(UserDevice::class);
}وداخل:
app/Models/UserDevice.phpنضيف:
class UserDevice extends Model
{
protected $fillable = [
'user_id',
'fcm_token',
'platform',
'device_name',
'last_seen_at',
];
protected function casts(): array
{
return [
'last_seen_at' => 'datetime',
];
}
public function user()
{
return $this->belongsTo(User::class);
}
}13. API لتسجيل FCM Token
يجب أن يقوم تطبيق الهاتف بإرسال Token إلى Laravel بعد تسجيل الدخول أو عند تحديث Token.
مثلاً:
POST /api/device-tokenوالبيانات:
{
"fcm_token": "TOKEN",
"platform": "android",
"device_name": "Samsung S25"
}14. تخزين Token في Laravel
public function storeDeviceToken(Request $request)
{
$validated = $request->validate([
'fcm_token' => [
'required',
'string',
],
'platform' => [
'nullable',
'in:android,ios',
],
'device_name' => [
'nullable',
'string',
'max:255',
],
]);
UserDevice::updateOrCreate(
[
'fcm_token' => $validated['fcm_token'],
],
[
'user_id' => $request->user()->id,
'platform' => $validated['platform'] ?? null,
'device_name' => $validated['device_name'] ?? null,
'last_seen_at' => now(),
]
);
return response()->json([
'message' => 'Device token saved successfully',
]);
}استخدام:
updateOrCreate()يمنع إنشاء نسخ متكررة من Token نفسه.
15. إنشاء Firebase Messaging Service
بدلاً من وضع كود Firebase داخل كل Controller، الأفضل إنشاء Service مستقلة.
أنشئ:
app/Services/FirebaseMessagingService.php16. إنشاء OAuth Access Token
نستخدم Google Auth Library:
use Google\Auth\Credentials\ServiceAccountCredentials;والـ Scope المطلوب لـ Firebase Messaging هو:
https://www.googleapis.com/auth/firebase.messagingثم يمكن إنشاء Access Token:
private function getAccessToken(): string
{
$credentialsPath = config(
'services.firebase.credentials'
);
if (!file_exists($credentialsPath)) {
throw new RuntimeException(
'Firebase service account file not found.'
);
}
$serviceAccount = json_decode(
file_get_contents($credentialsPath),
true,
512,
JSON_THROW_ON_ERROR
);
$credentials = new ServiceAccountCredentials(
[
'https://www.googleapis.com/auth/firebase.messaging'
],
$serviceAccount
);
$token = $credentials->fetchAuthToken();
if (!isset($token['access_token'])) {
throw new RuntimeException(
'Unable to generate Firebase access token.'
);
}
return $token['access_token'];
}17. لماذا لا نخزن Access Token بشكل دائم؟
الـ OAuth Access Token الخاص بـ FCM HTTP v1 قصير العمر.
وهذا أحد الاختلافات الأمنية المهمة عن Server Key القديم.
الـ Service Account يحتفظ بالمفتاح الأساسي، ثم يقوم Backend بالحصول على Access Token مؤقت عند الحاجة.
Service Account
│
▼
OAuth 2.0
│
▼
Short-lived Access Token
│
▼
FCM HTTP v118. إنشاء دالة إرسال Notification
نستخدم Laravel HTTP Client بدلاً من كتابة cURL يدوياً.
use Illuminate\Support\Facades\Http;ثم:
public function sendToToken(
string $token,
string $title,
string $body,
array $data = []
): array {
$accessToken = $this->getAccessToken();
$projectId = config(
'services.firebase.project_id'
);
$url = sprintf(
'https://fcm.googleapis.com/v1/projects/%s/messages:send',
$projectId
);
$data = collect($data)
->mapWithKeys(function ($value, $key) {
return [$key => (string) $value];
})
->all();
$response = Http::withToken($accessToken)
->acceptJson()
->post($url, [
'message' => [
'token' => $token,
'notification' => [
'title' => $title,
'body' => $body,
],
'data' => $data,
'android' => [
'priority' => 'high',
],
'apns' => [
'headers' => [
'apns-priority' => '10',
],
'payload' => [
'aps' => [
'sound' => 'default',
],
],
],
],
]);
$response->throw();
return $response->json();
}19. FirebaseMessagingService كاملاً
<?php
namespace App\Services;
use Google\Auth\Credentials\ServiceAccountCredentials;
use Illuminate\Support\Facades\Http;
use RuntimeException;
class FirebaseMessagingService
{
private function getAccessToken(): string
{
$credentialsPath = config(
'services.firebase.credentials'
);
if (!file_exists($credentialsPath)) {
throw new RuntimeException(
'Firebase service account file not found.'
);
}
$serviceAccount = json_decode(
file_get_contents($credentialsPath),
true,
512,
JSON_THROW_ON_ERROR
);
$credentials = new ServiceAccountCredentials(
[
'https://www.googleapis.com/auth/firebase.messaging'
],
$serviceAccount
);
$token = $credentials->fetchAuthToken();
if (!isset($token['access_token'])) {
throw new RuntimeException(
'Unable to generate Firebase access token.'
);
}
return $token['access_token'];
}
public function sendToToken(
string $token,
string $title,
string $body,
array $data = []
): array {
$accessToken = $this->getAccessToken();
$projectId = config(
'services.firebase.project_id'
);
$url = sprintf(
'https://fcm.googleapis.com/v1/projects/%s/messages:send',
$projectId
);
$data = collect($data)
->mapWithKeys(function ($value, $key) {
return [
$key => (string) $value
];
})
->all();
$response = Http::withToken($accessToken)
->acceptJson()
->timeout(10)
->retry(2, 500)
->post($url, [
'message' => [
'token' => $token,
'notification' => [
'title' => $title,
'body' => $body,
],
'data' => $data,
'android' => [
'priority' => 'high',
],
'apns' => [
'headers' => [
'apns-priority' => '10',
],
'payload' => [
'aps' => [
'sound' => 'default',
],
],
],
],
]);
$response->throw();
return $response->json();
}
}20. ما الفرق بين notification وdata؟
FCM تسمح بإرسال Notification Payload:
'notification' => [
'title' => 'خبر جديد',
'body' => 'تم إضافة مقال جديد',
]وData Payload:
'data' => [
'screen' => 'article',
'article_id' => '150',
]الـ Notification يحتوي عادة على المعلومات التي ستظهر للمستخدم.
أما Data فيحتوي معلومات يستخدمها التطبيق لتنفيذ منطق معين.
مثلاً عند الضغط على الإشعار يمكن لتطبيق الهاتف قراءة:
screen = article
article_id = 150ثم فتح المقال رقم 150.
21. إرسال إشعار إلى مستخدم
داخل Controller يمكن حقن Service:
use App\Services\FirebaseMessagingService;
class NotificationController extends Controller
{
public function send(
Request $request,
FirebaseMessagingService $firebase
) {
$user = User::with('devices')
->findOrFail($request->user_id);
foreach ($user->devices as $device) {
$firebase->sendToToken(
$device->fcm_token,
$request->title,
$request->body,
[
'screen' => 'notifications',
]
);
}
return response()->json([
'message' => 'Notification sent successfully',
]);
}
}22. إرسال إشعار عند إضافة مقال جديد
لنفترض أننا نريد إرسال إشعار بعد إضافة Article.
public function store(
Request $request,
FirebaseMessagingService $firebase
) {
$article = Article::create([
'title_ar' => $request->title_ar,
'text_ar' => $request->text_ar,
]);
UserDevice::query()
->select('id', 'fcm_token')
->chunkById(
500,
function ($devices) use ($firebase, $article) {
foreach ($devices as $device) {
$firebase->sendToToken(
$device->fcm_token,
'مقال جديد',
$article->title_ar,
[
'screen' => 'article',
'article_id' => $article->id,
]
);
}
}
);
return redirect('/admin/article')
->with(
'success',
'تم إضافة المقال بنجاح'
);
}23. لا ترسل آلاف الإشعارات داخل HTTP Request
المثال السابق يشرح المبدأ، لكنه ليس التصميم الأفضل عندما يكون لديك عدد كبير من المستخدمين.
إذا كان لديك مثلاً:
50,000 devicesثم أرسلت الإشعارات داخل Controller، سيبقى HTTP Request يعمل لفترة طويلة وقد ينتهي بـ Timeout.
الحل الصحيح هو استخدام:
Laravel Queues24. إنشاء Job للإشعارات
نفذ:
php artisan make:job SendPushNotificationمثلاً:
class SendPushNotification implements ShouldQueue
{
use Queueable;
public function __construct(
public string $token,
public string $title,
public string $body,
public array $data = []
) {
}
public function handle(
FirebaseMessagingService $firebase
): void {
$firebase->sendToToken(
$this->token,
$this->title,
$this->body,
$this->data
);
}
}ثم بدل الإرسال المباشر:
$firebase->sendToToken(...);استخدم:
SendPushNotification::dispatch(
$device->fcm_token,
'مقال جديد',
$article->title_ar,
[
'screen' => 'article',
'article_id' => $article->id,
]
);25. لماذا Queues مهمة؟
بدلاً من:
User
↓
POST Article
↓
Send 10,000 Notifications
↓
Wait...
↓
HTTP Responseتصبح البنية:
User
↓
POST Article
↓
Save Article
↓
Dispatch Jobs
↓
HTTP Response
Queue Workers
│
├── Send Notification
├── Send Notification
├── Send Notification
└── ...وبذلك لا ينتظر المستخدم انتهاء عملية إرسال جميع الإشعارات.
26. التعامل مع Token غير صالح
FCM Token ليس قيمة دائمة بالضرورة.
قد يصبح Token غير صالح عندما:
- يقوم المستخدم بإزالة التطبيق.
- يتم إعادة تثبيت التطبيق.
- تتغير بيانات Firebase الخاصة بنسخة التطبيق.
- يصبح تسجيل الجهاز قديماً أو منتهي الصلاحية.
لذلك يجب مراقبة رد FCM.
من الأخطاء المهمة:
UNREGISTEREDوالذي يدل على أن التسجيل لم يعد صالحاً.
في هذه الحالة ينبغي حذف Token من قاعدة البيانات وعدم محاولة إرسال إشعارات إليه مستقبلاً.
27. الاحتفاظ بتاريخ آخر تحديث للجهاز
لهذا أضفنا:
last_seen_atإلى جدول الأجهزة.
عندما يرسل التطبيق Token إلى Backend نقوم بتحديث:
'last_seen_at' => now()وهذا يسمح بمعرفة الأجهزة التي ما زالت نشطة وتنظيف registrations القديمة حسب سياسة التطبيق.
28. Token Refresh
لا تفترض أن FCM Token لن يتغير.
يجب أن يكون تطبيق Android أو iOS قادراً على إرسال Token الجديد إلى Laravel عندما تقوم Firebase بتحديث Registration الخاص بنسخة التطبيق.
التدفق الصحيح:
FCM Registration Changed
│
▼
Mobile Application
│
▼
POST New Registration
│
▼
Laravel
│
▼
Update Database29. إرسال إشعار إلى Topic
ليس من الضروري دائماً إرسال رسالة لكل Device Token بشكل منفصل.
تدعم Firebase ما يسمى:
Topicsمثلاً يمكن جعل المستخدمين يشتركون في:
newsثم إرسال:
'message' => [
'topic' => 'news',
'notification' => [
'title' => 'خبر جديد',
'body' => 'تم نشر خبر جديد',
],
]وبذلك تقوم Firebase بتوزيع الرسالة على الأجهزة المشتركة في Topic.
30. متى نستخدم Topic؟
Topics مناسبة لرسائل مثل:
- الأخبار العامة.
- تحديثات السوق.
- العروض العامة.
- التنبيهات المشتركة بين مجموعة كبيرة من المستخدمين.
لكن إذا كان الإشعار يحتوي بيانات خاصة بمستخدم محدد، فيجب استهداف جهاز المستخدم أو مستخدمي النظام وفق صلاحيات التطبيق بدلاً من Topic عام.
31. Android وiOS من نفس Laravel Backend
لا تحتاج لإنشاء Backend منفصل لكل منصة.
نفس FCM HTTP v1 Endpoint يستطيع إرسال رسائل إلى Android وiOS.
Laravel
│
▼
FCM HTTP v1
│
├──── Android
│
└──── iOS
│
▼
APNsبالنسبة إلى iOS، تقوم Firebase بالتكامل مع خدمة Apple Push Notification Service أو APNs بعد إعداد بيانات Apple المناسبة داخل Firebase.
32. إعداد iOS
حتى تستطيع FCM إرسال Push Notifications إلى تطبيق iOS يجب إعداد تكامل APNs داخل Firebase.
عادة يتم ذلك من:
Firebase Console
→ Project Settings
→ Cloud Messaging
→ Apple app configurationومن ثم إضافة بيانات APNs المطلوبة من حساب Apple Developer.
هذه العملية تخص إعداد تطبيق iOS وFirebase أكثر من Laravel؛ Laravel سيستمر بإرسال الرسالة إلى FCM بنفس HTTP v1 API.
33. حماية Firebase Credentials
ملف Service Account يجب اعتباره Secret عالي الحساسية.
لا تقم أبداً بـ:
git add firebase-service-account.jsonولا تضعه داخل:
public/ولا ترسله إلى تطبيق Android أو iOS.
أضف المسار إلى:
.gitignoreمثلاً:
/storage/app/firebase/*.json34. لا تستخدم CURLOPT_SSL_VERIFYPEER = false
بعض الأكواد القديمة تستخدم:
curl_setopt(
$ch,
CURLOPT_SSL_VERIFYPEER,
false
);تعطيل التحقق من TLS Certificate ممارسة غير جيدة أمنياً ولا ينبغي استخدامها كحل عادي في Production.
استخدم Laravel HTTP Client بإعداداته الآمنة الافتراضية، وعالج مشكلة شهادات الخادم إذا كانت موجودة بدلاً من تعطيل التحقق.
35. لا تستخدم dd() بعد إرسال الإشعار
الكود:
dd($response);مفيد فقط أثناء Debugging.
في Production يجب تحليل Response أو تسجيل الخطأ في Logs.
مثلاً:
if ($response->failed()) {
Log::error(
'FCM request failed',
[
'status' => $response->status(),
'response' => $response->json(),
]
);
}36. إضافة Timeout وRetry
إرسال الإشعار يعتمد على خدمة خارجية، وبالتالي قد تحدث مشاكل اتصال مؤقتة.
يمكن استخدام:
Http::withToken($accessToken)
->timeout(10)
->retry(2, 500)
->post(...);وبذلك لا يبقى الاتصال مفتوحاً إلى ما لا نهاية ويمكن إعادة محاولة بعض حالات الفشل المؤقتة.
37. لا تثق ببيانات Notification القادمة من المستخدم
إذا كانت لديك لوحة Admin تسمح بإرسال Notification، قم بعمل Validation.
$validated = $request->validate([
'title' => [
'required',
'string',
'max:255',
],
'body' => [
'required',
'string',
'max:1000',
],
]);ويجب كذلك حماية Endpoint بصلاحية إدارية مناسبة.
38. البنية المقترحة للنظام
Mobile Application
│
│ Registration / Token
▼
Laravel API
│
▼
user_devices
│
▼
Database
Application Event
│
▼
Laravel Controller / Event
│
▼
Queue
│
▼
SendPushNotification Job
│
▼
FirebaseMessagingService
│
▼
OAuth 2.0
│
▼
FCM HTTP v1
│
├────► Android
│
└────► iOS39. الأخطاء الشائعة
استخدام Server Key القديم
استخدم HTTP v1 وOAuth 2.0 بدلاً من Legacy API.
وضع Token واحد داخل users
استخدم جدول Devices إذا كان المستخدم يستطيع تسجيل الدخول من أكثر من جهاز.
عدم تحديث Registration
يجب أن يقوم التطبيق بإرسال التسجيل الحديث إلى Backend عند تغيّره.
عدم حذف Registrations غير الصالحة
تراكم الأجهزة غير النشطة يؤدي إلى إرسال Requests غير مفيدة وتشويه إحصائيات التسليم.
الإرسال إلى آلاف الأجهزة داخل Controller
استخدم Laravel Queues.
وضع Firebase Credentials في Git
Service Account Secret ولا يجب أن يكون جزءاً من Source Code Repository.
تعطيل SSL Verification
لا تستخدم CURLOPT_SSL_VERIFYPEER = false في Production.
استخدام cURL يدوياً دون حاجة
Laravel يحتوي على HTTP Client واضح يدعم Authentication وTimeout وRetries ومعالجة الأخطاء.
40. الخلاصة
إرسال Push Notifications من Laravel إلى Android وiOS يعتمد على ثلاثة أجزاء أساسية:
Mobile Registration
+
Laravel Backend
+
Firebase Cloud Messagingيحصل تطبيق الهاتف على Registration خاص به ويرسله إلى Laravel، ويقوم Laravel بتخزين بيانات الأجهزة، ثم يستخدم FCM HTTP v1 API لإرسال الرسائل إلى Firebase.
وفي التطبيقات الحديثة لا ينبغي الاعتماد على Server Key وLegacy FCM Endpoint، بل يجب استخدام Service Account وOAuth 2.0 للوصول إلى:
https://fcm.googleapis.com/v1/projects/{PROJECT_ID}/messages:sendأما في الأنظمة الحقيقية التي تحتوي عدداً كبيراً من المستخدمين، فيفضل بناء النظام باستخدام:
- جدول منفصل لأجهزة المستخدمين.
- تحديث Registration بشكل مستمر.
- إزالة registrations القديمة وغير الصالحة.
- Laravel Queues للإرسال في الخلفية.
- Firebase Topics عند إرسال الإشعارات العامة.
- Service منفصلة للتعامل مع FCM.
- Laravel HTTP Client بدلاً من cURL اليدوي.
- Service Account وOAuth 2.0 بدلاً من Server Key القديم.
بهذه البنية يصبح نظام الإشعارات أكثر أماناً وقابلية للتوسع والصيانة، ويمكن استخدام نفس Laravel Backend لإدارة Push Notifications لكل من Android وiOS.
اعتقد فيه مشكلة موجوده ولم دورت على مثال اخر لقيت شكل الداتا اللى بتتبعت مختلف $data = [ \"registration_ids\" => $firebaseToken, \"notification\" => [ \"title\" => $request->title, \"body\" => $request->body, ] ]; registration_ids ولم استخدمت طريقة حضرتك وشوفت ال response كان بيبقى to\\n
نعم، ملاحظتك صحيحة، ولكن الكود الذي يحتوي على
registration_idsكان مستخدماً ضمن FCM Legacy API.في الطريقة القديمة كان هناك فرق بين:
to: لإرسال الإشعار إلى جهاز واحد باستخدام Token واحد.registration_ids: لإرسال الإشعار إلى مجموعة من الأجهزة باستخدام مجموعة Tokens.لذلك استخدام
toفي المثال لم يكن خطأ إذا كان الهدف إرسال الإشعار إلى جهاز واحد.أما حالياً فقد تم تحديث المقال للاعتماد على FCM HTTP v1 API، وفي الطريقة الحديثة لم نعد نستخدم
toأوregistration_idsبالشكل القديم، وإنما يتم استهداف الجهاز باستخدامmessage.token.مثال:
أما في حالة الإرسال الجماعي، فيمكن استخدام الطرق الحديثة المناسبة مثل Topics أو آليات الإرسال المتعدد حسب طبيعة التطبيق.
شكراً لك على الملاحظة، وتم تحديث المقال ليتوافق مع الطريقة الحديثة في Firebase.
شرح جميل جزاك الله خيرا اتمنى المزيد من المقالات الشيقة
شكراً جزيلاً لك، وبارك الله فيك.
سعيد جداً أن الشرح كان مفيداً لك، وإن شاء الله سيتم إضافة المزيد من المقالات العملية حول Laravel وواجهات API وربط Laravel بتطبيقات الهواتف والخدمات المختلفة.
حلو مشكور جدا طيب الكلام هادا كيف هيكون مع الويب وكيف هستقبل الاشعارات و ازيد العداد
بالنسبة للويب، الفكرة الأساسية مشابهة لما نقوم به مع تطبيقات Android وiOS، ولكن طريقة استقبال الإشعار تختلف.
في تطبيق الويب يقوم المتصفح بالحصول على FCM Registration Token بعد منح المستخدم صلاحية استقبال الإشعارات، ثم يتم إرسال هذا الـ Token إلى Laravel وتخزينه في قاعدة البيانات.
أما استقبال الإشعارات فيتم باستخدام JavaScript وService Worker، خصوصاً عندما لا تكون صفحة الموقع مفتوحة في الواجهة.
وبالنسبة لعداد الإشعارات، إذا كان المقصود مثلاً إظهار:
فالأفضل عدم الاعتماد على Push Notification نفسها لحساب العدد، وإنما تخزين الإشعارات داخل قاعدة البيانات وتحديد حالة كل إشعار، مثل:
ثم يقوم Laravel بحساب عدد الإشعارات غير المقروءة وإرساله إلى الواجهة.
بالتالي يمكن أن يكون النظام بالشكل التالي:
بهذه الطريقة يبقى العداد صحيحاً ومتزامناً حتى لو قام المستخدم بفتح حسابه من جهاز أو متصفح آخر.