Как реализовать обратные вызовы для передачи сообщений в скрипте содержимого расширения браузера «все в одном» (Edge / Firefox / Chrome)? - PullRequest
0 голосов
/ 30 мая 2018

Среда разработки ОС: Windows 7 Enterprise LTS
Минимальные требования к совместимости браузера: Должна поддерживать все браузеры Edge, Firefox, Chrome, начиная с 2018.
Текущая текущая проблема: Невозможно запустить ВМ на рабочей станции разработчика;Невозможно запустить виртуальные машины Windows 10 для отладки расширений Microsoft Edge.

Для объяснения:

  • «Расширение браузера« все в одном »» относится к коду расширения браузера, который использует тот же кодс небольшими отличиями для работы в различных браузерах, поддерживаемых WebExtensions / Chrome Extensions.Как минимум, одна и та же кодовая база должна работать и работать в Edge, Firefox и Chrome с очень незначительными изменениями.
  • Обратные вызовы в скриптах содержимого для расширений Edge / Firefox / Chrome обрабатываются по-разному.
  • По неизвестным причинам я не могу запустить ВМ на своем компьютере рабочей станции.Когда ВМ работает, клиент ВМ черный.С моей стороны это локализованная проблема, которую я не могу решить, поэтому я вынужден найти другое решение / альтернативу.

Как они обрабатываются по-разному в сценариях содержимого:

  • Edge: browser.runtime.sendMessage использует обратные вызовы и возвращает undefined.
  • Firefox: browser.runtime.sendMessage использует обещания и возвращает обещание.
  • Chrome: chrome.runtime.sendMessage использует обратные вызовыи возвращает undefined.

По различным ссылкам:

Расширения Firefox / Chrome / MS Edge с использованием Chrome. * или браузера. *

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

К сожалению, из-за проблемы, с которой я столкнулся (виртуальная машина не работает), я не могу сказать, используется ли 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);
        }
    }
}

Я действительно чувствовал, что это хакерское решение, потому что кодоснованный на исключительных особенностях платформы браузера для разделения вызовов API chrome.runtime.sendMessage и browser.runtime.sendMessage, чтобы обрабатывать обратные вызовы на соответствующих платформах.Я действительно хотел изменить это.

Поэтому я спрашиваю, какие есть лучшие способы, которые полезны для обнаружения различных платформ и для обработки обратных вызовов при передаче сообщенийправильно одновременно?

Заранее спасибо.

1 Ответ

0 голосов
/ 30 мая 2018

Я полагал, что решил это.

РЕДАКТИРОВАТЬ: ФИНАЛЬНАЯ финальная версия (обновлена ​​и более стабильна, меньше сообщений):

//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.

Я думаю, что это единственное решение для обработки обратных вызовов / сообщений, передающих сообщенияответы на скрипты контента.

Я действительно не мог придумать лучшего решения, чем это.Так что теперь я буду использовать это.

Но если кто-то еще знает лучший способ, способ, при котором вам не нужно отправлять 1 дополнительное пустое сообщение для Firefox и Edge на вызов функции, это было бы здорово!

Этоотстой, что что-то внутри скрипта контента не является постоянным, и даже если вы храните информацию о том, на какой платформе запускается код, вам все равно придется извлечь информацию из фонового скрипта, прежде чем отфильтровать, какую функцию runtime.sendMessage вызывать,так что это на самом деле не экономит много времени.

...