Ответ 1
Три разных контекста
В качестве разработчика расширений Chrome вы можете выделить три разных среды.
- Код расширения, выполняемый в процессе расширения Chrome
- Предыстория/страница события
- Действие браузера/действие со страницы
- Страница в информационной панели.
- Вкладки, чей фрейм верхнего уровня - это документ из вашего расширения, например страница параметров.
- Скрипты содержимого, запущенные в процессе табуляции.
- Код без расширения, запущенный в процессе вкладки (введенный скриптами контента).
Обратите внимание, что <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
для отправки сообщения на страницу, но это может привести к конфликту с плохо закодированными страницами, которые не ожидают сообщений.