在浏览器环境中拦截 HTML5 Web 通知
Intercept HTML5 Web Notifications in a browser environment
我想截取 HTML5 Web Notifications. I have read the following 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);
}
})
问题是箭头函数不能用作构造函数(Source)。
使用此代码的项目仍然有一个箭头函数:https://github.com/nativefier/nativefier/blob/e00f08e5d6fbdd86cdba8efec5e809d0308117d8/app/src/static/preload.js but it runs in 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');
}
});
这样创建的代理将在其他code/libraries调用new Notification()
时生效,就像我的例子一样。我已将代理逻辑移至顶层,以确保其他 code/libraries 在用户接受通知之前不会保留对本机 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');
}
});
它更具可扩展性(当 Notification
API 在未来的 ECMAScript 版本中发生变化时没有影响,因为它允许操纵原生 Notification
而不是手工制作的)。
我想截取 HTML5 Web Notifications. I have read the following 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);
}
})
问题是箭头函数不能用作构造函数(Source)。
使用此代码的项目仍然有一个箭头函数:https://github.com/nativefier/nativefier/blob/e00f08e5d6fbdd86cdba8efec5e809d0308117d8/app/src/static/preload.js but it runs in 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');
}
});
这样创建的代理将在其他code/libraries调用new Notification()
时生效,就像我的例子一样。我已将代理逻辑移至顶层,以确保其他 code/libraries 在用户接受通知之前不会保留对本机 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');
}
});
它更具可扩展性(当 Notification
API 在未来的 ECMAScript 版本中发生变化时没有影响,因为它允许操纵原生 Notification
而不是手工制作的)。