یک کاربر را برای دریافت اعلان‌های فوری مشترک کنید

Matt Gaunt

برای ارسال پیام‌های push، ابتدا باید از کاربر اجازه بگیرید و سپس دستگاه او را در یک سرویس push ثبت نام کنید. این شامل استفاده از API جاوا اسکریپت برای دریافت یک شیء PushSubscription است که سپس آن را به سرور خود ارسال می‌کنید.

رابط برنامه‌نویسی کاربردی جاوا اسکریپت (JavaScript API) این فرآیند را به طور سرراست مدیریت می‌کند. این راهنما کل جریان، از جمله تشخیص ویژگی، درخواست مجوز و مدیریت فرآیند اشتراک را توضیح می‌دهد.

تشخیص ویژگی

ابتدا بررسی کنید که آیا مرورگر از پیام‌رسانی پوش پشتیبانی می‌کند یا خیر. می‌توانید با دو بررسی، پشتیبانی از پوش را بررسی کنید:

  • روی شیء navigator serviceWorker را بررسی کنید.
  • وجود PushManager را روی شیء window بررسی کنید.
if (!('serviceWorker' in navigator)) {
  // Service Worker isn't supported on this browser, disable or hide UI.
  return;
}

if (!('PushManager' in window)) {
  // Push isn't supported on this browser, disable or hide UI.
  return;
}

در حالی که پشتیبانی مرورگرها از هر دو سرویس ورکر و پیام‌رسانی پوش در حال افزایش است، همیشه هر دو ویژگی را شناسایی کرده و به تدریج برنامه خود را بهبود بخشید.

ثبت نام یک کارگر خدماتی

پس از شناسایی ویژگی، می‌دانید که از سرویس ورکرها و پیام‌رسانی پشتیبانی می‌شود. در مرحله بعد، سرویس ورکرهای خود را ثبت کنید.

وقتی یک سرویس ورکر ثبت می‌کنید، به مرورگر محل فایل سرویس ورکر خود را اعلام می‌کنید. این فایل یک فایل جاوا اسکریپت است، اما مرورگر به آن اجازه دسترسی به APIهای سرویس ورکر، از جمله پیام‌رسانی push، را می‌دهد. به طور خاص، مرورگر فایل را در یک محیط سرویس ورکر اجرا می‌کند.

برای ثبت یک سرویس ورکر، تابع navigator.serviceWorker.register() را فراخوانی کنید و مسیر فایل خود را به آن ارسال کنید. برای مثال:

function registerServiceWorker() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      console.log('Service worker successfully registered.');
      return registration;
    })
    .catch(function (err) {
      console.error('Unable to register service worker.', err);
    });
}

این تابع به مرورگر محل فایل سرویس ورکر شما را می‌گوید. در اینجا، فایل سرویس ورکر در /service-worker.js قرار دارد. پس از فراخوانی register() ، مرورگر این مراحل را انجام می‌دهد:

  1. فایل سرویس ورکر را دانلود کنید.

  2. جاوا اسکریپت را اجرا کنید.

  3. اگر فایل به درستی و بدون خطا اجرا شود، promise برگردانده شده توسط register() حل می‌شود. اگر خطایی رخ دهد، promise رد می‌شود.

نکته : اگر register() را رد کرد، در Chrome DevTools کدهای جاوا اسکریپت خود را از نظر غلط املایی یا خطا بررسی کنید.

وقتی register() ‎ حل می‌شود، یک ServiceWorkerRegistration برمی‌گرداند. شما از این ثبت برای دسترسی به PushManager API استفاده می‌کنید.

سازگاری با مرورگرهای API PushManager

Browser Support

  • کروم: ۴۲.
  • لبه: ۱۷.
  • فایرفاکس: ۴۴.
  • سافاری: ۱۶.

Source

درخواست مجوز

پس از ثبت سرویس ورکر و دریافت مجوز، از کاربر اجازه ارسال پیام‌های پوش را دریافت کنید.

API برای دریافت مجوز ساده است. با این حال، API اخیراً از دریافت یک فراخوانی برگشتی به بازگرداندن یک Promise تغییر کرده است . از آنجا که نمی‌توانید تعیین کنید مرورگر کدام نسخه API را پیاده‌سازی می‌کند، باید هر دو نسخه را پیاده‌سازی و مدیریت کنید.

function askPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error("We weren't granted permission.");
    }
  });
}

در کد قبلی، فراخوانی تابع Notification.requestPermission() یک اعلان به کاربر نمایش می‌دهد:

درخواست مجوز در کروم دسکتاپ و موبایل نمایش داده می‌شود.

پس از اینکه کاربر با انتخاب Allow ، Block یا بستن درخواست مجوز، با آن تعامل کرد، نتیجه را به صورت یک رشته دریافت خواهید کرد: 'granted' ، 'default' یا 'denied' .

در کد نمونه، promise برگردانده شده توسط askPermission() در صورت اعطای مجوز، حل می‌شود؛ در غیر این صورت، خطایی صادر می‌کند و promise رد می‌شود.

در مواقعی که کاربر روی دکمه مسدود کردن کلیک می‌کند، موارد حاشیه‌ای را مدیریت کنید. در این صورت، برنامه وب شما نمی‌تواند دوباره از کاربر درخواست اجازه کند. کاربر باید با تغییر وضعیت مجوز برنامه در پنل تنظیمات، آن را به صورت دستی از حالت مسدود خارج کند. به دقت در نظر بگیرید که چه زمانی و چگونه درخواست اجازه کنید، زیرا اگر کاربر روی دکمه مسدود کردن کلیک کند، لغو آن تصمیم آسان نیست.

بیشتر کاربران اگر دلیل درخواست برنامه را بفهمند، اجازه می‌دهند.

این سند در ادامه به چگونگی درخواست مجوز توسط برخی از سایت‌های محبوب می‌پردازد.

با استفاده از PushManager یک کاربر را مشترک کنید

پس از ثبت سرویس ورکر و دریافت مجوز، می‌توانید با فراخوانی registration.pushManager.subscribe() یک کاربر را ثبت نام کنید.

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

وقتی متد subscribe() را فراخوانی می‌کنید، یک شیء options را که شامل پارامترهای الزامی و اختیاری است، ارسال می‌کنید.

این بخش گزینه‌هایی را که می‌توانید از آنها عبور کنید، شرح می‌دهد.

گزینه‌های فقط کاربر قابل مشاهده

وقتی پیام‌های پوش (push messages) برای اولین بار به مرورگرها اضافه شدند، توسعه‌دهندگان در مورد ارسال پیام‌های پوش بدون نمایش اعلان مطمئن نبودند. این معمولاً به عنوان پوش بی‌صدا (silent push) شناخته می‌شود زیرا کاربر نمی‌داند که رویدادی در پس‌زمینه رخ داده است.

نگرانی این بود که توسعه‌دهندگان می‌توانند بدون اطلاع کاربر، موقعیت مکانی او را به طور مداوم ردیابی کنند.

برای جلوگیری از این سناریو و فراهم کردن امکان بررسی بهترین روش پشتیبانی از این ویژگی توسط نویسندگان مشخصات، گزینه userVisibleOnly اضافه شد. ارسال مقدار true یک توافق نمادین با مرورگر است که برنامه وب هر بار که یک پیام push دریافت می‌کند، یک اعلان نمایش دهد (یعنی بدون ارسال بی‌صدا).

شما باید مقدار true را ارسال کنید. اگر کلید userVisibleOnly را وارد نکنید یا false را ارسال کنید، خطای زیر را دریافت خواهید کرد:

Chrome currently only supports the Push API for subscriptions that will result
in user-visible messages. You can indicate this by calling
`pushManager.subscribe({userVisibleOnly: true})` instead. See
[https://goo.gl/yqv4Q4](https://goo.gl/yqv4Q4) for more details.

کروم از Push API فقط برای اشتراک‌هایی که منجر به پیام‌های قابل مشاهده توسط کاربر می‌شوند، پشتیبانی می‌کند. این مورد را با فراخوانی pushManager.subscribe({userVisibleOnly: true}) نشان دهید. برای اطلاعات بیشتر، به https://goo.gl/yqv4Q4 مراجعه کنید.

به نظر می‌رسد که ارسال بی‌صدای فراگیر در کروم پیاده‌سازی نخواهد شد. در عوض، نویسندگان spec در حال بررسی یک API مقرون‌به‌صرفه هستند که به برنامه‌های وب اجازه می‌دهد تعداد مشخصی پیام بی‌صدا را بر اساس میزان استفاده از برنامه وب ارسال کنند.

گزینه applicationServerKey

این سند قبلاً به کلیدهای سرور برنامه اشاره کرده است. یک سرویس ارسال پیام از کلیدهای سرور برنامه برای شناسایی برنامه‌ای که کاربر را مشترک می‌کند و اطمینان از اینکه همان برنامه به آن کاربر پیام می‌دهد، استفاده می‌کند.

کلیدهای سرور برنامه، یک جفت کلید عمومی و خصوصی هستند که مختص برنامه شما می‌باشند. کلید خصوصی را برای برنامه خود مخفی نگه دارید و کلید عمومی را آزادانه به اشتراک بگذارید.

گزینه applicationServerKey که در فراخوانی subscribe() ارسال می‌شود، کلید عمومی برنامه شماست. مرورگر هنگام عضویت کاربر، این کلید را به یک سرویس push ارسال می‌کند که به سرویس push امکان می‌دهد کلید عمومی برنامه شما را به PushSubscription کاربر مرتبط کند.

نمودار زیر این مراحل را نشان می‌دهد.

  1. برنامه وب خود را در مرورگر بارگذاری کنید و با ارسال کلید سرور عمومی برنامه، تابع subscribe() را فراخوانی کنید.
  2. سپس مرورگر یک درخواست شبکه به یک سرویس ارسال می‌کند که یک نقطه پایانی ایجاد می‌کند، این نقطه پایانی را با کلید عمومی برنامه شما مرتبط می‌کند و نقطه پایانی را به مرورگر بازمی‌گرداند.
  3. مرورگر این نقطه پایانی را به PushSubscription اضافه می‌کند، که promise subscribe() آن را برمی‌گرداند.

نموداری که نحوه استفاده از کلید سرور برنامه عمومی در متد `subscribe()` را نشان می‌دهد.

هنگام ارسال پیام فشار، یک هدر مجوز ایجاد کنید که حاوی اطلاعات امضا شده با کلید خصوصی سرور برنامه شما باشد. هنگامی که سرویس فشار درخواستی برای ارسال پیام فشار دریافت می‌کند، این هدر مجوز امضا شده را با جستجوی کلید عمومی مرتبط با نقطه پایانی دریافت کننده درخواست، اعتبارسنجی می‌کند. اگر امضا معتبر باشد، سرویس فشار می‌داند که درخواست از سرور برنامه با کلید خصوصی منطبق ارسال شده است. این یک اقدام امنیتی است که مانع از ارسال پیام توسط دیگران به کاربران برنامه شما می‌شود.

نموداری که نحوه استفاده از کلید خصوصی سرور برنامه هنگام ارسال پیام را نشان می‌دهد.

از نظر فنی، applicationServerKey اختیاری است. با این حال، ساده‌ترین پیاده‌سازی در کروم به آن نیاز دارد و ممکن است سایر مرورگرها نیز در آینده به آن نیاز داشته باشند. در فایرفاکس اختیاری است.

مشخصات VAPID کلید سرور برنامه را تعریف می‌کند. وقتی به کلیدهای سرور برنامه یا کلیدهای VAPID اشاره می‌کنید، به یاد داشته باشید که آنها یکسان هستند.

ایجاد کلیدهای سرور برنامه

شما می‌توانید با مراجعه به web-push-codelab.glitch.me یا با استفاده از خط فرمان web-push برای تولید کلیدها به شرح زیر، مجموعه‌ای عمومی و خصوصی از کلیدهای سرور برنامه ایجاد کنید:

    $ npm install -g web-push
    $ web-push generate-vapid-keys

این کلیدها را فقط یک بار برای برنامه خود ایجاد کنید و مطمئن شوید که کلید خصوصی را خصوصی نگه می‌دارید.

مجوزها و اشتراک()

فراخوانی subscribe() یک عارضه جانبی دارد. اگر برنامه وب شما هنگام فراخوانی subscribe() مجوز نمایش اعلان‌ها را نداشته باشد، مرورگر این مجوزها را برای شما درخواست می‌کند. اگر رابط کاربری شما با این جریان کار می‌کند، این مفید است، اما اگر کنترل بیشتری می‌خواهید (که اکثر توسعه‌دهندگان می‌خواهند)، از API Notification.requestPermission() که قبلاً در این سند مورد بحث قرار گرفته است، استفاده کنید.

مرور کلی اشتراک PushSubscription

شما تابع subscribe() فراخوانی می‌کنید، گزینه‌ها را ارسال می‌کنید و یک promise دریافت می‌کنید که به PushSubscription تبدیل می‌شود. برای مثال:

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

شیء PushSubscription شامل تمام اطلاعات مورد نیاز برای ارسال پیام‌های push به آن کاربر است. اگر محتویات را با استفاده از JSON.stringify() چاپ کنید، موارد زیر را مشاهده خواهید کرد:

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint آدرس اینترنتی سرویس پوش (push) است. برای فعال کردن یک پیام پوش، یک درخواست POST به این آدرس اینترنتی ارسال کنید.

شیء keys شامل مقادیری است که برای رمزگذاری داده‌های پیام ارسال شده با یک پیام push استفاده می‌شوند. (این سند بعداً در مورد رمزگذاری پیام بحث خواهد کرد.)

ارسال اشتراک به سرور شما

بعد از اینکه اشتراک پوش (push) را ایجاد کردید، آن را به سرور خود ارسال کنید. شما نحوه ارسال آن را تعیین می‌کنید، اما نکته این است که از JSON.stringify() برای استخراج تمام داده‌های لازم از شیء اشتراک استفاده کنید. به عنوان یک روش جایگزین، می‌توانید به صورت دستی همان نتیجه را جمع‌آوری کنید، به عنوان مثال:

const subscriptionObject = {
  endpoint: pushSubscription.endpoint,
  keys: {
    p256dh: pushSubscription.getKeys('p256dh'),
    auth: pushSubscription.getKeys('auth'),
  },
};

// The above is the same output as:

const subscriptionObjectToo = JSON.stringify(pushSubscription);

برای ارسال اشتراک از صفحه وب، از موارد زیر استفاده کنید:

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

سرور Node.js این درخواست را دریافت می‌کند و داده‌ها را برای استفاده‌های بعدی در یک پایگاه داده ذخیره می‌کند.

app.post('/api/save-subscription/', function (req, res) {
  if (!isValidSaveRequest(req, res)) {
    return;
  }

  return saveSubscriptionToDatabase(req.body)
    .then(function (subscriptionId) {
      res.setHeader('Content-Type', 'application/json');
      res.send(JSON.stringify({data: {success: true}}));
    })
    .catch(function (err) {
      res.status(500);
      res.setHeader('Content-Type', 'application/json');
      res.send(
        JSON.stringify({
          error: {
            id: 'unable-to-save-subscription',
            message:
              'The subscription was received but we were unable to save it to our database.',
          },
        }),
      );
    });
});

با جزئیات PushSubscription روی سرور خود، می‌توانید در هر زمانی برای کاربر خود پیام ارسال کنید.

برای جلوگیری از انقضا، مرتباً اشتراک خود را تمدید کنید

هنگام اشتراک در اعلان‌های فشاری، اغلب مقدار PushSubscription.expirationTime برابر با null دریافت می‌کنید. در تئوری، این بدان معناست که اشتراک هرگز منقضی نمی‌شود. (در مقابل، DOMHighResTimeStamp زمان دقیق انقضا را نشان می‌دهد.) با این حال، در عمل، مرورگرها معمولاً اجازه می‌دهند اشتراک‌ها منقضی شوند. به عنوان مثال، این اتفاق می‌تواند در صورتی رخ دهد که برای مدت طولانی هیچ اعلان فشاری دریافت نشود، یا اگر مرورگر تشخیص دهد که کاربر از برنامه‌ای که مجوز اعلان فشاری دارد استفاده نمی‌کند. یک الگو برای جلوگیری از این امر، همانطور که قطعه کد زیر نشان می‌دهد، اشتراک مجدد کاربر پس از هر اعلان دریافتی است. این امر مستلزم آن است که شما اعلان‌ها را به اندازه کافی مکرر ارسال کنید تا از انقضای خودکار اشتراک توسط مرورگر جلوگیری شود. شما باید مزایا و معایب نیازهای مشروع اعلان را در مقابل ارسال ناخواسته هرزنامه به کاربر صرفاً برای جلوگیری از انقضای اشتراک، با دقت بسنجید. در نهایت، نباید سعی کنید تلاش‌های مرورگر را برای محافظت از کاربر در برابر اشتراک‌های اعلان فراموش شده، دور بزنید.

/* In the Service Worker. */

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

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

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

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

سوالات متداول

در اینجا چند سوال رایج وجود دارد:

آیا می‌توان سرویس پوشی که یک مرورگر استفاده می‌کند را تغییر داد؟

خیر، مرورگر سرویس push را انتخاب می‌کند. همانطور که در این سند با فراخوانی subscribe() بحث شد، مرورگر درخواست‌های شبکه را به سرویس push ارسال می‌کند تا جزئیاتی را که PushSubscription تشکیل می‌دهند، بازیابی کند.

آیا سرویس‌های پوش مختلف از APIهای متفاوتی استفاده می‌کنند؟

همه سرویس‌های پوش انتظار API یکسانی دارند.

این API رایج که پروتکل Web Push نامیده می‌شود، درخواست شبکه‌ای را که برنامه شما برای ارسال یک پیام Push ارسال می‌کند، توصیف می‌کند.

اگر کاربری را روی دسکتاپش ثبت‌نام می‌کنید، آیا او روی گوشی‌اش هم ثبت‌نام می‌کند؟

خیر. کاربر باید برای دریافت پیام‌های فوری در هر مرورگری که می‌خواهد پیام دریافت کند، ثبت‌نام کند. این کار همچنین مستلزم آن است که کاربر در هر دستگاه مجوز لازم را اعطا کند.

مراحل بعدی

کدلبز