如何在一体式(Edge/Firefox/Chrome)浏览器扩展中实现消息传递回调&x27;什么是内容脚本?

如何在一体式(Edge/Firefox/Chrome)浏览器扩展中实现消息传递回调&x27;什么是内容脚本?,firefox,google-chrome-extension,callback,microsoft-edge,firefox-addon-webextensions,Firefox,Google Chrome Extension,Callback,Microsoft Edge,Firefox Addon Webextensions,开发环境操作系统:Windows 7企业版LTS 浏览器兼容性最低要求:自2018年起应支持所有Edge、Firefox和Chrome浏览器。 当前正在处理的问题:无法在开发人员工作站上运行VM;无法运行Windows 10虚拟机来调试Microsoft边缘扩展 解释: “一体式浏览器扩展”指的是一种浏览器扩展代码,它使用相同的代码,但有细微的差异,在各种支持WebExtensions/Chrome扩展的浏览器上工作。至少,相同的代码库应该可以在Edge、Firefox和Chrome上工作和运

开发环境操作系统:Windows 7企业版LTS
浏览器兼容性最低要求:自2018年起应支持所有Edge、Firefox和Chrome浏览器。
当前正在处理的问题:无法在开发人员工作站上运行VM;无法运行Windows 10虚拟机来调试Microsoft边缘扩展

解释:

  • “一体式浏览器扩展”指的是一种浏览器扩展代码,它使用相同的代码,但有细微的差异,在各种支持WebExtensions/Chrome扩展的浏览器上工作。至少,相同的代码库应该可以在Edge、Firefox和Chrome上工作和运行,只需做很小的更改
  • Edge/Firefox/Chrome扩展的内容脚本的回调处理方式不同
  • 由于未知原因,我无法在工作站计算机上运行VM。当VM运行时,VM客户端为黑色。这是我这边的一个局部问题,我无法解决,因此我不得不找到一个不同的解决方案/替代方案
如何在内容脚本上以不同方式处理它们:

  • 边缘:
    browser.runtime.sendMessage
    使用回调,并返回
    undefined
  • Firefox:
    browser.runtime.sendMessage使用承诺并返回承诺
  • Chrome:
    Chrome.runtime.sendMessage
    使用回调,并返回
    undefined
根据各种参考资料:

在内容脚本上,您可以在顶部声明以下JavaScript片段,以便创建可在其他任何地方引用的全局变量:

//Global "browser" namespace definition.
window.browser = (function() {
    return window.msBrowser || window.browser || window.chrome;
})();
不幸的是,由于我遇到的问题(VM未运行),我无法判断是否仍在使用
window.msBrowser
。当使用
namespace.runtime.sendMessage
处理消息回调时,此解决方案对我没有帮助


综上所述,我的主要问题是:如何编写能够正确处理回调的消息传递函数?

目前,我正在使用以下代码:

function sendGlobalMessage(messageRequest, callback) {
    if (chrome && window.openDatabase) {
        //This is Chrome browser
        chrome.runtime.sendMessage(messageRequest, callback);
    }
    else if (browser) {
        try {
            //Edge will error out because of a quirk in Edge IndexedDB implementation.
            //See https://gist.github.com/nolanlawson/a841ee23436410f37168
            let db = window.indexedDB.open("edge", (Math.pow(2, 30) + 1));
            db.onerror = function(e) {
                throw new Error("edge is found");
            };
            db.onsuccess = function(e) {
                //This is Firefox browser.
                browser.runtime.sendMessage(messageRequest).then(callback);
            };
        }
        catch (e) {
            //This is Edge browser
            browser.runtime.sendMessage(messageRequest, callback);
        }
    }
}
我真的觉得这是一个黑客解决方案,因为代码基于浏览器平台独有的怪癖,以便将
chrome.runtime.sendMessage
browser.runtime.sendMessage
API调用分开,以便在各自的平台中处理回调。我真的想改变这一切

所以我想问的是,有什么更好的方法可以用来检测不同的平台,同时正确地处理消息传递回调


提前谢谢。

我想我已经解决了

编辑:最终版本(更新更稳定,消息传递更少):


(原帖):

最终版本(现已废弃):

在第二个
if
语句中,通过检查
window.browser.runtime.sendMessage
的返回值是否为
Promise
undefined
,我们可以检测平台是否为
Firefox
Edge

我认为这是处理内容脚本上的消息传递回调/消息响应的唯一解决方案

我真的想不出比这更好的解决办法了。所以从现在起我将使用这个

但是如果其他人知道更好的方法,一种不需要在每次函数调用中为Firefox和Edge额外发送一条虚拟消息的方法,那就太好了


内容脚本中的任何内容都不是持久性的,这很糟糕,即使您存储了代码运行在哪个平台上的信息,您仍然必须先从后台脚本获取信息,然后再过滤出要调用的
运行时.sendMessage
函数,所以它并没有真正节省很多时间。

为什么你不能像其他人一样简单地使用Mozilla的web扩展polyfill?@wOxxOm它不适合Edge。此外,还缺少一些关键检查。在Edge/Firefox中,它什么也不做,因为它们已经有了
browser
API。至于这个问题,它已经在github回购协议中修复了,修复本身非常简单。@wOxxOm为什么问题仍然存在?:/我不是维护者,所以我不知道为什么。看起来边缘是一个完整的混乱,虽然(相当期待),所以这个polyfill不会帮助它。
//Global "browser" namespace definition, defined as "namespace". Can be renamed to anything else.
window.namespace = (function() {
    return window.browser || window.chrome;
})();

function sendGlobalResponse(message, callback){
    if (window.namespace === window.chrome) {
        //Chrome
        window.namespace.runtime.sendMessage(message, callback);
    }
    else if (window.namespace === window.browser) {
        //Using instanceof to check for object type, and use the returned evaluation as a truthy value.
        let supportPromises = false;
        try {
            supportPromises = window.namespace.runtime.getPlatformInfo() instanceof Promise;
        }
        catch(e) { }

        if (supportPromises){
            //Firefox
            window.namespace.runtime.sendMessage(message).then(callback);
        }
        else {
            //Edge
            window.namespace.runtime.sendMessage(message, callback);
        }
    }
}
//Global "browser" namespace definition.
window.namespace = (function() {
    return window.browser || window.chrome;
})();

function sendGlobalResponse(message, callback){
    if (window.namespace === window.chrome) {
        //Chrome
        window.namespace.runtime.sendMessage(message, callback);
    }
    else if (window.namespace === window.browser) {
        let returnValue = window.namespace.runtime.sendMessage({});
        if (typeof returnValue === "undefined"){
            //Edge
            window.namespace.runtime.sendMessage(message, callback);
        }
        else {
            //Firefox
            window.namespace.runtime.sendMessage(message).then(callback);
        }
    }
}