美文网首页
VUE PWA 插件,接收server端消息推送并显示通知

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

作者: louieSun | 来源:发表于2020-11-18 23:40 被阅读0次

    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

    相关文章

      网友评论

          本文标题:VUE PWA 插件,接收server端消息推送并显示通知

          本文链接:https://www.haomeiwen.com/subject/vyohiktx.html