Сообщения, проходящие через API для передачи расширений, всегда сериализуются в формате JSON. Этот формат используется не только для передачи сообщений между фоновой страницей и сценариями содержимого, но и с родные приложения. Итак, я предполагаю, что маловероятно, что API-интерфейсы передачи сообщений поддерживают больше элементов.
Запрос на алгоритм структурированного клонирования (более мощный, чем JSON-сериализация, менее мощный, чем передаваемые данные) был запрошен еще в 2012 году (Ошибка Chromium 112163). Вопрос все еще открыт; кто-то предложил использовать ссылку SharedWorker
как "батут".
На SharedWorker
влияет одна и та же политика происхождения, поэтому вызывающие абоненты должны находиться в одном и том же источнике. Для этого вы можете добавить страницу в web_accessible_resources
и встроить эту страницу в рама.
В конце этого ответа я прикрепил голую реализацию батута. Создайте расширение с этими файлами. Затем откройте вкладку. Эта вкладка будет содержать встроенный фрейм, а демонстрация отправит сообщение общему воркеру. Это сообщение будет перенесено на фоновую страницу, просто просмотрите консоль фоновой страницы, чтобы увидеть эти сообщения.
Демонстрация минимальна, вам нужно реализовать управление портами (уничтожение) самостоятельно.
В демо-версии нет используйте передаваемую передачу сообщений (пока), потому что это общая реализация, которая допускает несколько портов. Если вы гарантируете, что одновременно существует не более двух портов, вы можете изменить код, чтобы использовать передаваемые объекты (передаваемые объекты имеют смысл только тогда, когда есть один полученный и один отправитель, поскольку право собственности на объект также передается).
Особый случай: тот же процесс
Если весь ваш код выполняется в одном процессе, вы можете использовать более простой подход без SharedWorker
s.
Одна и та же политика происхождения запрещает прямой доступ из/к фрейму и расширению, поэтому вы будете использовать parent.postMessage
, чтобы пересечь этот мост. Затем в событии onmessage страницы вы можете использовать chrome.extension.getViews
для получить прямую ссылку на объект window
одной из ваших страниц расширения (например, всплывающую страницу, страницу параметров и т. д.).
С других страниц chrome.extension.getBackgroundPage()
дает ссылку на объект window
фоновой страницы (для страница событий, используйте chrome.runtime.getBackroundPage(callback)
).
Если вы хотите соединить два фрейма, используйте API обмена сообщениями канала (см. спецификация whatwg и статья разработчиков Opera а>). С помощью этого метода вы установите прямую связь между фреймами, даже если они расположены в разных источниках!
Пример: батут
worker.js
var ports = [];
onconnect = function(event) {
var port = event.ports[0];
ports.push(port);
port.start();
port.onmessage = function(event) {
for (var i = 0; i < ports.length; ++i) {
if (ports[i] != port) {
ports[i].postMessage(event.data);
}
}
};
};
trampoline.js
var worker = new SharedWorker(chrome.runtime.getURL('worker.js'));
worker.port.start();
// Demo: Print the message to the console, and remember the last result
worker.port.onmessage = function(event) {
console.log('Received message', event.data);
window.lastMessage = event.data;
};
// Demo: send a message
worker.port.postMessage('Hello');
trampoline.html
<script src="trampoline.js"></script>
contentscript.js
var f = document.createElement('iframe');
f.src = chrome.runtime.getURL('trampoline.html');
f.hidden = true;
(document.body || document.documentElement).appendChild(f);
manifest.json
Примечание. Я поставил trampoline.js
в качестве фонового сценария, чтобы сэкономить место в этом ответе. С точки зрения веб-работника не имеет значения, кто инициировал сообщение, поэтому я повторно использовал код для отправки и получения сообщений (в конце концов, это простая демонстрация!).
{
"name": "Trampoline demo",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["trampoline.js"],
"persistent": true
},
"content_scripts": [{
"js": ["contentscript.js"],
"matches": ["<all_urls>"]
}],
"web_accessible_resources": [
"trampoline.html"
]
}
13.01.2014
document.head/body || document.documentElement
. Почему частьdocumentElement
? 14.01.2014document_start
,document.head/body
обычно равноnull
.document.head/body
всегда равноnull
в некоторых документах (например, SVG). Но у всех документов есть корень, поэтому я добавляюdocument.documentElement
как запасной вариант. 14.01.2014f.style = "display: none !important;"
может быть более надежным способом скрыть кадр вместоf.hidden = true
. Если на странице есть CSS типаiframe { display: block; }
, то атрибутhidden
не поможет. 25.04.2016trampoline.html
. 25.04.2016