Работа с расширениями Google Chrome
Russian (Pусский) translation by Yuri Yuriev (you can also view the original English article)
Не скрою, Google Chrome мой любимый браузер. Мне нравится его надёжность и скорость, он не падает (очень часто) и хорошо смотрится. Есть у него и другие достоинства. Факт, что расширения для него можно построить только на HTML, CSS и JavaScript. Я всегда поддерживаю продукты, которые открыты для сообщества и Chrome является одним из них. Если вам нужно то, чего ещё нет, вы можете разработать это самостоятельно.
В конце этой статьи вы найдёте действующее расширение Chrome, которое использует большинство методов, описанных ниже. Вы можете загрузить окончательный пример по кнопке загрузки в верхней части этой страницы.
Зачем писать своё собственное расширение
Я призываю всех использовать лучшие инструменты для ускорения рабочего процесса. Программное обеспечение должно нам помогать, мы не должны с ним бороться. Разработка расширений/плагинов для вашего редактора или браузера помогает не только вам, но и другим программистам, которые рано или поздно окажутся в той же ситуации. Любое упущение можно восполнить самостоятельно, а с Chrome это будет очень просто. Моделирование среды вокруг ваших потребностей является ключом к высокопроизводительной работе.
Разработка и тестирование ваших расширений
К счастью, есть способ протестировать расширение, не загружая его в интернет-магазин Chrome. В адресной строке вашего браузера введите:
chrome://extensions
Убедитесь, что вы выбрали Developer mode и нажмите кнопку Load unpacked extension... И выберите папку с жёсткого диска, которая содержит файлы расширений.



Архитектура
Вот диаграмма архитектуры расширения Chrome:



Теперь давайте рассмотрим каждый элемент архитектуры.
Декларация (Manifest)
Точкой входа расширения является файл manifest.json. Он должен содержать действительный объект JSON. Например:
{ "name": "BrowserActionExtension", "version": "0.0.1", "manifest_version": 2, "browser_action": { "default_title": "That's the tool tip", "default_popup": "popup.html" } }
Его свойствами будут name
, version
и manifest_version
. version
может быть от одного до четырёх целых чисел, разделённых точками. Она используется системой автообновления Google. Так он узнаёт, когда обновлять ваше расширение. Значение manifest_version
должно быть целым числом 2
.
В манифесте могут содержаться другие свойства, в зависимости от того, какое расширение вам нужно, но я опишу только те, которые считаю более интересными.
Background Pages (фоновые страницы)
У каждого расширения есть невидимая справочная страница, которая запускается браузером. Существует два типа: постоянные фоновые страницы и страницы событий. Первые активны постоянно. Вторые только по необходимости. Google поощряет разработчиков использовать страницы событий, поскольку это экономит память и улучшает общую производительность браузера. Тем не менее, надо знать, что это место, где вы должны поместить основной алгоритм и инициализацию. Обычно background page/script играет роль моста между другими частями расширения.
Вот как вы должны описать это в manifest:
"background": { "scripts": ["background.js"], "persistent": false/true }
Как вы могли догадаться, если persistent
свойство является false
, вы используете event pages. В противном случае вы работаете с постоянной фоновой страницей.
Content Script (скрипт контента)
Если требуется доступ к DOM текущей страницы, вам нужно использовать content script. Код запускается в контексте текущей веб-страницы, что означает, что он будет выполнен при каждом обновлении. Для добавления скрипта используйте следующий синтаксис.
"content_scripts": [ { "matches": ["https://*/*", "https://*/*"], "js": ["content.js"] } ]
Имейте в виду, что значение matches
определяет, для каких страниц будет использован ваш скрипт. Подробней об этом matches patterns here.
User Interface (интерфейс пользователя)
Есть несколько путей построения UI вашего расширения. Вот четыре самых известных.
Browser Action
Для создания плагинов большинство разработчиков пользуется browser_action
. После его установки значок, обозначающий расширение, будет помещён в правую часть адресной строки. Щёлкнув по значку пользователи могут открыть всплывающее окно, которое на самом деле является содержимым HTML-контента.



Данные файла manifest должны содержать следующее:
"browser_action": { "default_icon": { "19": "icons/19x19.png", "38": "icons/38x38.png" }, "default_title": "That's the tool tip", "default_popup": "popup.html" }
default_title
содержит подсказку, которая отображается, когда пользователь указывает на значок. default_popup
- это фактически файл HTML, который загружается внутри всплывающего окна. Существует также значок, который вы можете разместить над своей иконой. Вы можете сделать это внутри background script. Например:
chrome.browserAction.setBadgeText({text: "yeah"});
Это код для создания изображения выше.
Page Action
Свойство page_action
похоже на browser action, но значок отображается внутри адресной строки:



Интересно, что ваш значок сначала скрыт, поэтому вы должны решить, когда его показывать. Например, на изображении значок RSS будет отображаться только в том случае, если текущая страница содержит ссылку на RSS-канал. Если вам нужно постоянно видеть значок, используйте browser_action
напрямую.
Чтобы добавить page action, пропишите следующий код в manifest:
"page_action": { "default_icon": { "19": "images/icon19.png", "38": "images/icon38.png" }, "default_title": "Google Mail", "default_popup": "popup.html" }
В отличие от browser action, page action значка не имеет.
DeveloperTools
Я много использую DeveloperTools и хорошо, что у Chrome есть метод пополнения этих инструментов. Во-первых, вам нужно добавить HTML-страницу, которая будет загружена при открытии панели:
"devtools_page": "devtools.html"
Не нужно помещать HTML-код внутри страницы, кроме ссылки в файле JavaScript, который будет создавать вкладку:
<script src="devtools.js"></script>;
Затем добавьте следующий код внутри файла devtools.js
:
chrome.devtools.panels.create( "TheNameOfYourExtension", "img/icon16.png", "index.html", function() { } );
Теперь этот код добавит новую вкладку с именем TheNameOfYourExtension
, и как только вы нажмете на неё, браузер загрузит index.html
внутри DeveloperTools.
Omnibox
omnibox
- это ключевое слово, которое отображается внутри адресной строки Chrome. Например, при добавлении в manifest следующего свойства:
"omnibox": { "keyword" : "yeah" }
А затем добавьте следующий код в свой background script:
chrome.omnibox.onInputChanged.addListener(function(text, suggest) { suggest([ {content: text + " one", description: "the first one"}, {content: text + " number two", description: "the second entry"} ]); }); chrome.omnibox.onInputEntered.addListener(function(text) { alert('You just typed "' + text + '"'); });
Вы должны иметь возможность ввести yeah
в адресную строку. Затем вы увидите следующее:



Нажатие на вкладку приведёт к появлению экрана:



Конечно, используя API chrome.omnibox
, вы можете поймать вход пользователя и отреагировать на него.
APIs
Есть множество разных вещей, которые вы можете сделать в своём расширении. Например, получить доступ к закладкам или истории пользователя. Вы можете перемещать, создавать вкладки или даже изменять размер главного окна. Я настоятельно рекомендую изучить documentation, чтобы лучше понять, как выполнить эти задачи.
Вы должны знать, что не все API доступны в каждой части вашего расширения. Например, ваш content script не получит доступ к chrome.devtools.panels
или скрипт на вкладке DeveloperTools не прочитает DOM страницы. Поэтому не удивляйтесь, если что-то не работает.
Messaging (обмен сообщениями)
Как я уже упоминал, у вас не будет доступа ко всем API, которые вы хотите использовать. В таком случае вы должны использовать передачу сообщений. Существует два типа сообщений - одноразовые запросы и долгоживущие соединения.
One-Time Requests (одноразовые запросы)
Этот тип связи на один раз. То есть, вы отправляете сообщение и ждёте ответа. Например, вы можете поместить следующий код в свой background script:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { switch(request.type) { case "dom-loaded": alert(request.data.myProperty); break; } return true; });
Затем используйте код ниже в вашем content script:
window.addEventListener("load", function() { chrome.extension.sendMessage({ type: "dom-loaded", data: { myProperty: "value" } }); }, true);
Так вы можете получить информацию о DOM текущей страницы и использовать её в своём фоновом скрипте, который обычно не имеет доступа к этим данным.
Long-Lived Connections (долгоживущие соединения)
Это тип сообщений, если вам нужен постоянный канал связи. Внутри content script пропишите следующий код:
var port = chrome.runtime.connect({name: "my-channel"}); port.postMessage({myProperty: "value"}); port.onMessage.addListener(function(msg) { // do some stuff here });
А в background script используйте это:
chrome.runtime.onConnect.addListener(function(port) { if(port.name == "my-channel"){ port.onMessage.addListener(function(msg) { // do some stuff here }); } });
Override Pages (переопределить страницы)
Переопределение страниц хороший способ настройки браузера. Вы также можете заменить в Chrome некоторые страницы по умолчанию. Например, создать свою собственную страницу истории. Для этого добавьте следующий фрагмент кода:
"chrome_url_overrides" : { "<page to override>;": "custom.html" }
Возможными значениями для <page to override>
будут bookmarks
, history
и newtab
. Здорово, если у вас есть свежая страница new tab
.
Пример расширения
В завершение я решил включить простой пример, чтобы вы могли лучше понять всю картину. В этом примере используется большинство вещей, которые я описал, чтобы установить цвет фона # F00
для всех разделов на текущей странице. Не стесняйтесь загрузить исходный код по кнопке в верхней части этой статьи.
Файл manifest
Начинаю с файла manifest:
{ "name": "BrowserExtension", "version": "0.0.1", "manifest_version": 2, "description" : "Description ...", "icons": { "16": "icons/16x16.png", "48": "icons/48x48.png", "128": "icons/128x128.png" }, "omnibox": { "keyword" : "yeah" }, "browser_action": { "default_icon": { "19": "icons/19x19.png", "38": "icons/38x38.png" }, "default_title": "That's the tool tip", "default_popup": "browseraction/popup.html" }, "background": { "scripts": ["background.js"], "persistent": false }, "chrome_url_overrides" : { "newtab": "newtab/newtab.html" }, "content_scripts": [{ "matches": ["http://*/*", "https://*/*"], "js": ["content.js"] }], "devtools_page": "devtools/devtools.html" }
Обязательно нужно упорядочить файлы в папках. Обратите внимание на свойство version
. Вы должны обновлять его каждый раз при загрузке расширения в веб-магазин.
Background Script
// omnibox chrome.omnibox.onInputChanged.addListener(function(text, suggest) { suggest([ {content: "color-divs", description: "Make everything red"} ]); }); chrome.omnibox.onInputEntered.addListener(function(text) { if(text == "color-divs") colorDivs(); }); // listening for an event / one-time requests // coming from the popup chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { switch(request.type) { case "color-divs": colorDivs(); break; } return true; }); // listening for an event / long-lived connections // coming from devtools chrome.extension.onConnect.addListener(function (port) { port.onMessage.addListener(function (message) { switch(port.name) { case "color-divs-port": colorDivs(); break; } }); }); // send a message to the content script var colorDivs = function() { chrome.tabs.getSelected(null, function(tab){ chrome.tabs.sendMessage(tab.id, {type: "colors-div", color: "#F00"}); // setting a badge chrome.browserAction.setBadgeText({text: "red!"}); }); }
Первые несколько строк отражают активность пользователя в omnibox. После этого я устанавливаю одноразовый запрос, который будет принимать сообщение по значку browser action.
Следующий фрагмент представляет собой долговременную связь с вкладкой devtools (для этого не обязательно использовать long-lived connection, я сделал это только для образовательных целей). Используя прослушку, я могу получить ввод пользователя и отправить на content script, который имеет доступ к элементам DOM. Ключевым моментом здесь был выбор вкладки, которой я хотел управлять, а затем отправить ей сообщение. Наконец, я поместил бейдж на значок расширения.
Browser Action
Займёмся нашим popup.html
файлом:
// popup.html <script type="text/javascript" src="popup.js"></script> <div style="width:200px"> <button id="button">Color all the divs</button> </div>
Затем создадим файл popup.js
:
// popup.js window.onload = function() { document.getElementById("button").onclick = function() { chrome.extension.sendMessage({ type: "color-divs" }); } }
Окно содержит кнопку и как только пользователь нажимает на неё, уходит сообщение в background script.
DeveloperTools
window.onload = function() { var port = chrome.extension.connect({ name: "color-divs-port" }); document.getElementById("button").onclick = function() { port.postMessage({ type: "color-divs"}); } }
Для DeveloperTools мы делаем почти то же самое, что и во всплывающем окне, единственное отличие в том, что используется долговременное соединение.
Content Script
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) { switch(message.type) { case "colors-div": var divs = document.querySelectorAll("div"); if(divs.length === 0) { alert("There are no any divs in the page."); } else { for(var i=0; i<divs.length; i++) { divs[i].style.backgroundColor = message.color; } } break; } });
Скрипт содержимого прослушивает сообщение, выбирает все div на текущей странице и меняет цвет фона. Обратите внимание на объект, к которому я прикреплял listener. В content script это chrome.extension.onMessage
.
Настройка страницы New Tab
Последнее, что делает это расширение, настройка страницы new tab
. Мы можем сделать это просто, указав свойство newtab
в файле newtab/newtab.html
:
"chrome_url_overrides" : { "newtab": "newtab/newtab.html" }
Имейте в виду, это не будет репликой new tab
по умолчанию. Идея этой функции заключается в добавлении совершенно другой функциональности. Вот, что сказано в Google:
Не пытайтесь переделывать страницу New Tab. API для изменения версии страницы New Tab - с верхними страницами, недавно закрытыми страницами, советами, фоновым изображением темы и т. д. - пока не существует. Пока этого нет, вам лучше попытаться сделать нечто иное.
Debugging (отладка)
При написании расширения для Google Chrome вы, вероятно, столкнётесь с некоторыми проблемами. Хорошо, что вы можете использовать консоль для вывода переменных, чтобы помочь в её отладке. Добавляйте console.log
в ваши background или content scripts. Однако это не будет работать в скриптах, которые запускаются в контексте инструментов разработчика, используйте метод alert
, который работает везде.
Заключение
На мой взгляд, Chrome - один из лучших браузеров. Разработчики в Google облегчают нам создание расширений, предоставляя возможность делать их в HTML, CSS и JavaScript.
Да, не без сложностей, но, как правило, мы можем создавать ценные плагины. Имейте в виду, что эта статья не охватывает всё, что связано с разработкой расширений Chrome. Существуют и другие полезные функции, такие как context menus, options pages и notifications. За более детальной информацией обращайтесь в documentation.