Внедрение Javascript-кода в страницу через Chrome Extension

Однажды передо мной встала задача написать расширение для одной браузерной игрушки под Google Chrome.
Для расширения необходимо было использовать javascript окружение непосредственно самой страницы. Проблема оказалась в том, что доступ к этому окружению невозможен из Content-скриптов расширения.

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

Идея основана на копировании содержимого файла скрипта непосредственно в тег
 страницы. Несмотря на всю простоту решения, я не нашел никаких примеров, либо упоминаний о нем на тот момент.

Итак состав нашего будущего расширения таков:
  • manifest.json - стандартный файл описания расширения
  • background.js - content script, загружающий внедряемый код
  • injected.js - непосредственно внедряемый код
  • jquery.js - используется для получения содержимого файла скрипта через ajax. Подробную информацию можно найти на сайте jquery.com


Рассмотрим подробнее содержимого каждого из файлов:

manifest.json

{ "name": "JS Code Injection", "version": "1.0", "manifest_version": 2, "content_scripts": [ { "matches": [ "http://extension.target.url" ], "js": [ "jquery.js", "background.js" ], "run_at": "document_end" } ], "web_accessible_resources": [ "/injected.js" ] }


Ничем не отличается от manifest-файла из примеров.
Обратите внимание, что файл с внедряемым кодом injected.js описан в разделе web_accessible_resources, для того чтобы позднее получить к нему доступ из content-скрипта.

injected.js

function injected_main() {
	alert('Injected!');
}


Внедряемый файл содержит все то, что вы хотите включить в страницу. Здесь вы уже можете использовать локальное javascript окружение страницы, в которую вы внедряете код.

background.js

$.get(chrome.extension.getURL('/injected.js'), 
	function(data) {
		var script = document.createElement("script");
		script.setAttribute("type", "text/javascript");
		script.innerHTML = data;
		document.getElementsByTagName("head")[0].appendChild(script);
		document.getElementsByTagName("body")[0].setAttribute("onLoad", "injected_main();");
	}
);


  1. Мы используем стандартную функцию Chrome Extension API chrome.extension.getURL(), которая возвращает путь, локальный для расширения.
  2. Далее мы запрашиваем данный файл через ajax и после успешного получения создаем новый элемент в основной странице (Благодаря Shared DOM мы можем манипулировать элементами страницы без лишних усилий)
  3. Последним пунктом мы устанавливаем функцию, которая будет вызвана после загрузки страницы (функция injected_main() описана в файле injected.js)


Вот собственно и все. Достоинством данного метода я считаю простоту в реализации (минимум лишнего кода), а главное - вы можете легко редактировать внедряемый код. Для отображения изменений необходимо просто перезагрузить страницу - обновленный injected.js будет сразу подхвачен расширением.
  • +5
  • 52,7k
  • 8
Поделиться публикацией
Похожие публикации
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 8
  • +2
    Я, когда писал первое расширение, тоже заметил что нет доступа к местным функциям. Поэтому просто зааппендил в боди и стал писать дальше. Даже мысли не было, что это целое «Внедрение Javascript-кода в страницу», просто очевидное решение
    • –1
      Есть ещё вариант — написать в строке браузера js —
      добавить его в избранное, и при заходе на произвольную страницу кликнуть :)
      • 0
        Это да, но extension здесь не обязательно, достаточен обычный юзерскрипт. Пример можно найти в юзерскрипте HabrAjax — там сделана кроссбраузерная подгрузка виджета reformal.ru на страницы Хабра. Без jQuery. Искать в коде слова «добавление виджета reformal.ru для отправки багрепортов». В общем, принцип тот же самый — подгружаем сторонний скрипт html-инклудом. При надобности это же делается и с кодом из самого юзерскрипта (пример там же, всё в кроссбраузерной функции addJs).

        Связано с тем, что у Chrome window для юзерскрипта сделано иное, чем для остальных обычных скриптов.
        • +2
          Мини хинт — почти все современные браузеры поддерживают querySelector/querySelectorAll методы:
          document.querySelector('head').appendChild(script);
          document.querySelector("body").addEventListener('load', injected_main, false);
          
          • 0
            Даже проще, кроме очевидного document.body многие современные браузеры поддерживают document.head.

            document.head.appendChild(script);
            document.body.setAttribute("onLoad", "injected_main();");
            
            • 0
              Фактически, согласно MDN, document.head поддерживают все современные бразуеры: Chrome 4+, Firefox 4+, IE9+, Opera 11.0+, Safari 5.0+.
              • 0
                Это очевидно, просто люди которые из jquery не вылазят практически никогда, зачастую даже не слышали о querySelector, а он работает даже с IE8.
                И тут вопрос больше не в сокращении кода, а в правильности кода. Работать с DOM через BOM-ссылки по-моему не очень корректно, смазывается абстракция.
            • 0
              Вот зачем, зачем тут jQuery? Вы заведомо знаете что скрипт будет запускаться из Chrome, где есть абсолютно все, что нужно. Нет, вы тянете за собой монструозную библиотеку, которая будет загружаться, инициализироваться, производить кучу проверок на поддерживаемые браузером фичи, тратите память пользователя, просто ради того, чтобы сделать $.get
              Это очень грустно :(

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.