الإشعارات الفورية على الويب المفتوح

إذا سألت مجموعة من المطورين عن ميزات الأجهزة المحمولة المفقودة من الويب، فتكون الإشعارات الفورية دائمًا في أعلى القائمة.

تتيح الإشعارات الفورية للمستخدمين الموافقة على تلقّي آخر الأخبار في الوقت المناسب من المواقع الإلكترونية التي يحبونها، كما تتيح لك إعادة جذبهم بفعالية من خلال محتوى مخصّص وجذاب.

اعتبارًا من الإصدار 42 من Chrome، أصبحت واجهتا برمجة التطبيقات Push API وNotification API متاحة للمطوّرين.

تعتمد Push API في Chrome على بعض التقنيات المختلفة، بما في ذلك ملفات بيان تطبيقات الويب وخدمات العمال. في هذه المشاركة، سنلقي نظرة على كلّ من هذه التقنيات، ولكن فقط الحدّ الأدنى لإعداد رسائل الإشعارات الفورية وتشغيلها. للحصول على فهم أفضل لبعض الميزات الأخرى في البيانات وإمكانيات العمل بدون الاتصال بالإنترنت للعاملين في الخدمة، يُرجى الاطّلاع على الروابط أعلاه.

سنلقي أيضًا نظرة على الميزات التي ستتم إضافتها إلى واجهة برمجة التطبيقات في الإصدارات المستقبلية من Chrome، وأخيرًا سنقدّم لك قائمة بالأسئلة الشائعة.

تنفيذ ميزة "الرسائل الفورية" في Chrome

يوضّح هذا القسم كل خطوة يجب إكمالها لتفعيل رسائل الدفع في تطبيق الويب.

تسجيل مشغّل خدمة

يجب توفُّر عامل خدمة لتنفيذ الرسائل الفورية على الويب. ويرجع سبب ذلك إلى أنّه عند تلقّي رسالة فورية، يمكن للمتصفح بدء تشغيل عامل خدمة يعمل في الخلفية بدون فتح صفحة وإرسال حدث كي تتمكّن من تحديد طريقة التعامل مع رسالة الدفع هذه.

في ما يلي مثال على كيفية تسجيل عامل خدمة في تطبيق الويب. عند اكتمال تسجيله بنجاح، نُجري initialiseState()، وسنتناوله قريبًا.

var isPushEnabled = false;



window.addEventListener('load', function() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.addEventListener('click', function() {
    if (isPushEnabled) {
        unsubscribe();
    } else {
        subscribe();
    }
    });

    // Check that service workers are supported, if so, progressively
    // enhance and add push messaging support, otherwise continue without it.
    if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
    .then(initialiseState);
    } else {
    console.warn('Service workers aren\'t supported in this browser.');
    }
});

يشترك معالِج النقر على الزر في الرسائل الفورية أو يُلغي اشتراك المستخدم فيها. isPushEnabled هو متغيّر عام يتتبّع ببساطة ما إذا كان اشتراك الرسائل الفورية مفعّلاً حاليًا أم لا. وسيتم الإشارة إليها في جميع مقتطفات الرموز البرمجية.

بعد ذلك، نتحقّق من توفّر مشغّلات الخدمات قبل تسجيل service-worker.js الملف الذي يتضمّن منطق معالجة رسالة فورية. وهنا نخبر المتصفح ببساطة أن ملف JavaScript هذا هو مشغّل الخدمات لموقعنا.

إعداد الحالة الأولية

مثال على تجربة مستخدم خدمة المراسلة الفورية المفعَّلة وغير المفعَّلة في Chrome

بعد تسجيل الخدمة، علينا إعداد حالة واجهة المستخدم.

سيتوقع المستخدمون واجهة مستخدم بسيطة لتفعيل رسائل الإشعارات الفورية أو إيقافها لموقعك الإلكتروني، وسيتوقعون أن تكون هذه الواجهة محدّثة باستمرار لتتضمّن أي تغييرات تحدث. بعبارة أخرى، إذا فعّل المستخدمون رسائل الإشعارات الفورية لموقعك الإلكتروني، يمكنك الخروج من التطبيق والعودة بعد أسبوع، ومن المفترض أن يُبرز واجهة المستخدم أنّ رسائل الإشعارات الفورية مفعّلة.

يمكنك الاطّلاع على بعض إرشادات تجربة المستخدم في هذا المستند، وسنركّز في هذه المقالة على الجوانب الفنية.

في هذه المرحلة، قد تعتقد أنّ هناك حالتَين فقط للتعامل معهما، مفعّل أو غير مفعّل. ومع ذلك، هناك بعض الحالات الأخرى المتعلّقة بالإشعارات التي يجب أخذها في الاعتبار.

مخطّط بياني يسلّط الضوء على الاعتبارات المختلفة لحالة الدفع في Chrome

هناك عدد من واجهات برمجة التطبيقات التي يجب التحقّق منها قبل تفعيل الزر، و إذا كان كل شيء متوافقًا، يمكننا تفعيل واجهة المستخدم وضبط الحالة الأولية لتحديد ما إذا كان قد تم الاشتراك في خدمة تلقّي الرسائل الفورية أم لا.

بما أنّ معظم عمليات التحقّق هذه تؤدي إلى إيقاف واجهة المستخدم، يجب ضبط الحالة الأولية على "غير مفعّلة". ويساعد ذلك أيضًا في تجنُّب أي التباس في حال حدثت مشكلة في JavaScript في صفحتك، على سبيل المثال، إذا تعذّر تنزيل ملف JS أو أوقف المستخدم JavaScript.

<button class="js-push-button" disabled>
    Enable Push Messages
</button>

باستخدام هذه الحالة الأولية، يمكننا إجراء عمليات التحقّق الموضّحة أعلاه في الأسلوب initialiseState()، أي بعد تسجيل عامل الخدمة.

// Once the service worker is registered set the initial state
function initialiseState() {
    // Are Notifications supported in the service worker?
    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.warn('Notifications aren\'t supported.');
    return;
    }

    // Check the current Notification permission.
    // If its denied, it's a permanent block until the
    // user changes the permission
    if (Notification.permission === 'denied') {
    console.warn('The user has blocked notifications.');
    return;
    }

    // Check if push messaging is supported
    if (!('PushManager' in window)) {
    console.warn('Push messaging isn\'t supported.');
    return;
    }

    // We need the service worker registration to check for a subscription
    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // Do we already have a push message subscription?
    serviceWorkerRegistration.pushManager.getSubscription()
        .then(function(subscription) {
        // Enable any UI which subscribes / unsubscribes from
        // push messages.
        var pushButton = document.querySelector('.js-push-button');
        pushButton.disabled = false;

        if (!subscription) {
            // We aren't subscribed to push, so set UI
            // to allow the user to enable push
            return;
        }

        // Keep your server in sync with the latest subscriptionId
        sendSubscriptionToServer(subscription);

        // Set your UI to show they have subscribed for
        // push messages
        pushButton.textContent = 'Disable Push Messages';
        isPushEnabled = true;
        })
        .catch(function(err) {
        console.warn('Error during getSubscription()', err);
        });
    });
}

في ما يلي نظرة عامة موجزة على هذه الخطوات:

  • نتحقّق من توفّر showNotification في ServiceWorkerRegistration النموذج الأولي. بدون هذا الإذن، لن نتمكّن من عرض إشعار من الخدمة العاملة عند تلقّي رسالة فورية.
  • نتحقّق من قيمة Notification.permission الحالية للتأكّد من أنّها ليست "denied". يعني رفض الإذن أنّه لا يمكنك عرض الإشعارات حتى يغيِّر المستخدم الإذن يدويًا في المتصفّح.
  • للتحقّق مما إذا كانت ميزة المراسلة الفورية متاحة، نتحقّق من توفّر PushManager في عنصر النافذة.
  • أخيرًا، استخدمنا pushManager.getSubscription() للتحقّق مما إذا كان لدينا اشتراك حاليًا أم لا. وفي حال حدوث ذلك، نرسل تفاصيل الاشتراك إلى الخادم لضمان حصولنا على المعلومات الصحيحة وضبط واجهة المستخدم للإشارة إلى ما إذا كانت ميزة "الرسائل الفورية" مفعّلة أم لا. سنطّلع على التفاصيل التي تظهر في عنصر الاشتراك لاحقًا في هذه المقالة.

ننتظر حتى يتم حلّ المشكلة في "navigator.serviceWorker.ready" للتحقّق من توفُّر اشتراك وتفعيل زر الدفع لأنّه لا يمكنك الاشتراك في خدمة إرسال الرسائل الفورية إلا بعد أن يصبح عامل الخدمة نشطًا.

الخطوة التالية هي معالجة الحالات التي يريد فيها المستخدم تفعيل رسائل الإشعارات الفورية، ولكن قبل أن نتمكّن من إجراء ذلك، علينا إعداد مشروع على Google Developers Console وإضافة بعض المَعلمات إلى البيان لكي تتمكّن من استخدام خدمة المراسلة عبر السحابة الإلكترونية من Firebase (FCM)، المعروفة سابقًا باسم "خدمة المراسلة عبر السحابة الإلكترونية من Google" (GCM).

إنشاء مشروع في "وحدة تحكّم مطوّري Firebase"

يستخدم Chrome خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" لمعالجة إرسال الرسائل الفورية وتسليمها، ولكن لاستخدام واجهة برمجة التطبيقات FCM API، يجب إعداد مشروع على Firebase Developer Console.

الخطوات التالية خاصة بمتصفّح Chrome وOpera لنظام التشغيل Android وSamsung Browser التي تستخدم إطار عمل Firebase للرسائل. سنناقش آلية عمل هذه الميزة في المتصفّحات الأخرى لاحقًا في المقالة.

إنشاء مشروع مطوّر جديد على Firebase

في البداية، عليك إنشاء مشروع جديد على https://console.firebase.google.com/ من خلال النقر على "إنشاء مشروع جديد".

لقطة شاشة جديدة لمشروع Firebase

أضف اسم المشروع وأنشئه وسيتم نقلك إلى لوحة معلومات المشروع:

الصفحة الرئيسية لمشروع Firebase

من لوحة البيانات هذه، انقر على الترس بجانب اسم مشروعك في أعلى الزاوية اليسرى وانقر على "إعدادات المشروع".

قائمة إعدادات مشروع Firebase

في صفحة الإعدادات، انقر على علامة التبويب "الرسائل عبر السحابة الإلكترونية".

قائمة &quot;المراسلة عبر السحابة الإلكترونية&quot; في مشروع Firebase

تحتوي هذه الصفحة على مفتاح واجهة برمجة التطبيقات لرسائل الدفع، وسنستخدمه لاحقًا، ومعرّف المرسِل الذي نحتاج إلى وضعه في بيان تطبيق الويب في القسم التالي.

إضافة بيان تطبيق ويب

بالنسبة إلى الإشعارات الفورية، يجب إضافة ملف بيان يتضمّن حقل gcm_sender_id، لإتمام اشتراك الإشعارات الفورية. لا يتطلّب سوى Chrome وOpera لأجهزة Android ومتصفّح Samsung استخدام هذه المَعلمة ليتمكّنوا من استخدام FCM أو GCM.

وتستخدِم هذه المتصفحات مَعلمة gcm_sender_id عند اشتراك جهاز أحد المستخدِمين في ميزة "المراسلة عبر السحابة الإلكترونية من Firebase". وهذا يعني أنّه بإمكان خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" التعرّف على جهاز المستخدم والتأكد من أنّ معرّف المُرسِل يتطابق مع مفتاح واجهة برمجة التطبيقات المقابل وأنّ المستخدم قد سمح لخادمك بإرسال رسائل الدفع إليه.

في ما يلي ملف بيان بسيط للغاية:

{
    "name": "Push Demo",
    "short_name": "Push Demo",
    "icons": [{
        "src": "images/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
        }],
    "start_url": "/index.html?homescreen=1",
    "display": "standalone",
    "gcm_sender_id": "<Your Sender ID Here>"
}

عليك ضبط قيمة gcm_sender_id على معرّف المُرسِل من مشروعك على Firebase.

بعد حفظ ملف البيان في مشروعك (يُعد Manifest.json اسمًا جيدًا)، أشِر إليه من HTML باستخدام العلامة التالية في رأس صفحتك.

<link rel="manifest" href="/manifest.json">

في حال عدم إضافة بيان ويب يتضمّن هذه المَعلمات، ستتلقّى استثناءً عند محاولة اشتراك المستخدم في خدمة إرسال الرسائل الفورية، مع الخطأ "Registration failed - no sender id provided" أو "Registration failed - permission denied".

الاشتراك في ميزة "إرسال رسائل من الخادم"

بعد إعداد البيان، يمكنك العودة إلى JavaScript في مواقعك الإلكترونية.

للاشتراك، عليك استدعاء الطريقة subscribe()‎ في العنصر PushManager، الذي يمكنك الوصول إليه من خلال ServiceWorkerRegistration.

ستطلب هذه الخطوة من المستخدم منح المصدر الإذن لإرسال إشعارات فورية. بدون هذا الإذن، لن تتمكّن من إشتراكٍ ناجح.

إذا تم حلّ الوعد الذي تم إرجاعه بواسطة الطريقة subscribe()‎، سيتم منحك عنصر PushSubscription الذي سيحتوي على نقطة نهاية.

يجب حفظ نقطة النهاية على خادمك لكل مستخدم، لأنّك ستحتاج إليها لإرسال رسائل فورية في تاريخ لاحق.

يشترك المستخدم في خدمة الرسائل الفورية باستخدام الرمز التالي:

function subscribe() {
    // Disable the button so it can't be changed while
    // we process the permission request
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe()
        .then(function(subscription) {
        // The subscription was successful
        isPushEnabled = true;
        pushButton.textContent = 'Disable Push Messages';
        pushButton.disabled = false;

        // TODO: Send the subscription.endpoint to your server
        // and save it to send a push message at a later date
        return sendSubscriptionToServer(subscription);
        })
        .catch(function(e) {
        if (Notification.permission === 'denied') {
            // The user denied the notification permission which
            // means we failed to subscribe and the user will need
            // to manually change the notification permission to
            // subscribe to push messages
            console.warn('Permission for Notifications was denied');
            pushButton.disabled = true;
        } else {
            // A problem occurred with the subscription; common reasons
            // include network errors, and lacking gcm_sender_id and/or
            // gcm_user_visible_only in the manifest.
            console.error('Unable to subscribe to push.', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        }
        });
    });
}

في هذه المرحلة، يكون تطبيق الويب جاهزًا لتلقّي رسالة فورية، ولكن لن يحدث أي تغيُّر إلى أن نضيف مستمعًا لأحداث الدفع إلى ملف الخدمة العاملة.

أداة معالجة حدث الدفع لمشغّل الخدمات

عند تلقّي رسالة دفع (سنتحدث عن كيفية إرسال رسالة دفع في القسم التالي)، سيتم إرسال حدث دفع في الخدمة العاملة، وعند هذه النقطة، ستحتاج إلى عرض إشعار.

self.addEventListener('push', function(event) {
    console.log('Received a push message', event);

    var title = 'Yay a message.';
    var body = 'We have received a push message.';
    var icon = '/images/icon-192x192.png';
    var tag = 'simple-push-demo-notification-tag';

    event.waitUntil(
    self.registration.showNotification(title, {
        body: body,
        icon: icon,
        tag: tag
    })
    );
});

يسجِّل هذا الرمز أداة مراقبة أحداث الإشعارات الفورية ويعرض إشعارًا يحتوي على عنوان ومقتطف نص ورمز وعلامة إشعار مُحدَّدَين مسبقًا. من التفاصيل الدقيقة التي يجب تسليط الضوء عليها في هذا المثال هي طريقة event.waitUntil() . تتلقّى هذه الطريقة وعدًا وتمدّد مدة معالجة الحدث (أو يمكن اعتبارها إبقاء عامل الخدمة قيد التشغيل) إلى أن يتم حلّ الوعد. في هذه الحالة، الوعد الذي تم تمريره إلى event.waitUntil هو الوعد الذي تم إرجاعه من showNotification().

تعمل علامة الإشعار كمعرّف للإشعارات الفريدة. إذا أرسلنا رسالتَي دفع إلى نقطة نهاية التطبيق نفسها، مع تأخير قصير بينهما، وعرضنا الإشعارات بالعلامة نفسها، سيعرض المتصفّح الإشعار الأول وسيحلّ محلّه الإشعار الثاني عند استلام رسالة الدفع.

وإذا كنت تريد عرض إشعارات متعددة في وقت واحد، يمكنك استخدام علامة مختلفة أو عدم استخدام أي علامة على الإطلاق. سنلقي نظرة على مثال أكثر اكتمالاً لعرض إشعار لاحقًا في هذا المنشور. في الوقت الحالي، لنجعل الأمور بسيطة ونرى ما إذا كان إرسال رسالة فورية سيؤدي إلى عرض هذا الإشعار.

إرسال رسالة فورية

لقد اشتركنا في خدمة الرسائل الفورية وأصبح العامل في الخدمة جاهزًا لعرض إشعار، لذا حان وقت إرسال رسالة فورية من خلال خدمة المراسلة عبر السحابة الإلكترونية Firebase (FCM).

لا ينطبق ذلك إلا على المتصفّحات التي تستخدم إطار عمل Firebase للرسائل.

عند إرسال المتغير PushSubscription.endpoint إلى خادمك، تكون نقطة نهاية "المراسلة عبر السحابة الإلكترونية من Firebase" خاصة. يحتوي على مَعلمة في نهاية عنوان URL وهي registration_id.

في ما يلي مثال على نقطة نهاية:

https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

عنوان URL لخدمة FCM هو:

https://fcm.googleapis.com/fcm/send

سيكون registration_id:

APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

ينطبق ذلك على المتصفّحات التي تستخدم "نظام إرسال الرسائل إلى الأجهزة الجوّالة من Google". في المتصفّح العادي، يمكنك ببساطة الحصول على نقطة نهاية ويمكنك الاتصال بنقطة النهاية هذه بطريقة عادية، وسيعمل ذلك بغض النظر عن عنوان URL.

يعني ذلك أنّه عليك التحقّق من أنّ نقطة النهاية هي لخدمة "المراسلة عبر السحابة الإلكترونية من Firebase"، وإذا كانت كذلك، عليك استخراج registration_id. لتنفيذ ذلك في Python، يمكنك إجراء ما يلي:

if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
    endpointParts = endpoint.split('/')
    registrationId = endpointParts[len(endpointParts) - 1]

    endpoint = 'https://fcm.googleapis.com/fcm/send'

بعد الحصول على معرّف التسجيل، يمكنك إجراء مكالمة إلى واجهة برمجة التطبيقات FCM API. يمكنك العثور على المستندات المرجعية حول واجهة برمجة تطبيقات FCM API هنا.

في ما يلي الجوانب الأساسية التي يجب تذكُّرها عند استدعاء FCM:

  • يجب ضبط عنوان Authorization بقيمة key=&lt;YOUR_API_KEY&gt; عند طلب البيانات من واجهة برمجة التطبيقات، حيث يكون &lt;YOUR_API_KEY&gt; هو مفتاح واجهة برمجة التطبيقات من مشروع Firebase.
    • تستخدم خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" مفتاح واجهة برمجة التطبيقات للعثور على معرّف المُرسِل المناسب، والتأكّد من أنّه قد منح المستخدم الإذن لمشروعك، وأخيراً، للتأكّد من أنّ عنوان IP الخاص بالخادم مُدرَج في القائمة المسموح بها لهذا المشروع.
  • يجب استخدام عنوان Content-Type مناسب لـ application/json أو application/x-www-form-urlencoded;charset=UTF-8 استنادًا إلى ما إذا كنت ترسل البيانات على هيئة JSON أو بيانات نموذج.
  • صفيف من registration_ids: هذه هي أرقام تعريف التسجيل التي تريد استخراجها من نقاط النهاية من المستخدمين.

يُرجى الاطّلاع على المستندات حول كيفية إرسال رسائل فورية من خادمك، ولكن لإجراء فحص سريع لعامل الخدمة، يمكنك استخدام cURL لإرسال رسالة فورية إلى المتصفّح.

استبدِل &lt;YOUR_API_KEY&gt; و&lt;YOUR_REGISTRATION_ID&gt; في أمر cURL هذا بقيمتك الخاصة ونفِّذ الأمر من وحدة طرفية.

من المفترض أن ترى إشعارًا مميزًا:

    curl --header "Authorization: key=<YOUR_API_KEY>" --header
    "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
    "{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
مثال على رسالة فورية من Chrome لنظام Android

عند تطوير منطق الخلفية، تذكَّر أنّ رأس Authorization و تنسيق محتوى POST خاصان بنقطة نهاية FCM، لذا عليك رصد الحالات التي تكون فيها نقطة النهاية مخصّصة لخدمة FCM وإضافة الرأس وتنسيق محتوى POST بشكل مشروط. بالنسبة إلى المتصفحات الأخرى (ونأمل أن يتوفّر في Chrome في المستقبل)، ستحتاج إلى تنفيذ Web Push Protocol.

من سلبيات التنفيذ الحالي لواجهة برمجة التطبيقات Push API في Chrome هو أنّه لا يمكنك إرسال أي بيانات باستخدام رسالة فورية. لا، لا شيء. وسبب ذلك هو أنه في أي عملية تنفيذ مستقبلية، سيتعين تشفير بيانات الحمولة على خادمك قبل إرسالها إلى نقطة نهاية رسائل الدفع. بهذه الطريقة، لن تتمكّن نقطة النهاية، مهما كان مقدّم خدمة الإشعارات الفورية، من عرض محتوى الرسالة الفورية بسهولة. ويؤدي ذلك أيضًا إلى الحماية من نقاط الضعف الأخرى، مثل التحقق الضعيف من شهادات HTTPS وهجمات الوسيط بين الخادم وموفّر خدمة الإشعارات الفورية. ومع ذلك، هذا التشفير غير متوافق بعد، لذا عليك تنفيذ عملية جلب للحصول على المعلومات المطلوبة لتعبئة الإشعار.

مثال أكثر اكتمالاً على حدث الإرسال الفوري

الإشعار الذي رأيناه حتى الآن بسيط جدًا، وبالنسبة إلى العيّنات، إنّه ضعيف جدًا في تغطية حالة استخدام في العالم الواقعي.

من الواقعي أنّ معظم المستخدمين سيحتاجون إلى الحصول على بعض المعلومات من الخادم قبل عرض الإشعار. وقد تكون هذه البيانات عبارة عن بيانات لملء عنوان الإشعار والرسالة بشيء محدد، أو الانتقال إلى خطوة أبعد والتخزين المؤقت لبعض الصفحات أو البيانات بحيث عندما ينقر المستخدم على الإشعار، يصبح كل شيء متاحًا على الفور عند فتح المتصفح، حتى إذا لم تكن الشبكة متاحة في ذلك الوقت.

في الرمز البرمجي التالي، نحصل على بعض البيانات من واجهة برمجة التطبيقات، ونحوّل الردّ إلى ملف شخصي، ثم نستخدمه لتعبئة الإشعار.

self.addEventListener('push', function(event) {
    // Since there is no payload data with the first version
    // of push messages, we'll grab some data from
    // an API and use it to populate a notification
    event.waitUntil(
    fetch(SOME_API_ENDPOINT).then(function(response) {
        if (response.status !== 200) {
        // Either show a message to the user explaining the error
        // or enter a generic message and handle the
        // onnotificationclick event to direct the user to a web page
        console.log('Looks like there was a problem. Status Code: ' + response.status);
        throw new Error();
        }

        // Examine the text in the response
        return response.json().then(function(data) {
        if (data.error || !data.notification) {
            console.error('The API returned an error.', data.error);
            throw new Error();
        }

        var title = data.notification.title;
        var message = data.notification.message;
        var icon = data.notification.icon;
        var notificationTag = data.notification.tag;

        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
        });
    }).catch(function(err) {
        console.error('Unable to retrieve data', err);

        var title = 'An error occurred';
        var message = 'We were unable to get the information for this push message';
        var icon = URL_TO_DEFAULT_ICON;
        var notificationTag = 'notification-error';
        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
    })
    );
});

يُرجى العِلم أنّ event.waitUntil() يأخذ وعدًا يؤدي إلى الوعد الذي يعرضه showNotification()، ما يعني أنّ مستمع الأحداث لن يخرج إلى أن يكتمل طلب fetch() غير المتزامن، ويُعرَض الإشعار.

سيظهر لك إشعار حتى في حال حدوث خطأ. ويعود سبب ذلك إلى أنّ Chrome سيعرض إشعاره العام إذا لم نفعل ذلك.

فتح عنوان URL عندما ينقر المستخدم على إشعار

عندما ينقر المستخدم على إشعار، يتم إرسال حدث notificationclick في worker الخدمة. في المعالج، يمكنك اتّخاذ الإجراء المناسب، مثل التركيز على علامة تبويب أو فتح نافذة تتضمّن عنوان URL معيّنًا:

self.addEventListener('notificationclick', function(event) {
    console.log('On notification click: ', event.notification.tag);
    // Android doesn't close the notification when you click on it
    // See: http://crbug.com/463146
    event.notification.close();

    // This looks to see if the current is already open and
    // focuses if it is
    event.waitUntil(
    clients.matchAll({
        type: "window"
    })
    .then(function(clientList) {
        for (var i = 0; i < clientList.length; i++) {
        var client = clientList[i];
        if (client.url == '/' && 'focus' in client)
            return client.focus();
        }
        if (clients.openWindow) {
        return clients.openWindow('/');
        }
    })
    );
});

يفتح هذا المثال المتصفّح على جذر مصدر الموقع الإلكتروني، وذلك من خلال التركيز على علامة تبويب حالية من المصدر نفسه في حال توفّرها، وفتح علامة تبويب جديدة في حال عدم توفّرها.

تتوفّر مشاركة مخصّصة لبعض الإجراءات التي يمكنك تنفيذها باستخدام واجهة برمجة التطبيقات Notification API هنا.

إلغاء اشتراك جهاز أحد المستخدِمين

لقد اشتركت في جهاز أحد المستخدمين وتلقّى رسائل فورية، ولكن كيف يمكنك إلغاء اشتراكه؟

إنّ الخطوات الرئيسية المطلوبة لإلغاء اشتراك جهاز المستخدم هي استدعاء الأسلوب unsubscribe() على عنصر PushSubscription وإزالة نقطة النهاية من خوادمك (لتجنُّب إرسال رسائل فورية تعلم أنّها لن يتم استلامها). التعليمة البرمجية أدناه تفعل هذا بالضبط:

function unsubscribe() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // To unsubscribe from push messaging, you need get the
    // subscription object, which you can call unsubscribe() on.
    serviceWorkerRegistration.pushManager.getSubscription().then(
        function(pushSubscription) {
        // Check we have a subscription to unsubscribe
        if (!pushSubscription) {
            // No subscription object, so set the state
            // to allow the user to subscribe to push
            isPushEnabled = false;
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            return;
        }

        var subscriptionId = pushSubscription.subscriptionId;
        // TODO: Make a request to your server to remove
        // the subscriptionId from your data store so you
        // don't attempt to send them push messages anymore

        // We have a subscription, so call unsubscribe on it
        pushSubscription.unsubscribe().then(function(successful) {
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            isPushEnabled = false;
        }).catch(function(e) {
            // We failed to unsubscribe, this can lead to
            // an unusual state, so may be best to remove
            // the users data from your data store and
            // inform the user that you have done so

            console.log('Unsubscription error: ', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        });
        }).catch(function(e) {
        console.error('Error thrown while unsubscribing from push messaging.', e);
        });
    });
}

إبقاء الاشتراك محدّثًا

قد لا تكون الاشتراكات متزامنة بين "خدمة المراسلة عبر السحابة الإلكترونية من Firebase" وخادمك. تأكَّد من أنّ خادمك يحلِّل نص الاستجابة لطلب POST في واجهة برمجة التطبيقات لـ "المراسلة عبر السحابة الإلكترونية من Firebase"، بحثًا عن نتائج error:NotRegistered وcanonical_id، كما هو موضّح في مستندات "المراسلة عبر السحابة الإلكترونية من Firebase".

قد تتوقف أيضًا مزامنة الاشتراكات بين الخدمة العاملة وخادمك. على سبيل المثال، بعد الاشتراك أو إلغاء الاشتراك بنجاح، قد يمنعك اتصال الشبكة المضطرب من تعديل الخادم، أو قد يبطل أحد المستخدمين إذن الإشعارات، ما يؤدي إلى إلغاء الاشتراك تلقائيًا. يمكنك التعامل مع مثل هذه الحالات من خلال التحقّق من نتيجة serviceWorkerRegistration.pushManager.getSubscription() بشكل دوري (مثل عند تحميل الصفحة) ومزامنتها مع الخادم. ننصحك أيضًا بالاشتراك تلقائيًا مرة أخرى إذا لم يعد لديك اشتراك، وإذا لم يعُد لديك اشتراك، فإذا كان لديك إذن بالوصول إلى "Notification.permission" == 'granted'.

في sendSubscriptionToServer()، عليك التفكير في كيفية معالجة طلبات الشبكة غير الناجحة عند تعديل endpoint. أحد الحلول هو تتبُّع حالة endpoint في ملف تعريف ارتباط لتحديد ما إذا كان خادمك بحاجة إلى أحدث التفاصيل أم لا.

تؤدي جميع الخطوات أعلاه إلى تنفيذ كامل للرسائل الفورية على الويب في Chrome 46. لا تزال هناك ميزات محدّدة ستسهّل الأمور (مثل واجهة برمجة تطبيقات عادية لتشغيل الرسائل الفورية)، ولكن يتيح لك هذا الإصدار بدء إنشاء رسائل فورية في تطبيقات الويب اليوم.

كيفية تصحيح أخطاء تطبيق الويب

أثناء تنفيذ رسائل الإشعارات الفورية، ستظهر الأخطاء في أحد المكانَين التاليَين: صفحتك أو الخدمة العاملة.

يمكن تصحيح الأخطاء في الصفحة باستخدام DevTools. لتصحيح أخطاء العامل المعني بالخدمة، أمامك خياران:

  1. انتقِل إلى chrome://inspect > مهام الخدمة. لا يوفّر هذا العرض معلومات كثيرة غير مهام الخدمة التي تعمل حاليًا.
  2. انتقِل إلى chrome://serviceworker-internals، ويمكنك من هنا الاطّلاع على حالة مهام الخدمة والاطّلاع على الأخطاء، إن وجدت. هذه الصفحة مؤقتة إلى أن تتوفر مجموعة ميزات مشابهة في "أدوات مطوّري البرامج".

ومن أفضل النصائح التي يمكنني تقديمها لأي شخص جديد في مجال تشغيل الخدمات هي الاستفادة من مربّع الاختيار "فتح نافذة أدوات مطوري البرامج وإيقاف تنفيذ JavaScript مؤقتًا عند بدء تشغيل عامل الخدمة لتصحيح الأخطاء". سيؤدي وضع علامة في مربّع الاختيار هذا إلى إضافة نقطة توقّف عند بدء الخدمة العاملة وإيقاف التنفيذ مؤقتًا، ما يتيح لك استئناف نص الخدمة العاملة أو التنقّل فيه والتحقّق مما إذا كنت تواجه أي مشاكل.

لقطة شاشة تعرض مكان مربّع الاختيار &quot;إيقاف التنفيذ مؤقتًا&quot; في serviceworker-internals

إذا بدا أنّ هناك مشكلة بين FCM وحدث الإرسال في worker الخدمة، ليس هناك الكثير مما يمكنك فعله لتصحيح أخطاء المشكلة لأنّه لا توجد طريقة لتحديد ما إذا كان Chrome قد تلقّى أي شيء. عليك التأكّد من أنّه يتم تلقّي استجابة ناجحة من FCM عندما يُجري خادمك طلبًا إلى واجهة برمجة التطبيقات. سيبدو شيئًا مثل:

{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}

لاحِظ الردّ "success": 1. إذا ظهرت لك رسالة خطأ بدلاً من ذلك، يعني ذلك أنّه ثمة مشكلة في رقم تعريف تسجيل FCM وأنّه لا يتم إرسال رسالة الدفع العميقة إلى Chrome.

تصحيح أخطاء مهام الخدمة على متصفّح Chrome لأجهزة Android

في الوقت الحالي، لا يمكن تصحيح أخطاء خدمات Chrome العاملة في الخلفية على أجهزة Android. عليك الانتقال إلى chrome://inspect، والعثور على جهازك والبحث عن عنصر في القائمة يحمل الاسم "Worker pid:...." والذي يحتوي على عنوان URL لعامل الخدمة.

لقطة شاشة تعرض مكان توفّر مهام الخدمة في فحص Chrome

تجربة المستخدم في الإشعارات الفورية

لقد عمل فريق Chrome معًا على إعداد مستند لأفضل الممارسات للإشعارات الفورية لتجربة المستخدم بالإضافة إلى وثيقة يتناول بعض الحالات الهامشية عند العمل مع الإشعارات الفورية.

مستقبل الرسائل الفورية على Chrome وشبكة الإنترنت المفتوحة

يتناول هذا القسم بعض التفاصيل المتعلقة ببعض الأجزاء المحددة في متصفّح Chrome والتي يجب أن تكون على دراية بها حول عملية التنفيذ هذه وكيف ستختلف عن عمليات التنفيذ الأخرى في المتصفِّح.

بروتوكول Web Push ونقاط النهاية

يكمن جمال معيار Push API في أنّه من المفترض أن تكون قادرًا على الوصول إلى نقطة النهاية وتمريرها إلى خادمك وإرسال رسائل فورية من خلال تطبيق بروتوكول Web Push.

‫Web Push Protocol هو معيار جديد يمكن لموفّري خدمات الإشعارات الفورية تنفيذه، ويسمح للّمطوّرين بعدم القلق بشأن موفّر خدمات الإشعارات الفورية. والفكرة هي أنّ هذا يتجنّب الحاجة إلى الاشتراك في مفاتيح واجهة برمجة التطبيقات وإرسال بيانات منسَّقة بشكل خاص، كما هو مطلوب في نظام Google Cloud Messaging.

كان Chrome هو المتصفّح الأول الذي نفَّذ واجهة برمجة التطبيقات Push API، ولا توفّر خدمة "إشعارات Google من خادم الرسائل الفورية" (FCM) دعمًا لبروتوكول Web Push Protocol، وهذا هو السبب في أنّ Chrome يتطلّب استخدام gcm_sender_id وعليك استخدام واجهة برمجة التطبيقات restful API لخدمة FCM.

يتمثّل هدف Chrome في استخدام بروتوكول Web Push مع متصفّح Chrome و"المراسلة عبر السحابة الإلكترونية من Firebase".

إلى ذلك الحين، عليك رصد نقطة النهاية "https://fcm.googleapis.com/fcm/send" ومعالجتها بشكل منفصل عن نقاط النهاية الأخرى، أي تنسيق بيانات الحمولة بطريقة معيّنة وإضافة مفتاح التفويض.

How to Implement the Web Push Protocol?

يعمل Firefox Nightly حاليًا على إتاحة ميزة الإشعارات الفورية، ومن المرجّح أن يكون أول متصفّح يطبّق بروتوكول Web Push.

الأسئلة الشائعة

أين المواصفات؟

https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/

هل يمكنني منع تلقّي إشعارات مكرَّرة إذا كان للحضور على الويب مصادر متعددة أو إذا كان لديّ حضور على الويب وفي التطبيقات الأصلية؟

لا يتوفّر حلّ لهذه المشكلة في الوقت الحالي، ولكن يمكنك متابعة مستوى التقدّم في Chromium.

السيناريو المثالي هو الحصول على نوع من المعرّفات لجهاز المستخدم ثم مطابقة معرّفات الاشتراك في التطبيق الأصلي وتطبيق الويب من جانب الخادم وتحديد التطبيق الذي سيتم إرسال رسالة فورية إليه. يمكنك إجراء ذلك من خلال حجم الشاشة، ونموذج الجهاز، ومشاركة مفتاح تم إنشاؤه بين تطبيق الويب والتطبيق الأصلي، ولكن لكل نهج إيجابيات وسلبيات.

لماذا أحتاج إلى مَعلمة gcm_sender_id؟

هذا الإجراء مطلوب لكي يتمكّن متصفِّح Chrome وOpera لنظام التشغيل Android ومتصفِّح Samsung من استخدام واجهة برمجة التطبيقات لخدمة "المراسلة عبر السحابة الإلكترونية من Firebase". والهدف هو استخدام Web Push Protocol عند الانتهاء من وضع المعيار وتوافقه مع FCM.

لمَ لا يتم استخدام Web Sockets أو Server-Sent Events (الأحداث المُرسَلة من الخادم) (EventSource)؟

تتمثل ميزة استخدام الرسائل الفورية في أنّه حتى إذا كانت صفحتك مغلقة، سيتم تنشيط عامل الخدمة وسيكون بإمكانه عرض إشعار. يتم إغلاق اتصال Web Sockets وEventSource عند إغلاق الصفحة أو المتصفّح.

ماذا لو لم أكن بحاجة إلى إرسال الأحداث في الخلفية؟

إذا لم تكن بحاجة إلى إرسال البيانات في الخلفية، فإنّ Web Sockets هي خيار رائع.

متى يمكنني استخدام الإشعارات الفورية بدون عرض إشعارات (أي الإشعارات الفورية الصامتة في الخلفية)؟

لا يوجد مخطّط زمني لموعد توفُّر هذه الميزة حتى الآن، ولكن هناك نية لتنفيذ المزامنة في الخلفية، وعلى الرغم من أنّه لم يتم تحديد ذلك أو تحديد مواصفاتها، هناك بعض المناقشات حول تفعيل ميزة "إرسال بدون صوت" مع مزامنة الخلفية.

لماذا يتطلّب هذا الإجراء استخدام بروتوكول HTTPS؟ كيف يمكنني حلّ هذه المشكلة أثناء مرحلة التطوير؟

تتطلّب مشغّلو الخدمات مصادر آمنة لضمان أنّ نص مشغّل الخدمة يأتي من المصدر المقصود ولم يتم إنشاؤه من خلال هجوم من نوع "الرجل في المنتصف" . ويعني ذلك حاليًا استخدام HTTPS على المواقع الإلكترونية المنشورة، على الرغم من أنّ localhost سيعمل أثناء التطوير.

كيف يبدو دعم المتصفح؟

يتيح Chrome هذه الميزة في إصداره الثابت، وتعمل Mozilla على طرحها في الإصدار Firefox Nightly. يمكنك الاطّلاع على قسم تنفيذ الخطأ في واجهة برمجة التطبيقات Push API للحصول على مزيد من المعلومات، ويمكنك تتبُّع تنفيذ الإشعارات هنا.

هل يمكنني إزالة إشعار بعد فترة زمنية معيّنة؟

لا يمكن حاليًا الحصول على هذه القائمة، ولكننا نخطط لإتاحة ذلك. إذا كان لديك حالة استخدام لضبط مهلة انتهاء صلاحية للإشعار بعد عرضه، يُرجى إعلامنا بها. لإضافة تعليق، يُرجى النقر على "إضافة تعليق"، وسنعيد توجيهه إلى فريق Chrome.

إذا كنت بحاجة فقط إلى إيقاف إرسال إشعار فوري إلى المستخدم بعد فترة زمنية معيّنة، ولا يهمّك مدة بقاء الإشعار مرئيًا، يمكنك استخدام مَعلمة وقت انتهاء الصلاحية (ttl) في "المراسلة عبر السحابة الإلكترونية من Firebase"، مزيد من المعلومات هنا.

ما هي قيود إرسال الرسائل الفورية في Chrome؟

هناك بعض القيود الموضّحة في هذه المشاركة:

  • يؤدي استخدام Chrome لخدمة CCM كخدمة دفع إلى فرض عدد من متطلبات الملكية الخاصة. نحن نعمل معًا لمعرفة ما إذا كان بإمكاننا رفع بعض هذه القيود في المستقبل.
  • يجب عرض إشعار عند تلقّي رسالة فورية.
  • يُرجى العِلم أنّه في حال عدم تشغيل متصفّح Chrome على الكمبيوتر المكتبي، لن يتم تلقّي الرسائل الفورية. يختلف ذلك عن نظام التشغيل ChromeOS وAndroid حيث سيتم دائمًا استلام رسائل الدفع.

هل يجب استخدام Permissions API؟

تم تنفيذ واجهة برمجة التطبيقات Permission API في Chrome، ولكنّها لن تكون متاحة بالضرورة في جميع المتصفّحات. مزيد من المعلومات

لماذا لا يفتح Chrome علامة التبويب السابقة عند النقر على إشعار؟

لا تؤثّر هذه المشكلة إلا في الصفحات التي لا يتحكّم فيها حاليًا مشغّل الخدمات. يمكنك الاطّلاع على المزيد من المعلومات هنا.

ماذا يحدث إذا كان الإشعار قديمًا في الوقت الذي تلقّى فيه جهاز المستخدم الإشعار الفوري؟

عليك دائمًا إظهار إشعار عندما تتلقّى رسالة فورية. في السيناريو الذي تريد فيه إرسال إشعار ولكنّه يكون مفيدًا فقط لمدة زمنية معيّنة، يمكنك استخدام المَعلمة time_to_live في CCM كي لا تُرسِل خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" رسالة الإشعار الفوري إذا تجاوزت وقت انتهاء الصلاحية.

يمكنك الاطّلاع على مزيد من التفاصيل هنا.

ماذا يحدث إذا أرسلتُ 10 رسائل دفع ولكن أريد أن يتلقّى الجهاز رسالة واحدة فقط؟

تتضمّن خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" مَعلمة "تصغير_مفتاح" يمكنك استخدامها لتطلب من خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" استبدال أي رسالة معلّقة تحتوي على "مفتاح_تصغير" نفسه بالرسالة الجديدة.

يمكنك الاطّلاع على مزيد من التفاصيل هنا.