مقدمة
يُرسِل Atelerix الإشعارات باستخدام الخدمة الأصلية لكل منصة — Firebase Cloud Messaging (FCM) على Android، وApple Push Notification service (APNs) مباشرةً على iOS (بدون الحاجة إلى Firebase)، وWeb Push القياسي (VAPID) على Flutter Web (بدون الحاجة إلى Firebase أو OneSignal هناك أيضاً). حزمة واحدة، وAPI واحد هوAtelerix.notifications.*، للمنصات الثلاث. بعد إتمام تثبيت Flutter، اتّبع خطوات كل منصة أدناه لتفعيل تسليم الإشعارات في تطبيقك.
تأكّد من تهيئة الـ SDK عبر
Atelerix.init() قبل إعداد الإشعارات.إعداد Android
لا حاجة لأي إعداد إضافي في الـ SDK على Android. كل ما تحتاجه هو إضافة ملفgoogle-services.json الخاص بـ Firebase إلى المشروع.
- أنشئ أو افتح تطبيقك في Firebase Console.
- نزّل ملف
google-services.jsonلتطبيق Android الخاص بك. - ارفع الملف إلى لوحة تحكم Atelerix.
إعداد iOS
تحتاج إلى حساب Apple Developer نشط لإرسال إشعارات على iOS.إعداد مصادقة APNs
- في بوابة Apple Developer، اذهب إلى Certificates, Identifiers & Profiles → Keys.
- أنشئ مفتاحاً جديداً مع تفعيل Apple Push Notifications service (APNs).
- نزّل مفتاح المصادقة
.p8ولاحظ Key ID. يمكنك تنزيل المفتاح مرة واحدة فقط. - ارفع ملف
.p8إلى لوحة تحكم Atelerix.
إعداد AppDelegate
أضف الاستدعاءات التالية إلىios/Runner/AppDelegate.swift:
AppDelegate.swift
إعداد الويب
Flutter Web مدعوم من نفس حزمةatelerix — بدون JS SDK منفصل، وبدون مشروع Firebase. خطوتان فقط بدلاً من إعداد Xcode:
- انسخ عامل الخدمة (service worker). لا يمكن لحزمة Flutter إضافة ملف إلى مجلد
web/في تطبيقك تلقائياً — انسخ ملفweb_sw/atelerix-sw.jsمن حزمةatelerixإلىweb/atelerix-sw.jsفي تطبيقك، بحيث يُقدَّم من جذر موقعك (مثال:https://yoursite.com/atelerix-sw.js). - أنشئ مفتاح Web Push من لوحة التحكم: الإشعارات ← الإعدادات ← Web Push ← إنشاء المفاتيح. نقرة واحدة — ينشئ Atelerix زوج مفاتيح VAPID ويخزّنه لك؛ لا حاجة لنسخ أي شيء في كودك.
على الويب، تفعل
requestPermissions() أكثر مما تفعله على الجوال — راجع الفروقات بين المنصات على الويب أدناه.إعداد Huawei
قريباً دعم إشعارات Huawei غير متوفر بعد. تابعنا قريباً للحصول على تعليمات الإعداد.إعدادات لوحة التحكم
بعد رفع ملفgoogle-services.json (لـ Android) و/أو مفتاح .p8 (لـ iOS)، أو إنشاء زوج مفاتيح Web Push، من تبويب الإشعارات ← الإعدادات في لوحة تحكم مشروعك، تظهر شارة تم الإعداد (Configured) على بطاقة تلك المنصة مع بيانات الاعتماد التي تحملها — يمكنك الضغط عليها مجدداً في أي وقت لمراجعتها أو استبدالها.
كود Flutter
جميع دوال الإشعارات موجودة علىAtelerix.notifications، وتتطلّب أن يكون await Atelerix.notifications.init() قد اكتمل تنفيذه أولاً — يتم التسجيل مع APNs/FCM تلقائياً كجزء من init()، لذا لا حاجة لاستدعاء “تسجيل” منفصل في السير الطبيعي للعمل.
main.dart
setOnNotificationTapped في مكان لديه وصول إلى التنقّل (navigation) — مثل navigatorKey عام — لأن الضغط على إشعار يعني غالباً الانتقال إلى شاشة محددة بناءً على payload.metadata، وليس مجرد تسجيله في السجلّات.
البيانات (Payload) المُستلَمة مع الإشعار
يستقبل كل منsetOnNotificationReceived وsetOnNotificationTapped كائناً من نوع AtelerixNotificationPayload — بنفس الشكل على iOS وAndroid والويب، بغضّ النظر عن اختلاف طريقة تسليم كل منصة للإشعار الأصلي:
يصل الضغط (tap) بشكل موثوق حتى لو كان هو ما فتح التطبيق من حالة إغلاق كامل —
سجّل
setOnNotificationTapped مباشرة بعد Atelerix.notifications.init()،
وأي ضغط حدث قبل انتهاء تشغيل التطبيق يُعاد تشغيله تلقائياً بمجرد تسجيل الدالة.معرّفات الجهاز: getDeviceId() مقابل getDeviceToken()
يتشابه هذان الاسمان لكنهما يخدمان غرضين مختلفين — استخدم المناسب حسب ما تفعله:
null حتى يكتمل التسجيل، وهو ما يتولّاه Atelerix.notifications.init() تلقائياً — لا حاجة لاستدعاء منفصل.
إرسال صوت مخصّص
اضبطsound عند إرسال إشعار — من تبويب إرسال إشعار في لوحة التحكم، أو معامل sound في REST API — لتشغيل ملف صوت مُرفق بدلاً من صوت الجهاز الافتراضي:
- يجب أن يكون الملف موجوداً بالفعل داخل مشروع تطبيقك — يمرّر Atelerix اسم الملف فقط، ولا يستضيف أو يرفع ملفات الصوت.
- iOS: مرّر اسم الملف مع امتداده، مثل
sound.mp3(مدعوم أيضاً.wav/.caf). - Android: مرّر اسم الملف بدون امتداد، بحيث يطابق ملفاً تحت
res/raw/(مثال:soundلملف عندres/raw/sound.mp3). الصيغ المدعومة:.wav،.mp3،.ogg. - الويب: غير مدعوم — لا توفّر واجهة Web Notifications طريقة موحّدة عبر المتصفحات لتحديد صوت مخصّص، لذا يُتجاهَل هذا المعامل بالنسبة لمستلمي الويب.
على Android، يُثبَّت الصوت أول مرة يُستخدم فيها على جهاز معيّن — يُثبّت النظام
صوت قناة الإشعارات (notification channel) عند إنشائها ولا يسمح بتغييره لاحقاً.
إرسال قيمة
sound مختلفة لاحقاً يُنشئ قناة جديدة بدلاً من تحديث القناة
القديمة؛ هذا سلوك متوقّع من Android، وليس خطأً.إرسال بيانات وصفية (Metadata)
أرفق بيانات مخصّصة عبرmetadata (كائن JSON) عند الإرسال — من تبويب إرسال إشعار في لوحة التحكم، أو معامل metadata في REST API. تصل هذه البيانات إلى الجهاز داخل payload.metadata:
إرسال صورة
اضبطimageUrl عند إرسال إشعار — من تبويب إرسال إشعار في لوحة التحكم، أو معامل imageUrl في REST API — لعرض صورة غنية في الإشعار. بخلاف sound، هذا رابط https:// عادي وليس ملفاً مُرفقاً — يقوم Atelerix بتنزيله نيابةً عنك.
- Android: يعمل تلقائياً، بدون إعداد إضافي. تُعرَض الصورة كإشعار من نوع
BigPictureStyle. - الويب: يعمل تلقائياً أيضاً، بدون إعداد إضافي — يعرضها عامل الخدمة (service worker) مباشرة كأيقونة/صورة الإشعار.
- iOS: يتطلّب أن يملك تطبيقك Notification Service Extension — لا تملك APNs حقل “صورة” أصلياً، لذا يحتاج النظام إلى امتداد صغير لتنزيل الصورة وإرفاقها قبل عرض الإشعار. هذه خطوة إعداد لمرة واحدة لكل تطبيق:
- في Xcode: File → New → Target… → Notification Service Extension. سمِّه (مثلاً
NotificationServiceExtension). - استبدل ملف
NotificationService.swiftالمُولَّد بالملف الموجود في حزمةatelerixعندios/NotificationServiceExtension/NotificationService.swift. - ابنِ التطبيق وشغّله — لا حاجة لأي إعداد آخر. يضبط الباك إند تلقائياً علم
mutable-contentالخاص بـ APNs كلما حمل الإشعار قيمةimageUrl، وهذا ما يُشغّل الامتداد.
- في Xcode: File → New → Target… → Notification Service Extension. سمِّه (مثلاً
إذا لم يكن امتداد iOS مُعدّاً، يُتجاهَل
imageUrl بصمت على iOS — يظهر الإشعار
بشكل طبيعي بدون صورة، ولا يفشل الإرسال. Android غير متأثر في كلتا الحالتين.payload.imageUrl (في setOnNotificationReceived/setOnNotificationTapped) إن أردت عرضها في شريط إشعار مخصّص داخل التطبيق، إضافة إلى عرضها الأصلي من النظام.
الفروقات بين المنصات على الويب
يستخدم Flutter Web نفس استدعاءاتAtelerix.notifications.* المستخدمة على الجوال، مع بعض الفروقات الحقيقية التي يجدر معرفتها بدلاً من مفاجأتك بها:
- تفعل
requestPermissions()أكثر على الويب. على الجوال، يحدث تسجيل الدفع (push) تلقائياً داخلinit()، وتُعنىrequestPermissions()فقط بإذن الإشعارات المرئية. لا يمكن للمتصفح الاشتراك في Push قبل منح الإذن، لذا على الويب، تقومrequestPermissions()أيضاً بتسجيل اشتراك الدفع الخاص بعامل الخدمة لدى الباك إند بمجرد سماح المستخدم — نفس استدعاء الدالة، لكنه يؤدي مهمّتين. - تُرجع
getSenderId()القيمةnullعلى الويب — فهي مفهوم خاص بـ Android/FCM فقط (يستخدم Web Push بروتوكول VAPID، وليس Firebase). - تُرجع
getDeviceToken()أيضاً القيمةnullعلى الويب — فكائنPushSubscriptionالخاص بالمتصفح ليس رمزاً واحداً معتماً بنفس طريقة APNs/FCM، فلا يوجد ما يستحق إرجاعه. استخدمgetDeviceId()على كل منصة بدلاً منه. - الصوت المخصّص غير مدعوم — راجع إرسال صوت مخصّص أعلاه.
- دعم المتصفحات: Chrome وFirefox وEdge بشكل كامل؛ يتطلّب Safari إصدار macOS 13+ أو iOS 16.4+ — الإصدارات الأقدم من Safari لا تدعم Web Push القياسي إطلاقاً.
المواضيع (Topics)
بدلاً من استهداف رموز أجهزة محددة، يمكن للجهاز الاشتراك في موضوع (topic) باسم معيّن — أرسِل إشعاراً واحداً إلى الموضوع ليصل لكل مشترك فيه. لا حاجة لإنشاء الموضوع مسبقاً؛ يُنشأ تلقائياً أول مرة يشترك فيها أي جهاز. يمكنك أيضاً عرض المواضيع وإنشاءها وحذفها من تبويب الإشعارات ← المواضيع في لوحة التحكم.sendByTopic: true.