What is pwa?
Прогрессивное веб-приложение, или PWA для краткости, — это новый способ улучшить работу веб-приложения, предоставляя пользователям возможность работы с собственными приложениями.
PWA может получить опыт нативных приложений, не ссылаясь на конкретную технологию, а применяя некоторые новые технологии для ее улучшения, что значительно улучшило безопасность, производительность и опыт. PWA по сути является веб-приложением. Некоторые новые технологии также имеют некоторые функции собственного приложения и имеют преимущества как веб-приложения, так и собственного приложения.
Технологическая зависимость:
- Service Worker
- Веб-хранилище (IndexedDB, Кэши)
- Fetch
- Promises
PWA advantages
Приложение PWA должно быть:
- обнаруживаемый, может быть идентифицирован как приложение, легко найти через поисковые системы
- устанавливаемый устанавливаемый, доступен для мобильных устройств, добавляется на главный экран пользователя
- Доступно для ссылок Доступно через URL-адрес, не требует сложной установки
- независимый от сети может работать в автономном режиме или в низкоскоростной сетевой среде
- Прогрессивное прогрессивное улучшение подходит для всех пользователей, поддерживаемые браузеры могут работать лучше, доступ к неподдерживаемым браузерам не будет затронут.
- повторное вовлечение Повторное вовлечение Упростите взаимодействие пользователей с помощью напоминаний
- отзывчивый для любого типа устройства
- безопасный Механизм доставки контента предотвращает отслеживание и гарантирует, что контент не будет подделан
Progressive web app advantages. To find out how to implement PWAs, consult the guides listed in the below section.
прогрессивный
Подчеркнуто, что он является постепенным, и процесс реновации может осуществляться постепенно, чтобы снизить стоимость реновации сайта.Степень поддержки новых технологий не является полной, и она эволюционирует постепенно с новыми технологиями. PWA включает в себя оптимизацию с точки зрения безопасности, производительности и опыта, и можно рассмотреть следующие шаги:
- Первым шагом должна быть безопасность, и сделать весь сайт HTTPS, потому что это основа PWA, без HTTPS нет Service Worker
- Вторым шагом должен быть Service Worker, чтобы улучшить базовую производительность, предоставить статические файлы в автономном режиме и улучшить работу пользователя с первого экрана.
- Третий шаг, манифест приложения, этот шаг можно выполнить одновременно со вторым.
- Позже рассмотрите другие функции, отправку сообщений в автономном режиме и т. д.
Уровень поддержки/покрытия
Service Worker
Service Worker, прокси-сервер между браузером и сетью, решает проблему кэширования ресурсов страницы и правильной работы в автономном режиме. Независимо от текущего процесса веб-страницы, он имеет собственный независимый рабочий контекст и не имеет доступа к модели DOM. В отличие от традиционных API, он неблокирует и возвращает результаты, когда они готовы, на основе методов обещаний. Это не только возможность работы в автономном режиме, но и такие функции, как уведомление о сообщениях и добавление значков на рабочий стол.
Предварительные условия
- HTTPS, поскольку для Service Worker требуется среда HTTPS, мы можем изучить отладку с помощью GitHub Page. Общий браузер позволяет хосту Worker, когда Host является Localhost.
- Механизм кэширования Service Worker зависит отCache APIосуществленный
- полагатьсяHTML5 fetch API
- полагатьсяPromiseвыполнить
Lifecycle
A more detailed introduction to The Service Worker Lifecycle
A service worker goes through three steps in its lifecycle:
- Регистрация
- Установка
- Активация
1. Регистрация
Перед установкой Server Worker его необходимо зарегистрировать в JavaScript-коде основного процесса.Регистрация должна сообщить браузеру, какой файл Service Worker находится, после чего в фоновом режиме Service Worker начинает устанавливаться и активироваться.
Регистрационный код можно разместить в html файле
<script></script>
теги или по отдельностиmain.js
Файл импортируется в html-файл.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
console.log('Registration successful, scope is:', registration.scope);
})
.catch(function(error) {
console.log('Service worker registration failed, error:', error);
});
}
В коде сначала проверьте, поддерживает ли браузер Service Worker, и если да, используйтеnavigator.serviceWorker.register
Регистрация, в случае успеха, будет в промисе.then
иди внутрьregistration
.
Файл service-worker.js — это файл, в котором мы хотим написать функцию Service Worker.
При регистрации вы также можете указать необязательный параметр scope, который представляет собой область, к которой Service Worker может получить доступ, или каталог.
navigator.serviceWorker.register('/service-worker.js', {
scope: '/app/'
});
Область действия, указанная в коде,/app/
, что означает, что путь, которым может управлять Service Workder, подобенapp
/app/home/
/app/abbout/
и т. д. внутренние каталоги без возможности доступа/
'/ изображения' и т. д./app
Еще раз на пути слоя.
Если Service Worker уже установлен, повторная регистрация вернет текущий активный объект регистрации.
Браузер Chrome хорошо поддерживает функцию отладки Service Worker, которую можно ввести в браузере.chrome://inspect/#service-workers
Проверьте, прошла ли регистрация успешно.
Или просмотреть его в опции приложения консоли.
2. Установка
Событие установки привязано к файлу Service Worker.При успешной установке будет запущено событие установки.
Как правило, мы будем обрабатывать кеш в событии установки, используя ранее упомянутыйCahce API
, который является глобальным объектом на обслуживающем работнике[5], который может кэшировать соответствующие ресурсы сети и генерировать ключи в соответствии с их запросами. Этот API работает аналогично стандартному кешу браузера, но только для своей области. Кэш будет существовать всегда, пока он не будет очищен или обновлен вручную.
var cacheName = 'cachev1'
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.addAll(
[
'/css/bootstrap.css',
'/css/main.css',
'/js/bootstrap.min.js',
'/js/jquery.min.js',
'/offline.html'
]
);
})
);
});
- Добавить прослушиватель для установки и использования
event.waitUntil()
чтобы сервисный работник неwaitUntil()
Установка завершается до завершения выполнения. - использовать
caches.open()
Создадим новый кеш cachev1 и вернем кешированный объект обещания.Когда он разрешен, мы используем его в методе thencaches.addAll
Чтобы добавить список, который вы хотите кэшировать, список представляет собой массив, а URL-адрес внутри относится к источнику. - Если обещание отклонено и установка не удалась, у нас нет подвоха, поэтому мы ничего не будем делать, мы также можем модифицировать код и добавить перерегистрированный код.
- После завершения установки Service Worker будет успешно активирован.
3. Активировать
Событие активации запускается, когда сервис-воркер установлен и активирован. Прослушивая событие активации, вы можете выполнить некоторую предварительную обработку, такую как обновление старых версий, очистку бесполезных кешей и т. д.
Как обновляются сервис-воркеры?
service-worker.js
Управляет кешем ресурсов страницы и запросов.Если содержимое js обновляется, браузер получает новый файл при доступе к странице сайта, и если он сравнивает файл js побайтно и находит, что он отличается, он будет считать, что обновление запущено.алгоритм обновления, который устанавливает новый файл и запускает событие установки. Но старый сервис-воркер, который уже находится в активном состоянии, в это время все еще работает, а новый сервис-воркер перейдет в состояние ожидания после завершения установки. Пока все открытые страницы не будут закрыты, старый сервис-воркер автоматически останавливается, и новый сервис-воркер не вступит в силу на следующей повторно открытой странице.
Что делать, если вы хотите, чтобы все страницы своевременно обновлялись автоматически при выходе новой версии? Вы можете выполнить метод self.skipWaiting() в событии установки, чтобы пропустить состояние ожидания и перейти непосредственно к фазе активации. Затем, когда произойдет событие активации, обновите Service Worker на всех клиентах, выполнив метод self.clients.claim().
// 安装阶段跳过等待,直接进入 active
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function (event) {
event.waitUntil(
Promise.all([
// 更新客户端
self.clients.claim(),
// 清理旧版本
caches.keys().then(function (cacheList) {
return Promise.all(
cacheList.map(function (cacheName) {
if (cacheName !== 'cachev1') {
return caches.delete(cacheName);
}
})
);
})
])
);
});
Когда файл js может кэшироваться браузером, когда файл изменяется, браузер по-прежнему использует старый файл. Это может привести к неотвечающим обновлениям. Если вы столкнулись с этой проблемой, вы можете попробовать следующее: добавить правило фильтрации для файла на веб-сервере, не кэшировать или установить более короткий срок действия.
или вызовите его вручнуюupdate()
обновить
navigator.serviceWorker.register('/service-worker.js').then(reg => {
// sometime later…
reg.update();
});
Может использоваться вместе с localStorage без необходимости каждый раз загружать и обновлять
var version = 'v1';
navigator.serviceWorker.register('/service-worker.js').then(function (reg) {
if (localStorage.getItem('sw_version') !== version) {
reg.update().then(function () {
localStorage.setItem('sw_version', version)
});
}
});
Схема
Каждое государство будет иметьing
, в ходе выполнения.
Web Storage
Выбор правильного механизма хранения важен как для хранилища на локальном устройстве, так и для хранилища на облачном сервере. Хороший механизм хранения гарантирует надежное хранение информации, уменьшая пропускную способность и повышая скорость отклика. Правильная стратегия кэширования хранилища является основным строительным блоком для обеспечения автономной работы мобильного Интернета.
Тип хранилища, постоянство хранилища, поддержка браузера и другие причины, как хранить более эффективно, находятся в центре нашего обсуждения.
материал
Best Practices for Using IndexedDB
Inspect and Manage Storage, Databases, and Caches
кеш API и IndexedDB
Рекомендации для автономного хранения данных могут включать:
- Для адресуемых URL-адресов ресурсов, используйтеCache API(часть сервисного работника)
- Для всех остальных данных используйте [IndexedDB}(developer.Mozilla.org/en-US/docs/…) (есть обертка обещания)
Фундаментальный
Оба вышеуказанных API являются асинхронными (IndexedDB основан на событиях, а Cache API — на Promise). они могут работать сweb Workers
windows
service workers
использовать вместе. IndexedDB в основном можно использовать во всех браузерных средах (см. CanIUse выше).Поддержка Service Wokers и Cahce API показана на рисунке выше, поддерживаются Chrome, Firefox и Opera. Оболочка Promise IndexedDB скрывает некоторые из мощных, но в то же время очень сложных механизмов, поставляемых с библиотекой IndexedDB (например, транзакции, управление версиями схемы). IndexedDB будет поддерживать наблюдателей, функцию, позволяющую легко синхронизировать теги.
Для PWA мы можем кэшировать статические ресурсы, тем самым используя Application Shell (файлы JS/CSS/HTML), написанные с помощью Cache API, и заполнять данные офлайн-страницы из IndexedDB.
Для веб-хранилища (LocalStorage/SessionStorage) является синхронным, не поддерживает рабочие веб-потоки и имеет ограничения по размеру и типу (только строки).
добавить на рабочий стол
Разрешение добавлять сайты на главный экран — важная функция, предоставляемая PWA. Хотя некоторые браузеры в настоящее время поддерживают добавление ярлыков веб-страниц на главный экран, чтобы облегчить пользователям быстрый доступ к сайтам, PWA добавляет больше, чем просто ярлык веб-страницы на главный экран, он предоставляет больше функций и делает PWA более родным.
Функциональность, которую PWA добавляет на рабочий стол, зависит отmanifest.json
.
Чтобы реализовать функцию добавления приложения PWA на рабочий стол, помимо требования, чтобы сайт поддерживал HTTPS, вам также необходимо подготовить файл manifest.json для настройки значка приложения, имени и другой информации. Например, базовый файл manifest.json должен содержать следующую информацию:
{
"name": "Easyify Docs",
"short_name": "Easyify Docs",
"start_url": "/",
"theme_color": "#FFDF00",
"background_color": "#FFDF00",
"display":"standalone",
"description": "A compilation tools for FE, built with webpack4.x, compile faster and smart, make work easier.",
"icons": [
{
"src": "./_assets/icons/32.png",
"sizes": "32x32",
"type": "image/png"
}
],
...
}
Разверните файл manifest.json в заголовке HTML-страницы сайта PWA, используя тег ссылки следующим образом:
<link rel="manifest" href="path-to-manifest/manifest.json">
Объяснение параметра:
name: {string} 应用名称,用于安装横幅、启动画面显示
short_name: {string} 应用短名称,用于主屏幕显示
icons: {Array.<ImageObject>} 应用图标列表
src: {string} 图标 url
type {string=} 图标的 mime 类型,非必填项,该字段可让浏览器快速忽略掉不支持的图标类型
sizes {string} 图标尺寸,格式为widthxheight,宽高数值以 css 的 px 为单位。如果需要填写多个尺寸,则使用空格进行间隔,如"48x48 96x96 128x128"
start_url: {string=} 应用启动地址
scope: {string} 作用域
// scope 应遵循如下规则:
//如果没有在 manifest 中设置 scope,则默认的作用域为 manifest.json 所在文件夹;
//scope 可以设置为 ../ 或者更高层级的路径来扩大PWA的作用域;
//start_url 必须在作用域范围内;
//如果 start_url 为相对地址,其根路径受 scope 所影响;
//如果 start_url 为绝对地址(以 / 开头),则该地址将永远以 / 作为根地址;
background_color: {Color} css色值 可以指定启动画面的背景颜色。
display: {string} 显示类型
//fullscreen 应用的显示界面将占满整个屏幕
//standalone 浏览器相关UI(如导航栏、工具栏等)将会被隐藏
//minimal-ui 显示形式与standalone类似,浏览器相关UI会最小化为一个按钮,不同浏览器在实现上略有不同
//browser 浏览器模式,与普通网页在浏览器中打开的显示一致
orientation: string 应用显示方向
//orientation属性的值有以下几种:
//landscape-primary
//landscape-secondary
//landscape
//portrait-primary
//portrait-secondary
//portrait
//natural
//any
theme_color: {Color} // css色值theme_color 属性可以指定 PWA 的主题颜色。可以通过该属性来控制浏览器 UI 的颜色。比如 PWA 启动画面上状态栏、内容页中状态栏、地址栏的颜色,会被 theme_color 所影响。
related_applications: Array.<AppInfo> 关联应用列表 可以引导用户下载原生应用
platform: {string} 应用平台
id: {string} 应用id
Push Notifications
Все уведомления — это сообщения, которые появляются на наших устройствах. Уведомления могут запускаться локально или отправляться сервером, а наше приложение в это время не запущено. Push-сообщение может создавать напоминания об обновлении приложения, и это также может представлять для нас интерес.
Когда наш веб-сайт может реализовывать push, веб-интерфейс становится на один шаг ближе к родному приложению.
Push-уведомления состоят из двух API:
- Notifications API используется для отображения системных уведомлений.
- Push API используется для обработки push-сообщений, отправляемых сервером.
Оба этих API основаны на Service Worker API, Service Worker отвечает на push-сообщения в фоновом режиме и передает их приложению.
Notification
Получать разрешение
Перед созданием уведомления необходимо получить разрешение пользователя:
// main.js
Notification.requestPermission(function(status) {
console.log('Notification permission status:', status);
//status 会有三个取值default granted denied 分别代表: 默认值(每次访问页面都询问)、 允许、拒绝
});
Добавить уведомление
После получения разрешения пользователя вы можетеshowNotification()
способ ограничения уведомлений из основного приложения.
// main.js
function displayNotification() {
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration().then(function(reg) {
reg.showNotification('Hello world!');
});
}
}
обращать вниманиеshowNotification
, вызовите этот метод для объекта регистрации Service Worker. Уведомления будут создаваться в активном Service Worker для прослушивания событий, вызванных взаимодействием с уведомлением.
showNotification
Методы имеют необязательные параметрыoptions
, чтобы настроить уведомления.
// main.js
function displayNotification() {
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration().then(function(reg) {
var options = {
body: 'Here is a notification body!', // 对通知添加描述
icon: 'images/example.png', // 添加一个icon图像
vibrate: [100, 50, 100], // 指定通知的电话振动模式,手机将振动100ms,暂停50ms,再次振动100ms
data: {
dateOfArrival: Date.now(),
primaryKey: 1
}, // 给通知添加自定义数据,当监听到通知的时候,可以捕获到这些数据,方便使用。
actions: [
{action: 'explore', title: 'Explore this new world',
icon: 'images/checkmark.png'},
{action: 'close', title: 'Close notification',
icon: 'images/xmark.png'},
] // 自定义的操作
};
reg.showNotification('Hello world!', options);
});
}
}
прослушать событие
После того, как пользователь получит уведомление, посредством операции уведомления будут инициированы связанные события отслеживаемых уведомлений, например, когда уведомление будет закрыто, будетnotificationclose
мероприятие.
// service-worker.js
self.addEventListener('notificationclick', function(e) {
var notification = e.notification;
var primaryKey = notification.data.primaryKey;
var action = e.action;
if (action === 'close') {
notification.close();
} else {
clients.openWindow('http://www.example.com');
notification.close();
}
});
Push
Операция уведомления должна сочетаться с push-уведомлением для достижения взаимодействия с пользователем, активного уведомления и напоминания пользователю.
Push service
В каждом браузере естьpush service
(служба push-уведомлений), когда пользователь разрешает разрешение на отправку текущего веб-сайта, текущий веб-сайт может быть подписан наpush service
. Это создает объект контракта, который содержит конечную точку службы push и открытые ключи. При отправке push-сообщения оно будет отправлено на URL-адрес конечной точки и зашифровано с помощью открытого ключа.push service
будет отправлен правильному клиенту.
Как служба push узнает, какому клиенту отправить сообщение? URL-адрес конечной точки содержит уникальный идентификатор. Этот идентификатор используется для перенаправления ваших сообщений на нужное устройство и при обработке браузером для идентификации Service Worker, который должен обрабатывать запрос.
Push-уведомления и сервис-воркеры работают вместе, поэтому push-уведомления также должны быть HTTPS, что гарантирует безопасность связи между сервером и службой push-уведомлений, а также безопасность службы push-уведомлений для пользователя.
Однако HTTPS не гарантирует безопасность самой службы push-уведомлений. Мы должны гарантировать, что данные, отправляемые с сервера клиенту, не подделываются и не проверяются напрямую какой-либо третьей стороной. Поэтому сообщение на сервере должно быть зашифровано.
Весь процесс отправки и получения показов
На стороне клиента:
1. Подпишитесь на push-сервис
2. Отправьте объект подписки на сервер
На сервере:
1. Создайте данные, отправленные пользователям
2. Зашифровать данные с помощью открытого ключа пользователя.
3. URL-адрес конечной точки, на которую отправляются данные с использованием зашифрованных полезных данных.
Сообщение направляется на устройство пользователя. Разбудите браузер, найдите нужного сервис-воркера и вызовите push-событие.
1. Получить данные сообщения (если есть) в push-событии
2. Выполнение пользовательской логики в push-событиях
3. Показать уведомления
Обработка push-событий
Когда браузер, который поддерживает push-сообщения, получает сообщение, он отправляет обслуживающий рабочийpush
мероприятие. Мы можем создать сервис-воркера вpush
Слушатели событий для обработки сообщений:
// service-worker.js
self.addEventListener('push', function(e) {
var options = {
body: 'This notification was generated from a push!',
icon: 'images/example.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: '2'
},
actions: [
{action: 'explore', title: 'Explore this new world',
icon: 'images/checkmark.png'},
{action: 'close', title: 'Close',
icon: 'images/xmark.png'},
]
};
e.waitUntil(
self.registration.showNotification('Hello world!', options)
);
});
Отличие от предыдущего заключается в том, что здесь отслеживается push-событие, ранее использовалось событие уведомления, а здесь используется метод event.waitUntil для продления жизненного цикла push-события до завершения асинхронной операции showNotification.
Подпишитесь на push-уведомления
Прежде чем отправлять push-сообщения, мы должны сначала подписаться на push-сервис. Подписка возвращает объект подписки илиsubscription
. Это очень важная часть всего процесса, поэтому мы можем знать, куда отправляется push-уведомление.
// main.js
//检查是否订阅了
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js').then(function (reg) {
console.log('Service Worker Registered!', reg);
reg.pushManager.getSubscription().then(function (sub) {
if (sub === null) {
// Update UI to ask user to register for Push
console.log('Not subscribed to push service!');
} else {
// We have a subscription, update the database
console.log('Subscription object: ', sub);
}
});
})
.catch(function (err) {
console.log('Service Worker registration failed: ', err);
});
}
function subscribeUser() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(function (reg) {
reg.pushManager.subscribe({
userVisibleOnly: true
}).then(function (sub) {
console.log('Endpoint URL: ', sub.endpoint);
}).catch(function (e) {
if (Notification.permission === 'denied') {
console.warn('Permission for notifications was denied');
} else {
console.error('Unable to subscribe to push', e);
}
});
})
}
}
Протокол веб-передачи
Протокол Web Push является официальным стандартом для отправки push-сообщений в браузеры. В нем описывается структура и процесс создания push-сообщения, его шифрования и отправки на платформу push-сообщений. Протокол абстрагируется от сведений о том, какая платформа обмена сообщениями и браузер у пользователя.
Протокол Web Push сложен, но нам не нужно знать все детали. Браузер автоматически отвечает за подписку пользователей с помощью службы push. Наша работа как разработчиков состоит в том, чтобы получить токен подписки, извлечь URL-адрес и отправить туда сообщение.
{"endpoint":"https://fcm.googleapis.com/fcm/send/dpH5lCsTSSM:APA91bHqjZxM0VImWWqDRN7U0a3AycjUf4O-byuxb_wJsKRaKvV_iKw56s16ekq6FUqoCF7k2nICUpd8fHPxVTgqLunFeVeB9lLCQZyohyAztTH8ZQL9WCxKpA6dvTG_TUIhQUFq_n",
"keys": {
"p256dh":"BLQELIDm-6b9Bl07YrEuXJ4BL_YBVQ0dvt9NQGGJxIQidJWHPNa9YrouvcQ9d7_MqzvGS9Alz60SZNCG3qfpk=",
"auth":"4vQK-SvRAN5eo-8ASlrwA=="
}
}
Обычно аутентификация VSPID используется для идентификации личности. Непосредственно к предыдущему примеру
//main.js
var endpoint;
var key;
var authSecret;
// We need to convert the VAPID key to a base64 string when we subscribe
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function determineAppServerKey() {
var vapidPublicKey = 'BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY';
return urlBase64ToUint8Array(vapidPublicKey);
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js').then(function (registration) {
return registration.pushManager.getSubscription()
.then(function (subscription) {
if (subscription) {
// We already have a subscription, let's not add them again
return;
}
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: determineAppServerKey()
})
.then(function (subscription) {
var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
authSecret = rawAuthSecret ?
btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
endpoint = subscription.endpoint;
return fetch('http://localhost:3111/register', {
method: 'post',
headers: new Headers({
'content-type': 'application/json'
}),
body: JSON.stringify({
endpoint: subscription.endpoint,
key: key,
authSecret: authSecret,
}),
})
});
});
}).catch(function (err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
// server.js
const webpush = require('web-push');
const express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
const app = express();
// Express setup
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
function saveRegistrationDetails(endpoint, key, authSecret) {
// Save the users details in a DB
}
webpush.setVapidDetails(
'mailto:contact@deanhume.com',
'BAyb_WgaR0L0pODaR7wWkxJi__tWbM1MPBymyRDFEGjtDCWeRYS9EF7yGoCHLdHJi6hikYdg4MuYaK0XoD0qnoY',
'p6YVD7t8HkABoez1CvVJ5bl7BnEdKUu5bSyVjyxMBh0'
);
// Send a message
app.post('/sendMessage', function (req, res) {
var endpoint = req.body.endpoint;
var authSecret = req.body.authSecret;
var key = req.body.key;
const pushSubscription = {
endpoint: req.body.endpoint,
keys: {
auth: authSecret,
p256dh: key
}
};
var body = 'Breaking News: Nose picking ban for Manila police';
var iconUrl = 'https://raw.githubusercontent.com/deanhume/progressive-web-apps-book/master/chapter-6/push-notifications/public/images/homescreen.png';
webpush.sendNotification(pushSubscription,
JSON.stringify({
msg: body,
url: 'http://localhost:3111/article?id=1',
icon: iconUrl,
type: 'actionMessage'
}))
.then(result => {
console.log(result);
res.sendStatus(201);
})
.catch(err => {
console.log(err);
});
});
// Register the user
app.post('/register', function (req, res) {
var endpoint = req.body.endpoint;
var authSecret = req.body.authSecret;
var key = req.body.key;
// Store the users registration details
saveRegistrationDetails(endpoint, key, authSecret);
const pushSubscription = {
endpoint: req.body.endpoint,
keys: {
auth: authSecret,
p256dh: key
}
};
var body = 'Thank you for registering';
var iconUrl = '/images/homescreen.png';
webpush.sendNotification(pushSubscription,
JSON.stringify({
msg: body,
url: 'https://localhost:3111',
icon: iconUrl,
type: 'register'
}))
.then(result => {
console.log(result);
res.sendStatus(201);
})
.catch(err => {
console.log(err);
});
});
// The server
app.listen(3111, function () {
console.log('Example app listening on port 3111!')
});
Весь процесс push будет подробно описан позже. Вы также можете сначала увидеть описание учебника, предоставленное Google.Developers.Google.com/Web/iTwo/Fatboy…