Расширение Chrome - получение глобальной переменной со страницы
Я работаю над расширением для Chrome. Я хочу проанализировать содержание "оригинального" сообщения Gmail (в настоящее время просматриваемого сообщения).
Я попытался использовать jQuery.load() следующим образом
$(windows).load(function() { alert(GLOBALS); });
и поместите его в скрипт контента, но он тоже не работает. Я использую инструменты разработчика Chrome, который возвращает следующую ошибку при вызове alert(GLOBALS);
Uncaught ReferenceError: GLOBALS не определен
Хотя, при использовании консоли инструментов разработчиков, набрав в консоли GLOBALS
он возвращает массив.
Любая подсказка, как получить доступ к GLOBALS из скрипта контента?
4 ответа
Сценарии содержимого выполняются в изолированной среде. Чтобы получить доступ к любым глобальным свойствам (из страниц window
), вы должны либо ввести новый <script>
элемент или использовать прослушиватели событий для передачи данных.
Посмотрите этот ответ, например, о введении <script>
элемент в контексте страницы.
пример
contentcript.js ("run_at": "document_end"
в манифесте):
var s = document.createElement('script');
s.src = chrome.extension.getURL('script.js');
(document.head||document.documentElement).appendChild(s);
s.onload = function() {
s.remove();
};
// Event listener
document.addEventListener('RW759_connectExtension', function(e) {
// e.detail contains the transferred data (can be anything, ranging
// from JavaScript objects to strings).
// Do something, for example:
alert(e.detail);
});
script.js
- Расположенный в каталоге расширений, он будет вставлен в саму страницу:
setTimeout(function() {
/* Example: Send data from the page to your Chrome extension */
document.dispatchEvent(new CustomEvent('RW759_connectExtension', {
detail: GLOBALS // Some variable from Gmail.
}));
}, 0);
Поскольку этот файл загружается через расширение Chrome: URL из DOM, необходимо добавить "script.js" в раздел web_accessible_resources файла манифеста. В противном случае Chrome откажется загружать файл скрипта.
Вы должны использовать как можно меньше логики на веб-странице и обрабатывать большую часть своей логики в скрипте контента. Это имеет несколько причин. Прежде всего, любой сценарий, внедренный на странице, работает в том же контексте, что и веб-страница, поэтому веб-страница может (преднамеренно или непреднамеренно) изменять методы JavaScript/DOM таким образом, что ваше расширение перестает работать. Во-вторых, у скрипта контента есть доступ к дополнительным функциям, таким как ограниченное подмножество API-интерфейсов chrome. * И сетевые запросы разных источников (при условии, что расширение объявило разрешения для них).
Более современным решением для связи между расширением chrome content_script и javascript на странице было бы использование html5 postMessage API. Любые сообщения, отправленные в "окно", видны как из javascript на веб-странице, так и из content_script расширения.
Расширение content_script.js:
window.addEventListener('message', function(event) {
console.log('content_script.js got message:', event);
// check event.type and event.data
});
setTimeout(function () {
console.log('cs sending message');
window.postMessage({ type: 'content_script_type',
text: 'Hello from content_script.js!'},
'*' /* targetOrigin: any */ );
}, 1000);
Javascript работает на веб-странице:
window.addEventListener('message', function(event) {
console.log('page javascript got message:', event);
});
setTimeout(function() {
console.log('page javascript sending message');
window.postMessage({ type: 'page_js_type',
text: "Hello from the page's javascript!"},
'*' /* targetOrigin: any */);
}, 2000);
Также см. http://developer.chrome.com/extensions/content_scripts.html
Существует новый API для веб-страниц для безопасного и без побочных эффектов (у window.postMessage могут быть другие слушатели!) Сценария содержимого.
"На веб-странице используйте API-интерфейсы runtime.sendMessage или runtime.connect для отправки сообщения определенному приложению или расширению"
// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
function(response) {
if (!response.success)
handleError(url);
});
"Из вашего приложения или расширения вы можете прослушивать сообщения с веб-страниц через API runtime.onMessageExternal или runtime.onConnectExternal, аналогичные обмену сообщениями между расширениями. Только веб-страница может инициировать соединение. [...]"
(с http://developer.chrome.com/extensions/messaging.html) Это все еще доступно только в канале разработчиков Chrome, но, похоже, будет в следующей версии или около того.
Не спрашивайте меня, как это работает, это кажется очень запутанным. Как на самом деле chrome.runtime определяется на веб-странице? Что, если сценарий уже определил эту переменную по какой-то причине? Я также не смог найти отчет об ошибке хрома, чтобы увидеть историю развития этой функции.
Добавьте в свой контент сценарий:
function executeOnPageSpace(code){
// create a script tag
var script = document.createElement('script')
script.id = 'tmpScript'
// place the code inside the script. later replace it with execution result.
script.textContent =
'document.getElementById("tmpScript").textContent = JSON.stringify(' + code + ')'
// attach the script to page
document.documentElement.appendChild(script)
// collect execution results
let result = document.getElementById("tmpScript").textContent
// remove script from page
script.remove()
return JSON.parse(result)
}
Теперь вы можете:
let window = executeOnPageSpace('window')
или даже так:
executeOnPageSpace('window.location.href = "http://stackru.com"')
ПРИМЕЧАНИЕ. Я не тестировал это для длительного кода.
У меня был немного другой подход, основанный на доступных HTML-страницах вашего расширения.
Добавьте свою страницу в манифест:
"web_accessible_resources": ["variables.html"]
Создайте свою страницу (здесь, variables.html) и извлеките данные содержимого (например, window.contentVar):
<script type="text/javascript">
$("#my-var-name").text(window["contentVar"]);
</script>
<div id="my-var-name" style="display: none;"></div>
Доступ из JavaScript вашего расширения:
var myVarName = $("#my-var-name").text();