Подтвердить что ты не робот

Контексты и методы для взаимодействия между действием браузера, фоновыми скриптами и сценариями содержимого хром-расширений?

Я думаю, что хром-расширения в целом довольно просты и очень мощные, но одна вещь, которая меня всегда смущает, - это попытка установить связь между различными script, в которых может работать код. Там код, который запускается при ссылке из "default_popup" страницы действия браузера, кода в свойстве "scripts" "background" и сценариях содержимого.

В каком контексте запускаются скрипты в этих категориях и как каждый может общаться с другими?

4b9b3361

Ответ 1

Три разных контекста

В качестве разработчика расширений Chrome вы можете выделить три разных среды.

  1. Код расширения, выполняемый в процессе расширения Chrome
  2. Скрипты содержимого, запущенные в процессе табуляции.
  3. Код без расширения, запущенный в процессе вкладки (введенный скриптами контента).

Обратите внимание, что <iframe src="chrome-extension://EXTENSIONID/page.htm"> на страницах без расширения используется для обработки как case 2 (скрипты контента), потому что кадр был загружен в процессе непривилегированной табуляции. Поскольку в Chrome 56 были запущены внепроцессные фреймы для расширений, эти страницы обрабатываются процессом расширения, и поэтому они могут использовать один и тот же полный набор API расширений. Это изменение в поведении (использование фреймов расширения для использования привилегированных API расширений) является намеренным.

Доступ к объекту window в процессе расширения

Поскольку весь код расширения работает в одном процессе, он может обращаться к глобальному объекту window. Эта функция не известна, но позволяет напрямую манипулировать объектами JavaScript и DOM в рамках одного процесса расширения. Обычно лучше не использовать этот метод, но вместо этого использовать API-интерфейс передачи сообщений.

// To access the 'window' of a background page, use
var bgWindowObject = chrome.extension.getBackgroundPage();
// To access the 'window' of an event or background page, use:
chrome.runtime.getBackgroundPage(function(bgWindowObject) {
    // Do something with 'bgWindow' if you want
});

// To access the 'window' of the badge popup page (only if it open!!!), use
var popupWindowObject = chrome.extension.getViews({type:'popup'})[0];

// To access the 'window' of the options page (called /options.html), use
var allWindowObjects = chrome.extension.getViews({type:'tab'});
var popupWindowObjects = allWindowObjects.filter(function(windowObject) {
    return windowObject.location.pathname == '/options.html';
});
// Example: Get the 'window' object of the first options page:
var popupWindowObject = popupWindowObjects[0];

Чтобы этот раздел был коротким, я намеренно ограничил пример кода демонстрацией доступа к другим глобальным объектам window. Вы можете использовать эти методы для определения глобального метода, установки глобальной переменной, вызова глобальной функции и т.д.
... при условии, что страница открыта. Кто-то подумал, что всплывающее window всегда доступно. Это неверно, когда всплывающее окно закрыто, глобальный объект удален!

Общение путем передачи сообщений

Канал сообщения всегда имеет два конца: отправитель и получатель.
Чтобы стать получателем, chrome.runtime.onMessage.addListener прослушиватель событий с chrome.runtime.onMessage.addListener метода chrome.runtime.onMessage.addListener. Это можно сделать с помощью кода расширения и сценариев контента.

Чтобы передать сообщения внутри расширения, используйте chrome.runtime.sendMessage. Если вы хотите отправить сообщение на другую вкладку, вызовите chrome.tabs.sendMessage. Целевая вкладка указана путем включения целого числа (tabId) в качестве первого аргумента. Обратите внимание, что справочная страница может отправлять сообщение только на одну вкладку. Чтобы получить доступ ко всем вкладкам, нужно вызвать метод для каждой вкладки. Например:

chrome.tabs.query({}, function(tabs) {
    for (var i=0; i<tabs.length; i++) {
        chrome.tabs.sendMessage(tabs[i].id, "some message");
    }
});

Скрипты содержимого могут вызывать только chrome.runtime.sendMessage для отправки сообщения на код расширения. Если вы хотите отправить сообщение из сценария контента другому сценарию контента, потребуется страница с фоном/событием, которая принимает сообщение и отправляет его на нужную вкладку. См. Этот ответ для примера.

Методы sendMessage принимают необязательную функцию, которая принимается в качестве третьего аргумента для события onMessage.

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    if (message === 'message') sendResponse('the response');
});
chrome.runtime.sendMessage('message', function(response) {
    console('sendResponse was called with: ' + response);
});

Предыдущий пример показывает очевидное поведение. Все становится сложнее, если вы хотите отправить ответ асинхронно, например, если вы хотите выполнить запрос AJAX для получения некоторых данных. Когда функция onMessage возвращается без sendResponse, Chrome немедленно вызовет sendResponse. Поскольку sendResponse можно вызвать только один раз, вы получите следующую ошибку:

Не удалось отправить ответ: слушатель chrome.runtime.onMessage должен вернуть значение true, если вы хотите отправить ответ после возвращения слушателя (сообщение было отправлено по расширению ID расширения)

Сделайте, как подсказывает ошибка, добавьте return true; внутри вашего прослушивателя событий onMessage:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    setTimeout(function() { // Example: asynchronous invocation of sendResponse
        sendResponse('async response');
    }, 200);
    return true;
});

Я объяснил практическое применение простого одноразового сообщения, передаваемого в этом разделе. Если вы хотите узнать больше о долговечных каналах сообщений или обмена сообщениями с расширенным расширением, прочитайте учебное пособие из официальной документации.

API-интерфейс передачи сообщений претерпел несколько изменений имени. Имейте это в виду, если вы читаете старые примеры. Заметки об истории и совместимости можно найти здесь.

Связь между скриптом контента и страницей

Возможно общение со страницей. Apsillers создал отличный ответ, в котором объясняется, как настроить канал связи между страницей (без расширения) и скриптом контента. Прочтите его ответ: может ли сайт ссылаться на расширение браузера? ,

Преимущество метода apsiller над документом в том, что используется пользовательское событие. Документация использует window.postMessage для отправки сообщения на страницу, но это может привести к конфликту с плохо закодированными страницами, которые не ожидают сообщений.

Ответ 2

В документации Google есть все, но сложно собрать всю информацию. Существует два основных типа скриптов:
1. Фоновые сценарии имеют полный доступ к Chrome api, но не могут взаимодействовать с целевой веб-страницей.
2. Скрипты содержимого могут взаимодействовать друг с другом и с веб-страницей DOM (но не с ее скриптами, из которых она изолирована), но имеют ограниченный доступ к Chrome api.
Оба запускаются всякий раз, когда вы загружаете новую страницу (если вы не использовали "совпадения", чтобы ограничивать, где выполняется контент script).

Вы можете общаться между ними через сообщение. Это проще сделать из сценариев контента, чем из фоновых сценариев, потому что вам нужно знать идентификатор вкладки для последнего.

Другие скрипты (browserAction.js, pageAction.js, optionsPage.js) запускаются только при открытии соответствующей страницы html (как если бы вы открывали веб-страницу в окне браузера, что вы действительно делаете). Они похожи на фоновые скрипты в ограничениях и способностях.

Попытайтесь избежать необходимости взаимодействовать со скриптами страниц. Лучший способ, которым я знаю, - взаимодействовать через общий DOM (буквально писать код javascript внутри html комментариев). Но цель вашего расширения не предназначена для этого, поэтому вам придется включить в свой собственный script, который делает это на веб-странице. Используйте содержимое script, чтобы записать элемент script в документ (его src - это chrome.extension.getURL("myscript.js"),
и вам нужно будет иметь "web_accessible_resources": ["myscript.js"]
в вашем манифесте.

Ответ 3

Прошло некоторое время с тех пор, как мне пришлось иметь дело с хромированными расширениями. Я помню, что это была довольно сложная борьба, прежде чем я понял, как все работает. Чтобы ваше расширение поддерживало связь с браузером, вам легко использовать свой файл javascript/background, а для связи с веб-страницей вам нужно использовать chrome.tabs.executeScript, но это очень сложно и может стать настоящей болью в прикладе. Я предлагаю вам принять google tour on extensions и дать их api действительно хороший промах, все там! Желаю вам удачи, и я надеюсь, что этот ответ вам помог!: P