ADN Open CIS
Сообщество программистов Autodesk в СНГ

31/01/2021

ForgeViewer и прогрессивные web-приложения

Цитируя (англ., по-русски статья немного отличается и внимание акцентируется на несколько иные вещи):

Прогрессивное web-приложение (PWA) - тип программного приложения, доставляемого по сети и использующего общие web технологии, включая HTML, CSS и JavaScript. Они предназначены для работы на любых платформах с использованием браузеров, следующих web-стандартам, включая как десктопные, так и мобильные устройства.

Эти приложения обычно используют современные Web API, такие как Service Workers, Push Notifications и IndexedDB. Мы уже писали о том, как Service Worker API может помочь нам реализовать сценарий работы с приложением в оффлайн (перевод статьи есть на нашем сайте) и сегодня мы посмотрим на другие API и посмотрим, что нужно сделать, чтобы наше приложение Forge стало настоящим прогрессивным web приложением. В качестве основы мы возьмём https://github.com/petrbroz/forge-basic-app и превратим его в приложение, которое Вы можете установить на своё iOS или Android устройство, запустив именно как приложение (т.е. Вы не увидите строки адреса или чего-то напоминающего Chrome mobile), которое даже будет уведомлять Вас о том, что преобразование модели сервисом Model Derivative завершено!

Manifest

Прогрессивное web-приложение обязано иметь Web Application Manifest. Это то место, где мы описываем, как должно выглядеть и вести себя приложение после того, как оно будет установлено пользователем, например:

- иконка и подпись

- цвета фона и темы (используются, например, на экране заставки)

- стартовый URL и display mode

В нашем приложении мы добавим новый файл app.webmanifest в папку public (где находятся все статические файлы, используемые приложением). Его содержание:

Код - JavaScript: [Выделить]
  1. {
  2.     "name": "Forge Basic App",
  3.     "short_name": "ForgeApp",
  4.     "description": "Sample application showing the basic usage of Autodesk Forge.",
  5.     "icons": [
  6.         {
  7.             "src": "/logo.png",
  8.             "type": "image/png",
  9.             "sizes": "48x48 72x72 96x96 128x128 256x256"
  10.         }
  11.     ],
  12.     "start_url": "/",
  13.     "display": "fullscreen",
  14.     "theme_color": "#ffa835",
  15.     "background_color": "#ffffff"
  16. }

В файле public/index.html в теге <head> добавим ссылку на созданный manifets:

Код - HTML: [Выделить]
  1. ...
  2.   ...
  3.   <link rel="manifest" href="app.webmanifest">
  4.   ...
  5. </head>
  6. ...

Даже с этим простым обновлением нам уже доступны некоторые преимущества PWA. Если Вы используете HTTPS (поскольку PWA могут быть запущены только в защищенном контексте), и запускаете главную страницу приложения с Вашего смартфона, система запросит установку приложения на Ваше устройство. Установленное приложение будет использовать иконку и подпись, которую мы задали в файле manifest-а, если Вы запустите его, оно будет в "полноэкранном" режиме, т.е. весь UI браузера будет скрыт. Здорово, правда?

Push Notifications

Push API может быть использован для отправки уведомлений Вашему приложению даже в том случае, если оно не открыто в текущий момент.

Примечание: Ваше приложение может использовать уведомления, даже если оно не PWA. Это API также может быть использовано в обычных web-приложениях в браузере.

Отправка push-уведомлений на стороне сервера - это не совсем простая задача, но, к счастью, есть различные поставщики подобных услуг, которые могут помочь с их реализацией, например, Amazon Simple Notification Service или Pusher Beams.

В нашем примере, тем не менее, мы не будем использовать сторонние поставщики услуг, вместо этого воспользуемся NPM модулем -web-push. Этот модуль предоставляет скрипт командной строки, с помощью которого мы сможем создать так называемые VAPID ключи следующим образом:

Код - HTML: [Выделить]
  1. web-push generate-vapid-keys

Серверная часть приложения

Чтобы включить push-уведомления в нашем серверном приложении, нам потребуется сделать следующее:

1. Зарегистрироать ключи VAPID в модуле web-push:

Код - JavaScript: [Выделить]
  1. //...
  2. const webpush = require('web-push');
  3. const { VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY } = process.env;
  4. webpush.setVapidDetails('mailto:your.email@domain.com', VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY);
  5. //...

2. Добавить новый метод API, по которому клиентская часть приложения может подписаться на уведомления (в нашем случае сохраняем все подписки в свойстве приложения "subs"):

Код - JavaScript: [Выделить]
  1. //...
  2. router.post('/push/subscribe', express.json(), async (req, res) => {
  3.     const subscription = req.body;
  4.     const subscriptions = req.app.get('subs') || [];
  5.     subscriptions.push(subscription);
  6.     req.app.set('subs', subscriptions);
  7.     res.status(201).end();
  8. });
  9. //...

3. Рассылаем уведомления при необходимости:

Код - JavaScript: [Выделить]
  1. //...
  2. const subscriptions = req.app.get('subs');
  3. if (subscriptions) {
  4.     const payload = JSON.stringify({ name: 'something', foo: 'bar' });
  5.     for (const subscription of subscriptions) {
  6.         webpush.sendNotification(subscription, payload)
  7.             .catch(error => console.error(error.stack));
  8.     }
  9. }
  10. //...

Клиентская часть приложения

Теперь мы можем обновить наше клиентское приложение так, чтобы оно могло подписаться на уведомления (с согласия пользователя, конечно!), а так же обработать уведомления, отправленные сервером.

Подписка обрабатывается с помощью объекта push manager, который становится доступным после регистрации service worker-а для нашего web-приложения. После вызова метода pushManager.subscribe, в который мы передадим ключ VAPID (преобразованный в Uint8Array из BASE64), браузер запросит у пользователя согласие на получение уведомления. Если пользователь согласился, мы получим объект, который мы можем отправить в метод /push/subscribe:

Примечание: ключ VAPID мы передаем, используя cookie

Код - JavaScript: [Выделить]
  1. //...
  2. if ('serviceWorker' in navigator) {
  3.     const registration = await navigator.serviceWorker.register('/service-worker.js', { scope: '/' });
  4.     setupNotifications(registration.pushManager);
  5. }
  6. //...
  7. async function setupNotifications(pushManager) {
  8.     function urlBase64ToUint8Array(base64String) {
  9.         const padding = '='.repeat((4 - base64String.length % 4) % 4);
  10.         const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
  11.         const rawData = atob(base64);
  12.         const outputArray = new Uint8Array(rawData.length);
  13.         for (let i = 0; i < rawData.length; ++i) {
  14.             outputArray[i] = rawData.charCodeAt(i);
  15.         }
  16.         return outputArray;
  17.     }
  18.     const match = document.cookie.match(/VAPID_PUBLIC_KEY=([\w\d_\+\-\/]+)/);
  19.     if (match) {
  20.         const vapidPublicKey = match[1];
  21.         try {
  22.             const subscription = await pushManager.subscribe({
  23.                 userVisibleOnly: true,
  24.                 applicationServerKey: urlBase64ToUint8Array(vapidPublicKey)
  25.             });
  26.             await fetch('/push/subscribe', {
  27.                 method: 'POST',
  28.                 body: JSON.stringify(subscription),
  29.                 headers: { 'Content-Type': 'application/json' }
  30.             });
  31.         } catch (err) {
  32.             console.error(err);
  33.         }
  34.     }
  35. }
  36. //...

И наконец, мы предлагаем супер-простую реализацию нашего service worker-а, которое будет просто реагировать на любые уведомления со стороны сервера, показывая уведомление как системное:

Код - JavaScript: [Выделить]
  1. self.addEventListener('push', ev => {
  2.     const data = ev.data.json();
  3.     self.registration.showNotification('Translation Complete', {
  4.         body: `Model: ${data.name}, status: ${data.status}`,
  5.         icon: '/logo.png'
  6.     });
  7. });

Вот и всё! Ваше PWA готово принимать уведомления от нашего сервера.

Если Вы хотите посмотреть, как исходное приложение https://github.com/petrbroz/forge-basic-app было преобразовано в PWA, посмотрите ветку experiment/pwa. И если Вы хотите развернуть и запустить приложение самостоятельно, в файле README Вы найдете больше информации о том, как сгенерировать ключи VAPID и передать их в приложение.

 

Источник: https://forge.autodesk.com/blog/forge-progressive-web-apps

Автор перевода: Александр Игнатович
Опубликовано 31.01.2021