简体   繁体   English

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

[英]Intercept HTML5 Web Notifications in a browser environment

I would like to intercept HTML5 Web Notifications .我想拦截HTML5 Web 通知 I have read the following answer where a user suggests that it is possible to override the window.Notification object with your own object that will act as a proxy.我已阅读以下答案,其中用户建议可以使用您自己的将充当代理的对象覆盖window.Notification对象。 I tried to do that but couldn't manage it to work.我试图这样做,但无法使其正常工作。 Below is the JavaScript code I am injecting when a page has been loaded:下面是我在加载页面时注入的 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);
    }
})

The problem is that an arrow function can't be used as a constructor ( Source ).问题是箭头函数不能用作构造函数( Source )。

The project that uses this code still has an arrow function: https://github.com/jiahaog/nativefier/blob/master/app/src/static/preload.js but it runs in Electron which might explain why it behaves differently.使用此代码的项目仍然具有箭头功能: https : //github.com/jiahaog/nativefier/blob/master/app/src/static/preload.js但它在Electron中运行,这可能解释了为什么它的行为不同。

If targeting recent browsers, rather use a named function like this:如果针对最近的浏览器,请使用像这样的命名函数:

(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');
    }
});

The proxy thus created will then be effective when other code/libraries call new Notification() like in my example.当其他代码/库像我的例子一样调用new Notification()时,这样创建的代理就会生效。 I have moved the proxifying logic to the top-level to ensure that the other code/libraries won't keep a reference on the native Notification before the user accepts to receive notifications.我已将代理逻辑移至顶层,以确保其他代码/库在用户接受接收通知之前不会保留对本机Notification的引用。 You must also put the code at the very first place to guarantee that.您还必须将代码放在首位以保证这一点。

And if your target browsers support ECMAScript 6, there is a much more elegant way to do it:如果您的目标浏览器支持 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');
    }
});

It's much more scalable (no impact when the Notification API changes in future ECMAScript versions since it allows to manipulate the native Notification rather than a handmade one).它更具可扩展性(当Notification API 在未来的 ECMAScript 版本中更改时不会产生影响,因为它允许操作本机Notification而不是手工制作的Notification )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM