H5使用Chrome 权限问题

一、Chrome浏览器音/视频无法自动播放

第一种:修改chrome 浏览器配置

添加对应的网站地址或者html 代码,允许其播放声音。

二、Chrome桌面提醒功能,兼容新老版本,firefox最新版本也通过

html 复制代码
<!DOCTYPE html>
<html lang="en">
 <head>
  <title> new document </title>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="renderer" content="webkit">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
 </head>
 <body>
  <div>
    <button type="button" autofocus onclick="start()">测试发送消息</button>
  </div>
<script>
    
  function start(){
    var count=1
    setInterval(()=>{
      notify("测试","测试"+count)
      count++
    },1000)
    
  }
  
  
//桌面提醒
function notify(title, content) {
        console.log("notify")
        if(!title && !content){
            title = "桌面提醒";
            content = "您看到此条信息桌面提醒设置成功";
        }
        //var iconUrl = "/images/send_ok.png";
     var iconUrl="https://profile-avatar.csdnimg.cn/764d816f76e346ea98a3a6ffefde8588_simayilong.jpg"
        
        if (window.webkitNotifications) {
            //chrome老版本
            if (window.webkitNotifications.checkPermission() == 0) {
                var notif = window.webkitNotifications.createNotification(iconUrl, title, content);
                notif.display = function() {}
                notif.onerror = function() {}
                notif.onclose = function() {}
                notif.onclick = function() {this.cancel();}
                notif.replaceId = 'Meteoric';
                notif.show();
            } else {
                window.webkitNotifications.requestPermission($jy.notify);
            }
        }
        else if("Notification" in window){
            // 判断是否有权限
            if (Notification.permission === "granted") {
                var notification = new Notification(title, {
                    "icon": iconUrl,
                    "body": content,
                });
            }
            //如果没权限,则请求权限
            else if (Notification.permission !== 'denied') {
                Notification.requestPermission(function(permission) {
                    // Whatever the user answers, we make sure we store the
                    // information
                    if (!('permission' in Notification)) {
                        Notification.permission = permission;
                    }
                    //如果接受请求
                    if (permission === "granted") {
                        var notification = new Notification(title, {
                            "icon": iconUrl,
                            "body": content,
                        });
                    }
                });
            }
        }
    }
    
</script>
 </body>
</html>

recat 代码

javascript 复制代码
 ### Recat index.tsx
/* 
    1. 进入页面时请求通知权限
    2. 建立websocket连接
        2.1 收到来自后端的消息,更新页面数据
        2.2 如果是页面被隐藏,那么则进行通知提示
*/
import warmTipsAudio from '@/assets/warmTips.mp3';
import type { TableProps } from 'antd';
import { Alert, message, Space, Statistic, Table, Tag } from 'antd';
import { useEffect, useRef, useState } from 'react';

interface DataType {
  key: string;
  name: string;
  age: number;
  address: string;
  tags: string[];
}

const columns: TableProps<DataType>['columns'] = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
    render: (text) => <a>{text}</a>,
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
  {
    title: 'Tags',
    key: 'tags',
    dataIndex: 'tags',
    render: (_, { tags }) => (
      <>
        {tags.map((tag) => {
          let color = tag.length > 5 ? 'geekblue' : 'green';
          if (tag === 'loser') {
            color = 'volcano';
          }
          return (
            <Tag color={color} key={tag}>
              {tag.toUpperCase()}
            </Tag>
          );
        })}
      </>
    ),
  },
  {
    title: 'Action',
    key: 'action',
    render: (_, record) => (
      <Space size="middle">
        <a>Invite {record.name}</a>
        <a>Delete</a>
      </Space>
    ),
  },
];

export default function Warning() {
  const [sum, setSum] = useState(0);
  const [tableData, setTableData] = useState<DataType[]>([]);
  const [notifArr, setNotifArr] = useState<Notification[]>([]);
  const [visible, setVisible] = useState(false);

  const [messageApi, contextHolder] = message.useMessage();
  // 这个值要取localStorage的notifyTip
  const [notifyTip, setNotifyTip] = useState(true);

  // 这个值存到浏览器中
  const [warmTips, setWarnTips] = useState(true);

  // 音频控制
  const warmTipsAudioRef = useRef();

  const handleWarmTipsClose = () => {
    setWarnTips(false);
    localStorage.setItem('warmTips', 'false');
  };

  const closeNotif = () => {
    if (document.visibilityState === 'visible') {
      notifArr.forEach((item: Notification) => {
        item.close();
      });
      setNotifArr([]);
    }
  };

  const handleNotifyTip = (e: boolean) => {
    setNotifyTip(e);
    localStorage.setItem('notifyTip', e + '');
  };

  const initNotifyPermission = () => {
    const notify = new Notification('提示(3s后自动关闭)', {
      body: '当弹窗被遮挡或是收起的时候,会通过此形式将「预警信息」提示用户',
      icon: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
    });
    handleNotifyTip(false);
    setTimeout(() => {
      notify.close();
    }, 3000);
  };

  // 请求用户通知权限,需要用户点击允许
  const notificationSet = () => {
    if (!('Notification' in window)) {
      // 检查浏览器是否支持通知
      setVisible(true);
    } else if (Notification.permission === 'granted') {
      // 检查是否已授予通知权限;如果是的话,创建一个通知
      initNotifyPermission();
    } else if (Notification.permission === 'default') {
      // 默认则征求用户的许可
      Notification.requestPermission().then((permission) => {
        // 如果用户接受,我们就创建一个通知
        if (permission === 'granted') {
          initNotifyPermission();
        } else {
          // 用户点击拒绝,再次发起征求请求
          setNotifyTip(true);
          messageApi.open({
            type: 'error',
            content:
              '您禁用了该页面发出通知,这将导致您收不到后续更新提示,请在浏览器设置中放开该页面通知权限',
            duration: 10,
          });
        }
      });
    } else {
      // 提示用户放开浏览器通知权限和系统通知权限
      setNotifyTip(true);
      handleNotifyTip(true);
    }
  };

  // 建立websocket连接
  const webSocketSet = () => {
    // Create WebSocket connection.
    const socket = new WebSocket('ws://localhost:8080');

    // 监听连接
    socket.addEventListener('open', function () {
      socket.send('Hello Server!');
    });

    // 监听后端传来的消息
    socket.addEventListener('message', function (event) {
      console.log('Message from server ', event.data);
      // 用新增一行table来标识接受到了消息
      setTableData((data) => [
        ...data,
        {
          key: Math.random().toString(36).slice(-6),
          name: 'Joe Black',
          age: 32,
          address: 'Sydney No. 1 Lake Park',
          tags: ['cool', 'teacher'],
        },
      ]);
      // eslint-disable-next-line no-param-reassign
      setSum((sum) => sum + 1);
      // 同时在这里判断,若网页变为不可见了,则进行提示
      if (document.visibilityState !== 'visible') {
        // 通知被关闭再发,不要一直发
        const notif = new Notification('数据已更新,请立即查看', {
          body: '具体信息。。。',
          icon: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
          requireInteraction: true,
          image:
            'https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png',
        });
        notif.onclick = () => {
          window.focus();
        };
        warmTipsAudioRef.current.play();
        setNotifArr((data: Notification[]) => [...data, notif]);
      }
    });
  };
  useEffect(() => {
    notificationSet();
    webSocketSet();
    if (localStorage.getItem('warmTips')) {
      setWarnTips(localStorage.getItem('warmTips') === 'true' ? true : false);
    }
    if (localStorage.getItem('notifyTip')) {
      setNotifyTip(localStorage.getItem('notifyTip') === 'true' ? true : false);
    }
  }, []);

  useEffect(() => {
    document.addEventListener('visibilitychange', closeNotif);
    return () => {
      document.removeEventListener('visibilitychange', closeNotif);
    };
  }, [notifArr]);

  return (
    <>
      {contextHolder}
      {warmTips && (
        <Alert
          message="若您收不到该页面发出的通知,可能是您禁止该页面发出通知或者是该浏览器被系统禁止发出通知,请放开相关权限"
          type="info"
          showIcon
          closable
          style={{ marginBottom: '10px' }}
          onClose={handleWarmTipsClose}
        />
      )}
      {notifyTip && (
        <Alert
          message="该页面已被禁止发出通知,这将导致您收不到后续更新提示,请检查"
          type="error"
          showIcon
          closable
        />
      )}
      {visible && (
        <Alert message="该浏览器不支持通知" type="error" showIcon closable />
      )}
      <Statistic title="数据量" value={sum} />
      <Table columns={columns} dataSource={tableData} />
      <audio
        src={warmTipsAudio}
        style={{ display: 'none' }}
        ref={warmTipsAudioRef}
      ></audio>
    </>
  );
}


### websocket server nodejs

const express = require('express');
const WebSocket = require('ws');
const WebSocketServer = WebSocket.WebSocketServer;

const app = express();

app.get('/', (req, res) => {
  res.send({
    ok: 1,
  });
});

app.listen(3000, () => {
  console.log('express start');
});

const wss = new WebSocketServer({port: 8080});

wss.on('connection', function connection(ws) {
  ws.on('error', console.error);

  ws.on('message', function message(data) {
    console.log('received: %s', data);
  });
  setInterval(() => {
    ws.send('something', {binary: false});
  }, 4000);
});

这里还有一个额外的知识,就是我发现某些网页能够实现:即使浏览器没有打开,也可以发送通知的功能,这个我去了解了一下,大致原理如下,有需要的朋友自行阅读:

「即使浏览器未打开,某些网页也能发出桌面通知」,通常是通过浏览器推送通知(Browser Push Notifications)技术实现的。具体来说,这项功能依赖于以下几个关键技术组件:

  1. 服务工作线程(Service Workers):

服务工作线程是一种独立于网页主线程的脚本,能够在后台运行,即使浏览器未打开,或者用户没有打开特定网站。它们在浏览器中作为一个中间层,处理网络请求、推送通知、缓存等任务。服务工作线程可以在后台保持活跃,并在接收到来自服务器的推送消息时触发通知。

  1. 推送通知(Push Notifications):

推送通知是由服务工作线程处理的消息。这些通知通过推送服务从服务器发送到用户的浏览器,即使用户当前没有访问该网站。推送服务将消息传递到浏览器中的服务工作线程,后者可以根据消息的内容在桌面上显示通知。

  1. Web 推送 API(Web Push API):

这是一个标准化的 API,允许网站在用户授权后注册一个服务工作线程,并通过推送服务发送通知。网站首先需要获得用户的许可,才能使用这项功能。一旦用户同意,网站可以在服务工作线程中注册推送事件,并配置通知的内容。

  1. 浏览器推送服务(Browser Push Service):

各大浏览器都有自己的推送服务,用于中转来自网站的推送消息。这些服务确保消息能够在合适的时间传递给浏览器,即使用户未打开浏览器。这些推送服务通常与操作系统通知系统集成,确保通知能在桌面上显示。

工作流程概述

  • 用户授权:当用户访问支持推送通知的网站时,网站会请求通知权限。
  • 服务工作线程注册:如果用户同意,浏览器会在后台注册一个服务工作线程。
  • 推送通知:网站服务器通过浏览器的推送服务向用户的设备发送通知,即使浏览器未打开,服务工作线程也能接收到这些消息,并在桌面上显示通知。

这种机制使得网站能够在用户没有主动访问时,仍然与用户保持互动,提供及时的信息或提醒。

相关推荐
掘金一周1 小时前
你们觉得房贷多少,没有压力 | 沸点周刊 4.30
前端·人工智能·后端
大貔貅喝啤酒1 小时前
接口测试_Postman(详细版)
javascript·测试工具·node.js·自动化·postman
小小码农Come on1 小时前
QML访问子项内容
前端·javascript·html
桜吹雪2 小时前
Langchain.js官方文档:构建具备按需加载技能的 SQL 助手
javascript·人工智能·node.js
han_2 小时前
一篇看懂国内外主流大模型:GPT、Claude、Gemini、DeepSeek、通义千问有什么区别?
前端·人工智能·llm
一行代码一行诗++2 小时前
注释是什么和注释该怎么写(C语言)
java·前端·javascript
涂兵兵_青石疏影2 小时前
beginPath-vs-save详解
前端
陈振wx:zchen20082 小时前
前端-面试题-JavaScript
javascript·前端面试题
泽_浪里白条2 小时前
我在 Superset 6.x 做自定义图表 + Embedded SDK 集成的实战复盘(附踩坑清单)
前端·数据可视化