Créer sa première extension Chrome
Par Ludovic Meurillon le mardi 18 mai 2010, 18:03 - Web 2.0 - Lien permanent
Lors du Bof d'avril 2010, nos équipes ont pu voir
de leur propres yeux la rapidité avec laquelle il est possible de créer,
installer, débugguer une extension à destination du navigateur Chrome.

En effet, à l'instar de Firefox, le navigateur de Google possède des api
simples d'accès pour réaliser des extensions.
Nous allons voir tout au long de ce post comment faire pour créer une
extension Chrome en partant de presque rien.
Avant de plonger dans la partie technique il est nécessaire de bien
définir ce que représente une extension pour Chrome. Une extension est vue dans
son intégralité comme un onglet de navigation ce qui implique qu'il possède son
propre processus système, les extensions ne font en définitive qu'exécuter du
code Web (Javascript, Html et CSS) en proposant quelques API supplémentaires
permettant des manipulations spécifiques au navigateur (comme la possibilité
d'ajouter une vignette à une icône d'extension).
Intéressons-nous maintenant à notre objectif du jour. Le but de notre
première extension sera de permettre de visualiser le statut des builds d'un
serveur Hudson, serveur qui propose nativement des API Json et XML permettant
de consulter son état. Par manque d'imagination et par soucis de rapidité nous
donnerons à cette extension le nom barbare de Chrudson.
Une extension Chrome se présente sous la forme d'une archive (signée ou
non) qui doit inclure un descripteur d'extension au format json. Ce fichier se
nomme dans le jargon "chromien" le Manifest.
Voici à quoi pourrait ressembler notre premier
manifest.json
{ "name": "Chrudson",
"version": "1.0",
"description": "Gestion d'un serveur hudson depuis
chrome",
"permissions": ["http://*/*","https://*/*"]
}
Comme on le voit rapidement, il est possible de nommer, versionner, et
décrire succintement son extension. Bien que notre extension n'ait aucun lien
direct avec Maven, nous l'autorisons à faire des
requêtes sur l'internet tout entier grâce à la ligne :
"permissions": ["http://*/*","https://*/*"]Une fois ce manifest écrit il est d'ores et déjà possible de l'installer
sur un navigateur Chrome en utilisant pour cela le navigateur lui-même en
passant par le panneau des extensions et en ouvrant le mode développeur.
L'extension peut être chargée soit empaquetée (directement en la glissant dans
le navigateur), soit directement depuis un dossier local (ce que nous utilisons
en développement).

Outre le fichier manisfest, une extension chrome peut aussi se composer d'autres modules "actifs" comme une tâche de fond ou background_page (service venant alimenter les données locales ou mettre à jour l'état de l'extension), d'une page d'options ou options_page (page permettant de configurer l'extension) et enfin soit d'une action navigateur ou popup, soit d'une action de page ou page_action (icone cliquable ajoutée à la barre d'adresse, ex : icône rss).
Options_page
Cette partie de l'extension est disponible lorque l'utilisateur clique sur
"options" dans le menu déroulant disponible sur l'icône d'extension.

Pour Chrudson, cette page permet de renseigner l'URL du serveur qui sera
surveillée par l'extension. Une page d'options simplifiée de Chrudson ressemble
à ceci :
<html> <head><title>Chrudson
Options</title>
<script type="text/javascript">
// Saves options to localStorage.
function save_options() {
var url =
document.getElementById("url");
localStorage["hudson_url"]
= url.value;
// Update status to let user know options
were saved.
var status =
document.getElementById("status");
status.innerHTML = "Options Saved.";
setTimeout(function() { status.innerHTML =
"";}, 750);
}
//Restores select box state to saved value from
localStorage.
function restore_options() {
var url =
localStorage["hudson_url"];
document.getElementById("url").value =
url;
}
</script>
</head>
<body onload="restore_options()">
Url :<input type="text" id="url">
<button
onclick="save_options()">Save</button>
<span id="status"></span>
</body>
</html>
On peut remarquer qu'il est possible de
stoquer localement des données via la table localStorage,
cette table étant accessible par toutes les parties javascript de l'extension.
Tout comme une page web, l'évènement onload de la balise <body> est levé
chaque fois que l'utilisateur affiche la page des options.
Pour définir cette page comme la page d'options il suffit d'ajouter la
description suivante au manifest.json précédent :
"options_page":"options.html"Background_page
Ce module de l'extension va permettre à Chrudson de scruter à intervalles
régulier l'état du serveur Hudson précédemment configuré dans la page
d'options. Pour des raisons de synthèse, le code n'est pas au complet dans ce
post. Quelques morceaux de cette page sont cependant intéressant
var pollInterval = DEFAULT_POLL_INTERVAL;
function onLoad() { chrome.browserAction.setTitle({title :"Hudson " +
getHudsonUrl()});
if(
localStorage["poll_frequency"]){ pollInterval =
localStorage["poll_frequency"];
}
startRequest();
}
Cette fonction, exécutée au chargement de l'extension met à jour le tooltip disponible sur l'icône d'extension. Le localStorage est une fois de plus utilisé pour récupérer la fréquence de rafraîchissment des pages (fréquence que l'utilisateur pourra changer dans une version plus évoluée de notre page d'options). Dans notre exemple, cette valeur n'est jamais renseignée, la valeur par défaut est donc utilisée.
La tâche de fond peut aussi utiliser les APIs plus spécifiques aux
extensions Chrome:
function setStatus(text, color) { chrome.browserAction.setBadgeText({text :text});
chrome.browserAction.setBadgeBackgroundColor({color
:color});
}
La fonction setStatus permet de changer l'état de l'icône de l'extension
en lui affectant un badge de couleur à la manière de ce qui peut se trouver sur
les iPhones (limité à quelques caractères).
Une fois la page html/javascript crée, il suffit de rajouter la ligne
suivante au manifest.json pour s'assurer de le déclencher à chaque lancement du
navigateur :
"background_page":"background.html"Browser_action
L'icône d'extension à laquelle fait référence la background_page est
définit par ce que l'on appelle une Browser_action. Cette page permettra lors
d'un clic utilisateur sur l'icône de l'extension d'afficher une fenêtre qui
contient en fait la page html définie comme popup pour la browser_action.
Pour cela il suffit d'ajouter la description de la browser_action au
désormais bien connu manifest.json
"browser_action":
{
"default_icon": "butler.png",
"popup": "popup.html"
}
Dans notre cas, le fichier
popup.html simplifé ressemble au code suivant :
<html><head>
<title>Chrudson Popup</title>
<script type="text/javascript">
...
function onLoad() {
url =
localStorage["hudson_url"];
titleDiv =
document.getElementById("title");
titleDiv.innerText = "Status hudson
("+url+")";
statusDiv =
document.getElementById("status");
statusDiv.innerText =
"loading";
refreshStatus();
}
function refreshStatus(){
var xmlUrl = url+"api/json";
updateReq = new
XMLHttpRequest();
updateReq.open("GET",xmlUrl,true);
updateReq.onload =
parseResult;
updateReq.send(null);
}
function parseResult(){...}
...
function onClick(url){
return
function(){open_tab(url)};
}
function open_tab(url){
chrome.tabs.create({"url":
url});
}
</script>
</head>
<body onload="onLoad();" class="status">
<div id="title" class="title"/>
<span id="status"/>
</body>
</html>
Il se contente d'afficher l'état des jobs listés sur le serveur dans des
éléments HTML simples. Ces éléments peuvent être enrichis de styles CSS 3. On
peut signaler dans ce code la possibilité d'ouvrir de nouveaux onglets Chrome
lors d'un clic souris sur le nom d'un job par exemple. Il est cependant
nécessaire de compléter les autorisations données à l'extension dans le fichier
manifest comme suit :
"permissions":
["http://*/*","https://*/*","tabs"]C'est bien beau tout ça ...
Tout ce qui nous avons vu jusqu'à présent montre à quel point il est
simple de coder, installer et utiliser rapidement une extension. Cependant, que
se passe-t-il lorsque l'un des traitements javascripts foire lamentablement, ou
que certains styles CSS présentent finalement des problèmes d'alignement
?
L'une des forces de Chrome sur ce point réside dans la possibilité
d'inspecter dynamiquement chacune des parties de l'extension (background,
options et popup) directement dans le navigateur.
En effet, un lien d'inspection du background est disponible dans le menu
des extensions, la page d'options est quant à elle inspectable comme n'importe
qu'elle autre page Web, et la popup peut être inspectée en effectuant un
clic-droit->inspecter sur l'icône de l'extension comme le montre la capture
d'écran suivante (réalisée sous chrome 6.0.401.1)

Le wrapping GWT
L'une des extensions les plus réussie de Chrome, livrée avec GWT 2.0,
s'appelle Speed Tracer. Cette extension a été codée en grande
partie avec le Framework GWT. Pour cela, les développeurs ont réalisé une
implémentation partielle des API d'extension chrome pour GWT. Si vous êtes un
fervent admirateur de GWT ou simplement un petit curieux, je vous invite à
explorer le code par vous même pour vous faire une idée de la puissance de
l'engin (l'implémentation des api d'extension se trouve dans le package
com.google.gwt.chrome.crx.*).
Cette variation d'utilisation du Google Web Toolkit sera d'ailleurs
abordée au Google I/O cette semaine http://code.google.com/events/io/2010/sessions/gwt-linkers-webworkers-extensions.html
Vous savez maintenant tout ce qu'il faut savoir pour coder votre première
extension chrome, vous savez aussi qu'il sera bientôt possible de coder des
extensions avec GWT de manière encore plus intuitive pour les Java-istes qui
lisent ce post.
Ressources
SpeedTracer http://code.google.com/p/speedtracer/
Guide & APIs http://code.google.com/chrome/extensions/devguide.html
Projet Git d'où nos exemples sont librement inspirés http://github.com/sanitz/hudson-chrome-extension
