Pull to refresh

Разработка простого расширения для google chrome

Reading time 6 min
Views 47K
imageРасширения для браузеров очень популярны в наше время. Повод написать какое-либо расширение всегда найдется, и их напашется еще много.

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

Если поискать, то на русском языке нет ничего толкового по разработке расширений для chrome, только лишь эта статья доступно описывает самые основы.

Данный пост будет более продвинутой версией.

Приступим.

Не хочется вдаваться в самые основы и поэтому рекомендую для начала прочесть эту статью.

Скачайте мое расширение и смотрите код параллельно чтению.

Мы уже примерно знаем, что такое manifest.json и для чего он нужен.
Если кратко, то это основной файл расширения, который сообщает браузеру какими вещами расширение будет пользоваться, и основные параметры (название, описание и тд).

Перейдем непосредственно к моему расширению.
Это простой скрипт, который удаляет со страницы фриланса те объявления, которые мешают искать интересные мне объявления (если точнее, то я ищу лишь долгосрочные проекты). Дополнение к существующему встроенному фильтру.

manifest.json

{
  "name":"Ffilter",
  "version": "1.0",
  "background_page": "bg.html",   // имя background страницы.
  "icons": {
    "48":"icon_48.png",
    "128":"icon_128.png"
  },
  "page_action":{      // действие для текущей страницы
    "default_title": "Ffilter",
    "default_icon": "icon_19.png",
    "default_popup":"popup.html"   // имя страницы фильтра
  },
  "permissions": [      // разрешения
    "tabs","http://www.free-lance.ru/*"
  ],
  "content_scripts":[{       // работа с DOM страницы фриланса.
    "matches": ["http://www.free-lance.ru/*"],
    "js": ["jq.js","script.js"]
  }]
}


* This source code was highlighted with Source Code Highlighter.

Рассмотрим.
Имя, версия — это всем понятно.

imagebackground_page — тут должно лежать имя фоновой страницы. Фоновая страницы — очень важный элемент, хотя для некоторых приложений он и не обязателен. Но в нашем случаи без него не обойтись.
Фоновая страницы работает всегда, когда работает расширение (то есть когда оно включено). Она всегда одна и может связываться и управлять всеми остальными элементами.

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

page_action — важный объект. Он сообщает браузеру, что наше расширение будет индивидуально для каждой вкладки, то есть значок будет выводиться в адресной строке, а не на панели (например gmail checker). Такие расширения как gmail checker не считаются индивидуальными, они открываются один раз для всего браузера (для них в манифесте используется вместо объекта page_action объект browser_action, на картинках соответственно).
image    image

default_title, default_icon — название, иконка соответственно.
default_popup — имя html-страницы расширения, которая будет всплывать при нажатии на иконку. Посмотрите предыдущий топик, если не все ясно.

permissions — массив с разрешениями. Нам пригодиться общаться с системным объектом tabs и обращаться к адресу фриланса (имеется в виду не ajax запросы, а js работа со страницей).

content_scripts — важный для нас объект, именно он разрешает пользоваться js на странице фриланса. Мы указываем адрес страницы и указываем js-файлы, которые будут исполнены сразу после загрузки body. Я использую jQuery и определяю свои функции. Порядок имеет значение.
Важно знать, что скрипты расширения не могу видеть объекты/переменные скриптов самой страницы. Это значит, что если у страницы уже есть свой jQuery мы не сможем его использовать, обязательно надо подгрузить свой. Это называется изолированными мирами и это иногда удобно. Скрипты из расширения, конечно же, могут манипулировать DOM.

Идем далее.
Если Вы все верно представили себе то видите, что наше расширение состоит из 3х основных объектов: фоновая страница (одна для всех), окошко с фильтром (для каждой страницы), и скрипты на каждой странице.

Общий алгоритм таков:
Фильтр должен общаться только со скриптом на текущей странице. Скрипт должен только принимать указания от фильтра на текущей странице и исполнять их. И тот и другой не должен общаться с фоновой страницей, но фоновая страница должна контролировать фильтр. Ведь фильтр должен появляться только на странице фриланса. И, кстати говоря, расширение page_action по умолчанию всегда скрыто, и его нужно включать через фоновую страницу, она это и делает когда загружается страница фриланса.
image


bg.html

chrome.tabs.onUpdated.addListener(function(id,info,tab) {
  if(info.url)
    if(/free-lance.ru/.test(info.url))
      chrome.pageAction.show(id);
});  


* This source code was highlighted with Source Code Highlighter.

Приведен только js код (только он и нужен).
chrome.tabs — системный объект с которым приходится больше всего работать, как Вы догадались, он отвечает за вкладки.

Мы вешаем свою функцию на событие onUpdated (обновление вкладки, переход по ссылке). В качестве параметров приходят идентификатор вкладки, информация о обновлении, объект самой вкладки. Нам понадобиться информация — она содержит адрес текущей страницы. Мы проверяем фриланс ли это и если да, то у объекта chrome.pageAction вызываем метод show передавая туда идентификатор этой вкладки.

chrome.pageAction — объект отвечающий за расширения внутри адресной строки, и мы просим показать иконку в нужной нам вкладке (где только что открылся фриланс).

Все действия фоновой страницы окончены, сайт открылся, иконка появилась, теперь можно на нее кликнуть и появится popup.html.

popup.html

Нет смысла разбирать весь код, важно только знать как обратиться из этого окошка к скрипту который ждет на странице, как наладить транспорт?

Вообще, в документации сразу предлагают этот способ:
chrome.tabs.executeScript(null, {code:"alert(‘hello!’)"});

* This source code was highlighted with Source Code Highlighter.

или можно так:
chrome.tabs.executeScript(null, {file : “script.js”});

* This source code was highlighted with Source Code Highlighter.

imageНо подумайте, как туда передавать параметры? Только строковые? (к слову говоря, null — это значит, что мы хотим исполнить скрипт на текущей вкладке)
Это мне подходило, я искал способ передать объекты. И такой способ нашелся, но он был спрятан в документации.
port — специальный объект в chrome, с помощью которого можно общаться от скрипта к фоновой странице и popup, или от фоновой страницы и popup к скрипту.

Что бы подключиться к скрипту нужно соединяться через табы:
var port = chrome.tabs.connect(id);

* This source code was highlighted with Source Code Highlighter.

где id номер нужной вкладки со скриптом. port — возвращенный объект транспорта.

Что бы подключиться к фоновой странице или всплывающему окну нужно обратиться к объекту расширения:
var port = chrome.extension.connect();

* This source code was highlighted with Source Code Highlighter.

Расширение одно — идентификатор указывать не надо.
Прослушивать эти подключения можно одинаково и там и там:

chrome.extension.onConnect.addListener(function(port){
  port.onMessage.addListener(MyFunc);
});


* This source code was highlighted with Source Code Highlighter.

Для чего onMessage станет понятнее позже.

Вернемся к popup.html.
В этом месте я связываюсь со скриптом, который “дежурит” на данной странице.
Для меня стало проблемой то, что нужно указать идентификатор вкладки, а ведь я не знаю этот ИД. Забавно, что нам нужная текущая вкладка, и можно было бы просто послать null вместо номера, но это не пройдет — нужно знать ИД. Как?
Много времени убил на это и сделал вот так:
chrome.windows.getCurrent(function(w){
  chrome.tabs.getSelected(w.id,function(t){
    port = chrome.tabs.connect(t.id);
  })
});


* This source code was highlighted with Source Code Highlighter.

Мы просим сказать какое окно сейчас активно, и нам в callback возвращают объект окна. Далее мы просим сказать текущую вкладку в этом окне и нам ее возвращают тоже в callback. И только тогда мы открываем соединение со скриптом.
Это работает, но мне кажется, что это неправильно — должен быть способ проще.

Когда все данные фильтра собраны, по нажатию на кнопку мы отправляем в этот порт объект с помощью метода:
port.postMessage(obj);

* This source code was highlighted with Source Code Highlighter.

И в этот момент начинает работать script.js

В script.js важно это:

chrome.extension.onConnect.addListener(function(port){
  port.onMessage.addListener(Filtr);
});


* This source code was highlighted with Source Code Highlighter.

Прослушиваем порт и дожидаемся входящего подключения с объектом port.
У этого объекта есть событие onMessage — событие когда сюда присылают сообщение. Мы вешаем свою функцию Filtr, которая примет все аргументы, которые пришлют с помощью port.postMessage() на другом конце. Функция Filtr удалит все объявления, которые указаны в объекте.

Все

Вот и все. Это работает и помогает мне в поиске заработка.
Было сложно разбираться без знания английского.
Надеюсь Вам пригодится.

Документация, расширение.
Tags:
Hubs:
+97
Comments 26
Comments Comments 26

Articles