VUE PWA 插件,接收server端消息推送并显示通知

PWA,即 Progressive web apps(渐进式 Web 应用),PWA使得web应用具有与原生应用类似的用户体验,如离线运行、添加到主屏、消息通知等(详细介绍)。本文介绍VUE工程中使用@vue/cli-plugin-pwa插件实现消息通知并刷新VUE组件。

创建VUE工程并安装PWA插件

终端执行以下命令创建vue-pwa-notification工程:

vue create vue-pwa-notification

执行以下命令安装PWA插件:

cd vue-pwa-notification
vue add @vue/pwa

安装完成后工程结构:

.
├── babel.config.js
├── package.json
├── package-lock.json
├── public
│   ├── favicon.ico
│   ├── img
│   │   └── icons
│   ├── index.html
│   └── robots.txt
├── README.md
└── src
    ├── App.vue
    ├── assets
    │   └── logo.png
    ├── components
    │   └── HelloWorld.vue
    ├── main.js
    └── registerServiceWorker.js

安装AXIOS,实现API client

安装axios:

npm i axios

src下创建plugins目录,plugins目录下新建axios.js:

// plugins/axios.js
import Axios from "axios";

const axios = Axios.create({
    // 实际开发中应使用环境配置
    baseURL: 'http://192.168.3.90:3000',
    timeout: 10 * 1000,
    withCredentials: false
})

/**
 * 请求拦截器
 */
axios.interceptors.request.use(config => {
    config.headers.Authorization = sessionStorage.getItem('access_token')
    return config
}, error => {
    return Promise.reject(error)
})

/**
 * 响应拦截器
 */
axios.interceptors.response.use(response => {
    return response
}, error => {
    // 响应错误
    return Promise.reject(error)
})

export default axios


修改registerServiceWorker.js

service worker就绪后订阅消息服务并提交subscribe至server端保存:

// registerServiceWorker.js
import {register} from 'register-service-worker'
import axios from "@/plugins/axios";

// 公钥
const publicKey = 'BO_sjITRaeBOaC5UDMb6L3_h64FMRozOAgct02jsKcfjvM6SuKcJjQTMXBBGM5H3xhT1u-Oz11_Gi1yC8RDsin4'

if (process.env.NODE_ENV === 'production') {
    register('./sw.js', {
        // service worker 就绪
        ready(registration) {
            console.log(
                'App is being served from cache by a service worker.\n' +
                'For more details, visit https://goo.gl/AFskqB'
            )
            // 订阅web push服务,成功后提交endpoint至服务端保存
            const convertedVapidKey = urlBase64ToUint8Array(publicKey);
            const subscribeOption = {
                userVisibleOnly: true,
                applicationServerKey: convertedVapidKey,
            }
            registration.pushManager.subscribe(subscribeOption).then(endpoint => {
                // 提交endpoint
                axios.post('endpoint', endpoint).then(res => {
                    console.log('save push endpoint result, ' + JSON.stringify(res))
                })
            })
        },
        registered() {
            console.log('Service worker has been registered.')
        },
        cached() {
            console.log('Content has been cached for offline use.')
        },
        updatefound() {
            console.log('New content is downloading.')
        },
        updated() {
            console.log('New content is available; please refresh.')
        },
        offline() {
            console.log('No internet connection found. App is running in offline mode.')
        },
        error(error) {
            console.error('Error during service worker registration:', error)
        }
    })
}

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;
}

server端保存endpoint,push消息时根据特定条件获取要通知的endpoint,然后sendNotification。

vue.config.js配置pwa

module.exports = {
    publicPath: './',
    pwa: {
        name: 'notification',
        themeColor: '#1976D2',
        msTileColor: '#FFFFFF',
        workboxPluginMode: 'InjectManifest',
        workboxOptions: {
            swSrc: 'src/sw.js'
        }
    }
}

src下新建sw.js

service worker注册push事件监听

self.addEventListener('push', evt => {
    const message = evt.data.json()
    // 显示通知
    self.registration.showNotification(message.title, {
        body: message.content
    })
})

首次访问时应用将获取通知权限,如下:

调用server端发送消息,terminal执行:

curl -X POST http://192.168.3.90:3000/message -b '{"title": "system notification","content": "nice, this is a notification from web-push"}' -H "Content-Type: application/json"

消息通知:

web push更新VUE DATA

service woker接收到server端Push的通知后,当我们点击通知,将消息内容显示在vue组件中。

sw.js中注册通知点击事件:

self.addEventListener('notificationclick', evt => {
    evt.notification.close()
    // 获取client
    evt.waitUntil(self.clients.matchAll({ type: 'window' }).then(clients => {
        clients.forEach(client => {
            // postMessage将信息发送给界面
            client.postMessage(evt.notification.body)
        })
    }))
})

App.vue中注册message监听:

// App.vue
  mounted() {
    navigator.serviceWorker.addEventListener('message', evt => {
      this.response = evt.data
    })
  }

vue工程需build后部署运行,因为@vue/cli-plugin-pwa插件只在production环境运行,因为若service worker在dev环境启用,则缓存资源导致本地变更不能被使用。

  1. 本文源码地址:https://github.com/louie-001/vue-pwa-notification.git
  2. server端如何保存endpoint以及使用web push推送消息,请查看https://juejin.im/post/6890733677534248974
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容