代码之家  ›  专栏  ›  技术社区  ›  tom_mai78101

如何在一体化(edge/firefox/chrome)浏览器扩展的内容脚本中实现消息传递回调?

  •  1
  • tom_mai78101  · 技术社区  · 6 年前

    开发环境操作系统: Windows 7企业版LTS
    浏览器兼容性最低要求: 自2018年起,应支持所有Edge、Firefox、Chrome浏览器。
    当前正在进行的问题:

    解释:

    • “一体式浏览器扩展”是指使用相同的代码,但有细微差别的浏览器扩展代码,用于支持各种webextensions/chrome扩展的浏览器。至少,相同的代码库应该可以在edge、firefox和chrome上工作和运行,并且只需要很小的更改。
    • 回拨 内容脚本 对于edge/firefox/chrome扩展,处理方式不同。
    • 由于未知原因,我无法在工作站计算机上运行vm。当虚拟机运行时,虚拟机客户端为黑色。这是我这边的一个本地化问题,我无法解决,所以我不得不找到另一个解决方案/替代方案。

    如何在内容脚本上以不同的方式处理它们:

    • 边缘: browser.runtime.sendMessage 使用回调,并返回 undefined .
    • 火狐: browser.runtime.sendmessage浏览器 使用承诺,并返回承诺。
    • 铬: chrome.runtime.sendMessage 使用回调,并返回 未定义 .

    根据各种参考资料:

    Firefox / Chrome / MS Edge extensions using chrome.* or browser.*

    https://www.smashingmagazine.com/2017/04/browser-extension-edge-chrome-firefox-opera-brave-vivaldi/

    在内容脚本中,您可以在顶部声明以下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调用,以便在各自的平台中处理回调。我 真的? 想改变这个。

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

    提前谢谢。

    1 回复  |  直到 6 年前
        1
  •  1
  •   tom_mai78101    6 年前

    我相信我解决了。

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

    //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);
            }
        }
    }
    

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

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

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

    但是如果其他人知道更好的方法,一种不需要为每个函数调用发送一条额外的firefox和edge伪消息的方法,那就太好了!

    很糟糕的是,内容脚本中的任何内容都不是持久的,即使您存储了有关代码在哪个平台上运行的信息,在筛选出 runtime.sendMessage 要调用的函数,因此不会真正节省太多时间。

    推荐文章