Chrome Extension(расширение)

Это Вам так же может быть интересно!

Делитесь с друзьями в социальных сетях! Оставляйте комментарии!

Share/Save
test

Расширяем Chrome/Chromium

Часто по работе приходиться вкручивать всякого разного. В данном случае понадобилось делать расширение для хрома и собирать информацию по кусочкам.
Не могу не упомянуть хороший блог посвященный расширениям для хрома.
В этом материале я расскажу об основах но чуть больше чем многие введения.
Если вы попали на мой материал то скорее всего уже видели что само расширение состоит из нескольких базовых файлов:
  1. icon.png - иконка расширения
  2. manifest.json - файл с мета-информацией по расширению, такой как название, версия, права расширения, подключаемые файлы и прочее и прочее.
  3. init.js - этот скрипт может называться и по другому, главное его указать в манифесте. Включается в исходные страницы сайтов и расширение может с ним взаимодействовать.
  4. popup.html - так же файл может называться по другому, главное указать его в манифесте. Используется для отображения формы по клику на кнопку экстеншна. Поддерживается любой HTML и JS.
  5. popup.js - подключаемый в всплывающее окно скрипт с нужными функциями. Может отсутствовать или называться по другому. Подключается в самом popup.html как обычный скрипт.

Некоторые особенности расширения:
  1. Изолированность попапа - само расширение работает изолированно от страницы. Другие расширения не видят вашего, ваше не видит других если не сказано иначе. То есть если вы не используете специальную коммуникацию между расширениями. Так же попап не может общаться с init.js(скриптом подключаемым в страницу) напрямую, кроме как через специальные механизму коммуникации между ними. Так же он не видит содержимого страницы, так как изолирован сам по себе.
  2. Изолированность подключаемого на странице скрипта - он видит содержимое страницы, но не видит содержимого расширения. Страница его не видит, так как он в своей песочнице. Так же этот скрипт не видят другие расширения и скрипты. Единственно что страница может обнаружить модификацию DOM, но вряд ли кто таким сильно заморачивается.
Это основы которые нужны для понимания.
manifest.json:
{
  "manifest_version": 2,
  "name": "parser",
  "description": "parser",
  "version": "1.0",
  "browser_action": {
    "default_icon": "icon.png", //иконка    "
    "default_popup": "popup.html" //код самого виджета будет лежать тут
  },
  "permissions": [ //права доступа
    "activeTab","debugger","tabs","pageCapture","http://*/*","https://*/*","background","unlimitedStorage","notifications"  ],//внедряем свой скрипт в код страницы.
  //он будет инициализировать прослушивание поступающих сообщений
  //если получим нужное сообщение, будем запускать нашу функцию
  "web_accessible_resources": [ "icon.png" ],
  "content_scripts": [
    {
    "matches": [ "<all_urls>" ], //совпадения по url, можно использовать регулярные выражения//тег <all_urls> говорит о том что будем вставлять код на всех страницах    "
    "js": ["thirdParty/jquery-3.2.1.min.js","init.js"], //сам файл(ы) который(е) будем вставлять в страницу    "
    "run_at" :"document_end",//вставляем в конец документа    "
    "all_frames": false
  }
  ]
}

в данном случае пункт content_scripts->js указывает какие скрипты в нужном порядке у нас подключаются к странице. Для удобства я использовал jQuery, так как на таких объемах удобство важнее скорости которая все-равно не хромает практически.
popup.html:
<!doctype html>
<head>
    <title>Parser</title>
    <script src="thirdParty/jquery-3.2.1.min.js"></script>
</head>
<body style="width: 300px;">
<h2>Actions:</h2>
<button id="seyMeHello">Parse</button>
<button id="StopWorking" style="display: none">Stop</button>
<script src="popup.js"></script>
<h2>Status:<div id="p_status">Ready</div> <img src="loader.gif" id="loader" style="max-width: 30px"></h2>
</body>
</html>
Если вы работали с html/js/css то проблем вам данный код никак не доставляет. Картинку loader.gif нужно положить внутри расширения, я ее использовал как отображение что происходит какое-либо действие. Так же в шапке видно что я подключаю скрипт jQuery вручную, так как в попап их нужно включать напрямую.

И теперь более сложная часть из двух следующих скриптов, которые должны общаться друг с другом иначе расширение не сможет говорить скрипту на странице что нужно сделать.
popup.js
$(document).ready(function () {
//загрузка завершена, прячем лоадер
    $("#loader").hide();
//пример функции запрашивающей данные с API
//описана ниже
    //getAPIData();
});

//обработчик нашей кнопки
document.getElementById("seyMeHello").addEventListener("click",    function() {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        chrome.tabs.sendMessage(tabs[0].id, {
            action: "sayMe",//переменные которые мы
            text: "Hello!"//отправляем скрипту на странице
        },
            function(response) {
//ответ из скрипта если такой есть
//не советую полагаться на ответ, так как если там выполняется хоть какая-то функция,
//механизм может и не отправить ответ и вы их на этой стороне не получите
                console.log("Ответ получен!",response.answer);
saveTextToStorage('saved!');
        });
    });
}, false);

//здесь используется localStorage расширения, так что
//кроме вашего расширения его никто не видит
function saveTextToStorage(text) {
        localStorage['my_ext_status'] = text;
}
//так можно обратиться к нашему серверу из расширения и получить, например, настройки
function getAPIData(){
  var api_url = "http://someserver.com/api/settings";
  $.post(api_url, { action:'get' }, function (response) {
        localStorage['settings'] = response.settings;
    });
}
В этом файле мы спокойно используем функции jQuery для удобства или обычный JS, либо любую другую библиотеку которую подключили.
Сообщения скрипту таким образом как в коде не гарантируют обратную связь калбеком или чем еще, эта функция спокойно может выполниться не дождавшись ответа. Если Вам нужна функция с обратным ответом то нужно использовать именованные каналы вида:
var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question == "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question == "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});

И с другой стороны получать и отправлять:
chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name == "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke == "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer == "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer == "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});
Но потратив пару-тройку часов этот подход у меня так и не заработал. По этому я на него забил. Оставив только коммуникацию из экстеншна в подключаемый скрипт.
Последний файл из нашего сборища:
init.js
chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        switch (request.action)
        {
            case "sayMe":
              var result = sayMe(request.text);
//функция сохранения в localStorage, описана в коде ниже
              saveTextToStorage(request.text) ;
              saveAPIData(request.text);
              sendResponse({answer: "goodbye",result:result});//callback функция для возврата
//обратно в скрипт popup.js в данном случае, но он не факт что сработает,
//так что callback может получить result == 'undefined'
                break;
        }
        return true;
});

function sayMe(text){
  alert(text);
return true;
}

//здесь используется localStorage для страницы и домена, так что
//можно через него общаться со скриптами на странице
//как вариант
function saveTextToStorage(text) {
        localStorage['my_ext_text'] = text;
}
//так же можно обратиться к API со страницы и сохранить, например текст
function saveAPIData(text){
  var api_url = "http://someserver.com/api/settings";
  $.post(api_url, { action:'save',data:text }, function (response) {
        console.log(response);
    });
}

Практически все что доступно на обычных страницах, так же доступно и здесь. Самым большим ограничением является именно коммуникация между плагином(popup.js) и внедряемым на страницу скриптом(init.js). Так же API механизма расширений позволяет делать еще много других любопытных вещей непосредственно с браузером, но это вы уже можете поискать сами.

Несколько дополнительных моментов:
  1. Чтобы включить расширение нужно зайти в браузере на страницу расширений через меню или ссылку chrome://extensions/
    поставить галочку "Режим разработчика"
    нажать "Загрузить распакованное расширение" и выбрать папку с вашим расширением.
  2. Чтобы делать расширение я предполагаю что вы уже знакомы с Developer Tools(F12). Для расширения он так же вызывается но для этого вы кликаете по расширению, всплывает ваш попап и на элементе вы нажав правой кнопкой мыши выбираете "Просмотреть код". После этого у вас открывается Developer Tool для расширения и вы пользуетесь им привычным вам способом.
  3. Подсказки вы можете посмотреть в других расширениях так же вызвав само расширение и Developer Tools, кликаете на попапе "Просмотреть код" и на вкладке Sources можете увидеть содержимое плагина.
Категория: 
Share/Save