在浏览器环境中拦截 HTML5 Web 通知

问题描述 投票:0回答:2

我想拦截 HTML5 Web 通知。我已阅读以下 answer,其中用户建议可以使用您自己的充当代理的对象来覆盖

window.Notification
对象。我尝试这样做,但无法使其发挥作用。以下是我在加载页面时注入的 JavaScript 代码:

function setNotificationCallback(callback) {

    const OldNotify = window.Notification;
    OldNotify.requestPermission();

    const newNotify = (title, opt) => {
        callback(title, opt);
        return new OldNotify(title, opt);
    };
    newNotify.requestPermission = OldNotify.requestPermission.bind(OldNotify);
    Object.defineProperty(newNotify, 'permission', {
        get: () => {
            return OldNotify.permission;
        }
    });

    window.Notification = newNotify;
}
function notifyCallback(title, opt) {
    console.log("title", title); // this never gets called
}

window.Notification.requestPermission(function (permission) {
    if (permission === "granted") {
        setNotificationCallback(notifyCallback);
    }
})
javascript html web browser web-notifications
2个回答
12
投票

问题是箭头函数不能用作构造函数(Source)。

使用此代码的项目仍然具有箭头功能:https://github.com/nativefier/nativefier/blob/e00f08e5d6fbdd86cdba8efec5e809d0308117d8/app/src/static/preload.js但它在Electron中运行,这可能会解释为什么它的行为不同。

编辑:

它不再使用箭头函数:https://github.com/nativefier/nativefier/blob/master/app/src/preload.ts

如果针对最新的浏览器,请使用如下命名函数:

(function () {

    function notifyCallback(title, opt) {
        console.log("title", title);
    }

    const OldNotify = window.Notification;

    function newNotify(title, opt) {
        notifyCallback(title, opt);
        return new OldNotify(title, opt);
    }

    newNotify.requestPermission = OldNotify.requestPermission.bind(OldNotify);
    Object.defineProperty(newNotify, 'permission', {
        get: function() {
            return OldNotify.permission;
        }
    });

    window.Notification = newNotify;
})();

Notification.requestPermission(function (permission) {
    if (permission === "granted") {
        const notif = new Notification('My title');
    }
});

如此创建的代理将在其他代码/库调用

new Notification()
(如我的示例中所示)时生效。我已将代理逻辑移至顶层,以确保在用户接受接收通知之前其他代码/库不会保留对本机
Notification
的引用。您还必须将代码放在最前面以保证这一点。

如果您的目标浏览器支持 ECMAScript 6,则有一种更优雅的方法:

(function () {

    function notifyCallback(title, opt) {
        console.log("title", title);
    }

    const handler = {
        construct(target, args) {
            notifyCallback(...args);
            return new target(...args);
        }
    };

    const ProxifiedNotification = new Proxy(Notification, handler);

    window.Notification = ProxifiedNotification;
})();

Notification.requestPermission(function (permission) {
    if (permission === "granted") {
        const notif = new Notification('My title');
    }
});

它更具可扩展性(未来 ECMAScript 版本中的

Notification
API 更改时不会产生影响,因为它允许操作原生
Notification
而不是手工制作的)。


0
投票

我按照 Guerric P 的说明更新了我的代码,但仍然没有发生任何事情。 幸运的是,我偶然发现了这个[答案][1]。

您可能会想仅使用 notifhook.js 作为内容脚本,但这行不通 因为内容脚本和网页具有单独的执行环境。

以下是我使用 manifest v3

采取的步骤
  1. 创建一个名为 intercept-notify.js 的文件:

    (函数(){

    // Customize notification inside callback
    function notifyCallback(title, opt) {
        opt.body = 'You have a new message'
    }
    
    const OldNotify = window.Notification;
    
    function newNotify(title, opt) {
        notifyCallback(title, opt);
        return new OldNotify(title, opt);
    }
    
    newNotify.requestPermission = OldNotify.requestPermission.bind(OldNotify);
    Object.defineProperty(newNotify, 'permission', {
        get: function () {
            return OldNotify.permission;
        }
    });
    
    window.Notification = newNotify;
    

    })();

  2. 接下来,将

    intercept-notify.js
    包含在
    web_accessible_resources
    manifest.json
    列表中。

  3. 最后,在 content 脚本中,将

    <script>
    元素注入到页面中,并将
    intercept-notify.js
    作为其 src:

    const s = document.createElement("script"); s.id = '注入拦截通知' // 可选 =))

    s.src = chrome.runtime.getURL("src/intercept-notify.js");

    document.body.appendChild(s);

  4. 重新加载扩展程序,祝你好运! 💕 [1]:https://stackoverflow.com/a/15953720/15893890

© www.soinside.com 2019 - 2024. All rights reserved.