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

dal*_*t97 5 html javascript browser web web-notifications

我想拦截HTML5 Web通知。我已经阅读了以下答案,其中用户建议可以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);
    }
})
Run Code Online (Sandbox Code Playgroud)

Twi*_*her 5

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

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

如果定位最新的浏览器,则应使用如下命名函数:

(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: () => {
            return OldNotify.permission;
        }
    });

    window.Notification = newNotify;
})();

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

这样创建的代理将在其他代码/库调用时有效,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');
    }
});
Run Code Online (Sandbox Code Playgroud)

它具有更大的可扩展性(NotificationAPI在将来的ECMAScript版本中更改时不会产生影响,因为它允许操作本机Notification而不是手工的)。