Přejít k navigační liště

Zdroják » Webdesign » Vytváříme rozšíření pro prohlížeč Chrome

Vytváříme rozšíření pro prohlížeč Chrome

Články Webdesign

Uživatelé tráví s prohlížečem stále víc času, a to nejen při surfování a hledání informací, ale i při posílání mailů, chatování, správě dokumentů,… Prohlížeč se stává aplikační platformou a rozšíření nabízí významné vylepšení jeho funkčnosti. Pojďme se podívat, jak takové rozšíření pro prohlížeč Chrome vypadá.

Snad každý používaný prohlížeč umožňuje nějakým způsobem přidat moduly, které rozšiřují jeho funkce. Původně se tvůrci prohlížečů snažili nabídnout co nejvíc funkcí v rámci vlastního prohlížeče – včetně mailového klienta a všemožných funkcí. S prohlížečem Firefox se začal prosazovat trend odlehčeného prohlížeče, který neřeší vše sám, ale místo toho nabízí silné API pro rozšíření.

Velká část popularity Firefoxu jde na vrub právě možnosti rozšířit prohlížeč o doplňky dle vlastního výběru a potřeb. Vlastní systém rozšíření nabízí Opera, podobné nástroje fungují i v Safari 5, nabízí je i Internet Explorer (i když tam nejsou tak snadno spravovatelné), a nabízí je i prohlížeč Google Chrome.

Widgets, addons, extensions, BHO…

Každý prohlížeč používá vlastní systém doplňků, vlastní API pro doplňky, a dokonce i vlastní názvosloví, nekompatibilní s ostatními prohlížeči. Určitým extrémem je v tomto směru Internet Explorer, který implementuje rozšíření jako klasické binární .dll knihovny. Vzhledem k tomu, že IE je vázán na prostředí OS Windows, nepředstavuje to problém. (O tvorbě rozšíření pro IE např. zde.) Ostatní prohlížeče, které jsou multiplatformní, používají techniky, které fungují na všech platformách. U prohlížečů se přímo nabízí použití JavaScriptu. Při tvorbě rozšíření pro tyto prohlížeče si tedy vystačíte většinou se znalostmi, potřebnými pro tvorbu stránek – tedy HTML, CSS a JS.

U Firefoxu, který je v oblasti rozšíření určitým průkopníkem, je API poměrně komplexní. Pro tvorbu rozšíření ve FF je potřeba znát alespoň základy XUL, na němž je postaveno UI celého prohlížeče. Tvorba rozšíření tak není zcela triviální a špatně napsané rozšíření může destabilizovat či znefunkčnit celý prohlížeč. Systém rozšíření ve FF je tak poměrně nepružný (i když mocný) – například je potřeba po instalaci či odinstalaci rozšíření restartovat prohlížeč. Určitý posun přináší projekt Jetpack, který má zjednodušit tvorbu rozšíření. (Bližší informace o JetPacku doplnil Pavel Cvrček v komentářích.)

Chrome Extensions

Prohlížeč Google Chrome nastoupil na scénu poměrně razantně a během relativně krátké doby existence si vydobyl slušnou uživatelskou základnu. Přišel s některými zajímavými koncepty a funkcemi, jako jsou oddělené procesy pro jednotlivé panely, velmi rychlý interpret JavaScriptu nebo právě jednoduché vytváření, spravování a ladění rozšíření. Právě tvorbou rozšíření pro Chrome se bude zabývat následující text.

Rozšíření pro Chrome lze nainstalovat i do Firefoxu pomocí Google Chrome Extensions Manageru. Viz článek na toto téma.

Typy rozšíření

Rozšíření pro Chrome jsou několika typů. Některá z nich přidávají vlastní prvky uživatelského rozhraní, jako např. Browser action a Page action. Rozšíření mohou rovněž přistupovat k bookmarkům a panelům. Pokud potřebuje rozšíření přistupovat k obsahu stránek, lze implementovat content scripts nebo cross-origin XMLHttpReques­ts.Každé rozšíření může obsahovat nejvýše jednu Browser action či Page action. Browser action se používá tehdy, pokud je rozšíření využitelné na většině stránek. Pokud rozšíření má fungovat v závislosti na tom, jaký je obsah stránky (např. pouze tehdy, je-li ve stránce informace o RSS či mikroformát apod.), zvolte page action.

Browser action

Tento typ rozšíření se vztahuje na celý prohlížeč, lze je tedy použít kdykoli. Vizuálně je reprezentován ikonou v hlavní liště, napravo od adresního řádku. Chování je jednoduché – po kliknutí je ve vyskakovacím okénku (popup) otevřena určitá HTML stránka, která v sobě obsahuje potřebné skripty, co provedou požadovanou akci. Browser action mohou mít vlastní ikonu, mohou nabízet tooltip, tedy informace co se objeví při najetí myší, a mohou obsahovat i badge, což je kratičký text (4 znaky), co se zobrazí přes ikonu – užitečné v případech, kdy rozšíření pracuje s nějakými spočetnými údaji.

Page action

Některá rozšíření mají smysl pouze na určitých stránkách, jak jsme si řekli výše. Jejich ikona se zobrazí pouze tehdy, pokud stránka splňuje dané požadavky. Zobrazí se přímo v adresním řádku. Podobně jako předchozí typ akce může mít i page action vlastní tooltip a popup okno (nemůže zobrazovat badge).

Struktura rozšíření

Rozšíření pro Chrome je v podstatě soubor ZIP (s příponou .crx), který obsahuje následující součásti:

  • Soubor manifest
  • Jeden nebo více HTML souborů
  • Volitelně: Soubory se skripty v JavaScriptu
  • Volitelně: Další soubory, které vaše rozšíření potřebuje – obrázky, styly apod.

Při vývoji rozšíření si udržujte tyto soubory v jednom adresáři. Když chcete distribuovat rozšíření uživatelům, zabalíte obsah adresáře do .crx souboru – můžete použít skript v Pythonu nebo funkce Chrome. Pokud budete své rozšíření publikovat přes Extensions Gallery, nemusíte balení řešit, galerie zabalí soubory za vás. (Detaily k publikování rozšíření naleznete v dokumentaci v sekci Hosting). Každé rozšíření má vlastní unikátní čtyřicetiznakové ID přidělené při vytváření balíčku.

Pro vývoj rozšíření je vhodné použít vývojářskou verzi prohlížeče. V tomto návodu naleznete informace jak přepnout na vývojářskou verzi.

Pokud se chcete v HTML souboru odkázat na soubory (obrázky apod.), můžete použít relativní cestu – např. <img src="images/icon.png">. Pokud už znáte ID rozšíření, mlžete použít i absolutní cestu chrome-extension://<ID rozšíření>/<cesta-k-souboru>.

Manifest

Manifest je soubor ve formátu JSON a jmenuje se manifest.json. Tento soubor obsahuje potřebné informace o dalších částech rozšíření. Příklad (ze stránek Google) ukazuje takový typický manifest pro rozšíření s browser action:

{
  "name": "My Extension",
  "version": "2.1",
  "description": "Gets information from Google.",
  "icons": { "128": "icon_128.png" },
  "background_page": "bg.html",
  "permissions": ["http://*.google.com/", "https://*.google.com/"],
  "browser_action": {
    "default_title": "",
    "default_icon": "icon_19.png",
    "default_popup": "popup.html"
  }
}

Background page

Většina rozšíření pro Chrome obsahuje nějakou stránku na pozadí, která se nezobrazuje a která obsahuje hlavní logiku celého rozšíření. Background stránka (ve výše předvedeném manifestu to je bg.html) je spuštěna v systému pro každé rozšíření jen jednou – máte-li tedy otevřená dvě okna s rozšířením, sdílejí obě společný background.

Background stránka běží po dobu spuštění prohlížeče a stará se mj. o zaregistrování obslužných rutin, které reagují na kliknutí na ikonu ( chrome.browserAction.onClicked.addListener) v případě, že rozšíření nemá definovaný popup, či rutin, které reagují na otevření stránky ( chrome.tabs.onUpdated.addListener ).

HTML stránky

Background není jediná HTML stránka, kterou může rozšíření obsahovat. Např. browser action může mít popup okno, které je opět implementováno jako HTML stránka. V rozšíření můžeme rovněž volat funkce chrome.tabs.cre­ate() nebo window.open() a zobrazovat další stránky

HTML stránky v rozšíření mají kompletní přístup k DOM stromu dalších stránek – mohou si tedy navzájem volat funkce. Na následujícím obrázku je ukázána struktura rozšíření typu „browser action“ s vyskakovacím oknem. 

Obsah vyskakovacího okna je definován v HTML souboru popup.html. V tomto souboru není potřeba psát znovu funkce, které jsou napsány v background stránce ( background.html), protože je lze přímo volat. Při volání funkce z jiné stránky lze použít metody z chrome.extension , jako jsou getViews() nebo getBackgroundPage(), které vrátí referenci na danou stránku. Přes tu je pak možno volat příslušné funkce.

Content scripts

Pokud má vaše rozšíření nějak interagovat s obsahem webové stránky, budete potřebovat content script. Jde o JavaScript, který je proveden v kontextu stránky načtené do prohlížeče. Je možné na něj pohlížet jako by byl součástí načtené stránky spíš než jako na součást nějakého balíčku (rodičovského rozšíření, parent extension). Content script může proto přímo přistupovat k načtené stránce, číst a měnit její DOM. Nemůže ale přímo měnit DOM v background stránce rozšíření. Neznamená to ale, že content script nemůže komunikovat s rodičovským rozšířením – stále může posílat zprávy a přijímat je.

Nastavení

U některých rozšíření je vhodné, aby si je uživatel mohl přizpůsobit, aby mohl nastavit určité parametry. K tomu slouží stránka Options – opět jednoduchá HTML stránka s vlastním skriptem, která se zobrazí, pokud uživatel vybere v kontextovém menu volbu Možnosti.

V rozšíření pro Chrome můžete využívat perzistentní úložiště WebStorage (viz popis WebStorage na Zdrojáku) a můžete si nastavení ukládat do pole localStorage.

API

Rozšíření pro Chrome mohou přistupovat k některým funkcím prohlížeče pomocí API. K dispozici jsou programová rozhraní pro bookmarky, panely, kontextové menu, pro cookies, jazykové verze a další funkce prohlížeče, jak napovídá jejich seznam:

Bezpečnost

Každé rozšíření musí ve svém manifestu určit, jaká oprávnění požaduje. Uživatel je při instalaci upozorněn na to, že dává rozšíření právo přistupovat k určitým oblastem.

"permissions": [
  "tabs",
  "bookmarks",
  "http://www.blogger.com/",
  "http://*.google.com/",
  "unlimitedStorage"
], ...

Výše uvedený příklad ukazuje rozšíření, které požaduje přístup k API panelů, bookmarků, ke stránkám blogger.com a Google. Navíc požaduje větší prostor pro localStorage (bez tohoto požadavku má pouze 5 MB).

Vytvořili jste nebo vytváříte rozšíření pro prohlížeče?

Ukázkové rozšíření

Ukažme si příklady jednoduchých rozšíření pro Google Chrome – velmi obsáhlý souhrn různých ukázek naleznete na stránce příkladů.

Page action

Ukažme si jedno z nejjednodušších rozšíření typu Page action, které zobrazí ikonku „G!“ v adresním řádku, pokud URL obsahuje písmeno G. Bude obsahovat pouze manifest, ikonku a background page. V manifestu určíme typ rozšíření a metainformace:

{
  "name": "Page action by URL",
  "version": "1.0",
  "description": "Shows a page action for urls which have the letter 'g' in them.",
  "background_page": "background.html",
  "page_action" :
  {
    "default_icon" : "icon-19.png",
    "default_title" : "There's a 'G' in this URL!"
  },
  "permissions" : [
    "tabs"
  ],
  "icons" : {
    "48" : "icon-48.png",
    "128" : "icon-128.png"
  }
}

V manifestu je zadáno jméno rozšíření, popis, jeho verze (slouží k automatické aktualizaci rozšíření), odkaz na background page, sadu ikon různých velikostí, informace o potřebných právech (zde jen přístup k panelům) a konečně informace o vlastní page action – ikona která se zobrazí v adresním řádku a její popis.

Vlastní funkci implementuje stránka background.html:

<!DOCTYPE html>
<!--
 * Copyright (c) 2010 The Chromium Authors. All rights reserved.  Use of this
 * source code is governed by a BSD-style license that can be found in the
 * LICENSE file.
-->
<html>
  <head>
    <script>
      // Called when the url of a tab changes.
      function checkForValidUrl(tabId, changeInfo, tab) {
        // If the letter 'g' is found in the tab's URL...
        if (tab.url.indexOf('g') > -1) {
          // ... show the page action.
          chrome.pageAction.show(tabId);
        }
      };
      // Listen for any changes to the URL of any tab.
      chrome.tabs.onUpdated.addListener(checkForValidUrl);
    </script>
  </head>
</html>

Jak vidíte, jde o prostou stránku v HTML5, která obsahuje jen skript. V něm je callback funkce, která zkontroluje při změně stránky její URL, a pokud obsahuje písmeno „g“, zobrazí ikonu pro page action. Funkce je pomocí chrome.tabs.onUpdated.addListener zaregistrována jako obsluha události, která je vyvolána při aktualizaci panelu.

Browser action – tisk stránky

Jako ukázku jednoduchého rozšíření typu browser action si ukažme rozšíření, které nabídne ikonku pro tisk stránky. V manifestu určíme opět potřebné údaje jako v minulém příkladu:

{
  "name": "Print this page",
  "description": "Adds a print button to the browser.",
  "version": "1.1",
  "background_page": "background.html",
  "permissions": [
    "tabs", "http://*/*", "https://*/*"
  ],
  "browser_action": {
      "default_title": "Print this page",
      "default_icon": "print_16x16.png"
  }
}

Vlastní skript, který obslouží kliknutí na ikonu rozšíření, je opět v background.html a je velmi jednoduchý:

<html>
<head>
<script>
  // Called when the user clicks on the browser action.
  chrome.browserAction.onClicked.addListener(function(tab) {
    var action_url = "javascript:window.print();";
    chrome.tabs.update(tab.id, {url: action_url});
  });
</script>
</head>
</html>

(Stejnou funkcionalitu by šlo zařídit i pomocí obsluhy popup.)

Rozšíření pro Jdem.cz

O něco komplexnější rozšíření si ukážeme na praktickém rozšíření, které zkracuje URL stránky pomocí služby Jdem.cz. Autorem je Michal Wiglasz. Manifest vypadá takto:

{
   "browser_action": {
      "default_icon": "icon19.png",
      "default_popup": "popup.html",
      "default_title": "Zkrátit adresu stránky pomocí Jdem.cz"
   },
   "description": "Zkracování adres pomocí Jdem.cz",
   "name": "Zkracování adres pomocí Jdem.cz",
   "permissions": [ "tabs" ],
   "version": "5.4"
}

V manifestu je tentokrát definována stránka pro popup funkci po kliknutí na ikonu; rozšíření nepoužívá background page. Řešení pomocí popup stránky má pro toto použití výhodu – není třeba registrovat ovladač a stránka je při každém kliknutí načtena znovu. Ve stránce je použit externí JavaScript s API Jdem.cz.

<!DOCTYPE html>
<html>
  <head>
   
  <script type="text/javascript" src="http://jdem.cz/jsapi.js"></script>       
  <script>
    chrome.tabs.getSelected(null, zkrat);
   
    function zkrat(tab) {
      JdemClient.shorten(tab.url, 'JdemCB.zkraceno');   
    }
   
    JdemCB.zkraceno = function(data) {
      var result;
      if (data.statusCode=='OK') {
        for (var r in data.results) {
          result = data.results[r];
          break;
        }
       
        var box = document.getElementById("url");
        var img = document.getElementById("qr");
        img.src = 'http://x0.cz/' + result['userHash'] + '?qr';
        box.value = result['shortUrl'];
        box.focus();
        box.select();
        document.execCommand('Copy');
      } else {
        document.getElementById("result").innerHTML = "Chyba " + data.errorMessage;
      }
    }
  </script>   
  </head>   
  <body>       
    <input type="text" name="url" id="url" value="" style="width: 100%;">       
    <img src="" id="qr">   
  </body>
</html>

Stránka je po kliknutí na ikonu načtena a je proveden skript. Pomocí funkce chrome.tabs.getSelected je získán handler k aktuálně otevřenému panelu. Ten je předán callback funkci zkrat, která získá URL stránky a pomocí API Jdem.cz jej zkrátí. Výsledek pak vloží do elementu input, který je součástí vyskakovacího okna (kromě toho zobrazí i QR kód dané zkratky jako IMG).

Content Scripts

Použití ContentScriptu si předvedeme na rozšíření Page action, které je závislé na obsahu stránky (nezapomeňme, že rozšíření nemůže přistupovat přímo ke stránce, ale musí k tomu použít právě Content scripts). Manifest pro rozšíření je tento:

{
  "name" : "Page action by content",
  "version" : "1.0",
  "description" : "Shows a page action for HTML pages containing the word 'sandwich'",
  "background_page" : "background.html",
  "page_action" :
  {
    "default_icon" : "sandwich-19.png",
    "default_title" : "There's a 'sandwich' in this page!"
  },
  "content_scripts" : [
    {
      "matches" : [
        "http://*/*",
        "https://*/*"
      ],
      "js" : ["contentscript.js"],
      "run_at" : "document_idle",
      "all_frames" : false
    }
  ],
  "icons" : {
    "48" : "sandwich-48.png",
    "128" : "sandwich-128.png"
  }
}

V manifestu tentokrát přibyla sekce, v níž je určeno, jak se má skript chovat, kdy má být načten, u jakých stránek a další informace. Seznam „matches“ určuje stránky – zde to budou všechny s protokolem http nebo https. „js“ jsou skripty, které budou vloženy do kódu stránky (lze určit i uživatelské CSS). Parametr „run_at“ určuje okamžik, kdy bude skript proveden (zda před vytvářením DOM, po vytvoření nebo až ve chvíli, kdy je dokument připraven). Rovněž je řečeno, zda se má skript spustit pro všechny rámce, nebo jen pro hlavní.

Vlastní contentscript.js je jednoduchý – zkontroluje, zda je v textu stránky řetězec „sandwich“ a pokud ano, pošle zprávu skriptu v background page:

/*
 * Copyright (c) 2010 The Chromium Authors. All rights reserved.  Use of this
 * source code is governed by a BSD-style license that can be found in the
 * LICENSE file.
 */
var regex = /sandwich/;
// Test the text of the body element against our regular expression.
if (regex.test(document.body.innerText)) {
  // The regular expression produced a match, so notify the background page.
  chrome.extension.sendRequest({}, function(response) {});
} else {
  // No match was found.
}

Všimněte si, že tělo zprávy je prázdné (pokud slovo není nalezeno, zpráva se neposílá, je tedy v roli prostého spouštěče) a obsluha pro odpověď je rovněž prázdná. Vlastní HTML pro background stránku je podobný prvnímu příkladu – registruje obslužnou rutinu pro zprávy od contentscriptu. Rutina zobrazí ikonu pro rozšíření a pošle prázdnou odpověď.

<!DOCTYPE html>
<!--
 * Copyright (c) 2010 The Chromium Authors. All rights reserved.  Use of this
 * source code is governed by a BSD-style license that can be found in the
 * LICENSE file.
-->
<html>
  <head>
    <script>
      // Called when a message is passed.  We assume that the content script
      // wants to show the page action.
      function onRequest(request, sender, sendResponse) {
        // Show the page action for the tab that the sender (content script)
        // was on.
        chrome.pageAction.show(sender.tab.id);
        // Return nothing to let the connection be cleaned up.
        sendResponse({});
      };
      // Listen for the content script to send a message to the background page.
      chrome.extension.onRequest.addListener(onRequest);
    </script>
  </head>
</html>

K dalšímu studiu

Téma tvorby rozšíření jsme ani zdaleka nevyčerpali. Ukázali jsme si pouze základy tvorby rozšíření pro prohlížeč Chrome. K vlastní tvorbě pak určitě využijete následující materiály:

(Článek vychází z textu manuálu Google Chrome Extensions, zveřejněného pdo licencí CC-BY, především pak ze sekce Overview a Get started. Obsahuje přeložené pasáže z těchto stránek. Ukázky kódu jsou ze stránek Samples a jsou zveřejněny pod licencí BSD. Rozšíření pro Jdem.cz napsal Michal Wiglasz a bylo zveřejněno s jeho laskavým souhlasem – děkujeme. Autor článku je autorem služby Jdem.cz)

Komentáře

Subscribe
Upozornit na
guest
9 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Oleg

Pěkný článek. Jen v Opeře se jako rozšíření používá uživatelských skriptů (JavaScript). Ony pomůcky (widgets) jsou spíše samostatné aplikace.

Mem_

Díky za pěkné shrnutí. Mám jen malé OT k terminologii („Rozšíření mohou rovněž přistupovat k bookmarkům a záložkám“), i v českém Chrome je menu „Správce záložek“ právě správce bookmarků, kdežto tabům se tam říká karty, případně se ujalo v češtině i panely. U běžné populace je to jedno a záložky se nabízí pro oba významy, ale v článku by se asi chtělo držet minimálně terminologie Googlu kvůli jednoznačnosti.

Mem_

Tak pokud IE9 používá v české lokalizaci termín záložky pro karty, tak je to smutné, uznávám :). Protože oni naopak název panely používají (aspoň v IE8 co tu mám) jako funkční prvky, které si uživatel může volitelně zobrazovat (tj. oblíbené položky, historie, řádek nabídek atd.). V IE9 to bude předpokládám taky tak?

Pavel Cvrček

…Systém rozšíření ve FF je tak poměrně nepružný (i když mocný) – například je potřeba po instalaci či odinstalaci rozšíření restartovat prohlížeč. Určitý posun přináší projekt Jetpack, který má zjednodušit tvorbu rozšíření a přinést např. možnost jejich instalace bez restartu…

Je to trochu jinak. Jetpack je javascriptové API (knihovna/fra­mework) nad existujícím API. Samotná možnost instalace/odin­stalace rozšíření bez restartu je nyní vlastností celé platformy tj. neplatí, že rozšíření vytvořené skrze Jetpack po instalaci nevyžadují restart a ty „klasické rozšíření“ ano, byť u těch klasických záleží na tom, zda si s tím autor rozšíření dá tu práci. Důležitá je též informace, že se to týká Firefoxu 4 a výše. Rozšíření postavené na JetPacku a instalované do Firefoxu 3.6 tuto možnost nemá.

pozortucnak

Nijak jsem to nezkoumal, ale přijde mi, že to API chromia je málo komplexní, přijde mi to tak trochu na úrovní uživatelského scriptu/grease­monkey.
Tedy napřiklad pro chromium nelze napsat něco jako Vimperator. O projektech Vimium, Vrome vím, ale ty nesahají Vimperatoru ani po kolena…

Rado2

No priekopník rozšírení je skvôr IE, ak sa nemýlim, nie? Mám pocit, že už od verzie 3 poskytoval nejaké interfacy na jeho ovládanie, výrazne sa to rozšírilo v IE 4. Bohužiaľ (alebo našťastie) programujem len pre IE, nie priamo doplnky, ale hostujem a ovládam jeho jadro, myslím že cez COM to je dobre spravené, nezdá sa mi to komplikované, keď som zisťoval, či by to šlo robiť cez jadro FX, tak sa mi to zdalo hrozne komplikované a na ich stránke chaos.
Neviete, či je možné využívať jadro nainštalovaného FX, prípadne chrome vo vlastnej aplikácii a plne ovládať aj jeho DOM?

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.