Criando extensões para o Firefox - Parte I


Leia em 8 minutos

Todo mundo já teve uma idéia ou sentiu falta de algum recurso em um programa. No caso de navegadores, é muito fácil adicionar funcionalidades, pelo menos para quem usa Mozilla.

O Mozilla permite adicionar, remover ou alterar funcionalidades utilizando apenas Javascript, CSS e XML. Isso te dá flexibilidade suficiente para fazer absolutamente tudo o que você quiser. Neste artigo, você terá uma idéia de como fazer sua própria extensão utilizando recursos como requisições remotas (XMLHttpRequest), suporte a múltiplos idiomas e configurações (about:config).

Mas o que é uma extensão, afinal?

Uma extensão nada mais é do que um série de arquivos escritos em XUL, Javascript e CSS e compactados em formato ZIP, com a extensão xpi. Veja, por exemplo, como é a estrutura da extensão webdeveloper, de Chris Pederick.

Estrutura da extensão Webdeveloper, criada por Chris Pederick

Você pode ou não compactar sua estrutura em formato JAR, a exemplo da extensão Webdeveloper. Neste artigo, não iremos compactá-la.

Toda a interface de sua extensão será feita com tags em XML. Por exemplo, para adicionar um botão você pode utilizar a tag <button />. Já o comportamento que sua extensão terá é definido com Javascript. Por exemplo, podemos exibir uma mensagem "Você clicou no botão" com o código <button oncommand="alert('Você clicou no botão');" />.

Percebeu que tudo é feito de maneira clara e simples?

Preparando o ambiente para desenvolvimento

Para começar a desenvolver, podemos instalar algumas extensões que irão facilitar nossa vida:

Além disso, devemos definir algumas configurações do navegador. Basta digitar about:config como URI na barra de endereços. Se não sabe do que estou falando, dê uma olhada aqui e aqui.

Uma coisa extremamente útil é trabalhar com dois perfis distintos. O Firefox não permite que mais de um perfil seja aberto por padrão, mas é possível abrir quantos você quiser. Basta digitar set MOZ_NO_REMOTE=1 na linha de comando. Depois, abra o perfil com o comando firefox -P dev (se for fazer uma extensão para o Thunderbird, é aconselhável que você faça isso). Para usuários de Windows, adicione a pasta do Firefox na variável de ambiente PATH. Veja mais sobre como fazer isso aqui.

Arquivos de Configuração

Para permitir que sua extensão seja instalada, é preciso configurar dois arquivos com algumas informações. São eles chrome.manifest e install.rdf.

Entendendo o "Install Manifest"

O install.rdf é um arquivo XML que contém informações que são utilizadas pelo instalador no momento em que você for adicionar a extensão. Veja um exemplo:

<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
	<Description about="urn:mozilla:install-manifest">
		<em:id>{XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}</em:id>
		<em:name>Extensão de Exemplo</em:name>
		<em:version>1.0</em:version>
		<em:description>Uma extensão de exemplo com algumas funcionalidades</em:description>
		<em:creator>Seu nome aqui</em:creator>
		<em:contributor>Uma pessoa que te ajudou</em:contributor>
		<em:contributor>Outra pessoa</em:contributor>
		<em:homepageURL>http://sampleextension.mozdev.org/</em:homepageURL>
		<em:optionsURL>chrome://sampleext/content/settings.xul</em:optionsURL>
		<em:aboutURL>chrome://sampleext/content/about.xul</em:aboutURL>
		<em:iconURL>chrome://sampleext/skin/mainicon.png</em:iconURL>
		<em:updateURL>http://sampleextension.mozdev.org/update.rdf</em:updateURL>
		<em:type>2</em:type>
		<em:targetApplication>
			<Description>
				<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
				<em:minVersion>0.9</em:minVersion>
				<em:maxVersion>1.0</em:maxVersion>
			</Description>
		</em:targetApplication>
	</Description>
</RDF>

Os pricipais elementos deste arquivo são:

id
Obrigatório. Identificador único de sua extensão. Atualmente, somente duas maneiras são aceitas. A primeira é gerando um ID com uma ferramenta desenvolvida pela Microsoft e disponibilizada aqui. Você também pode gerá-la aqui e aqui. A segunda é utilizando o formato extensao@dominio, por exemplo, extensao@simplesideias.com.br.
name
Obrigatório. É o nome de sua extensão, por exemplo, "GMail Notifier".
version

Obrigatório. Versão de sua extensão. Se você não em idéia de como definir a versão de sua extensão, use algo como X.Y.Z, onde:

  • X denota a versão da extensão
  • Y denota implementação de funcionalidades
  • Z denota correções de bugs

Na prática, fica algo assim:

  • 1.0: versão inicial da extensão;
  • 1.0.1: correção de algum bug ou modificação não-significativa;
  • 1.1: implementação de nova funcionalidade ou modificação significativa;
  • 1.1.1: correção de bug ou modificação não-significativa;
description
Obrigatório. Uma descrição de sua extensão, expressa de maneira suscinta.
creator
Obrigatório. Nome do criador da extensão.
homepageURL
Opcional. Site onde o usuário pode encontrar mais informações sobre a extensão.
optionsURL
Opcional. Arquivo que será exibido quando o usuário selecionar a opção "Preferências" da extensão o gerenciador de extensões.
updateURL
Opcional. Caminho para atualizações da extensão. Veja um exemplo deste arquivo:
<?xml version="1.0"?>
<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       xmlns="http://www.mozilla.org/2004/em-rdf#">
<r:Description about="urn:mozilla:extension:
{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}">
  <updates>
    <r:Seq>
      <r:li>
        <r:Description>
          <version>0.1</version>
          <targetApplication>
            <r:Description>
              <id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</id>
              <minVersion>0.8</minVersion>
              <maxVersion>1.9</maxVersion>
              <updateLink>http://www.webserver.com/foowidget.xpi</updateLink>
            </r:Description>
          </targetApplication>
        </r:Description>
      </r:li>
    </r:Seq>
  </updates>
  <version>0.1</version>
  <updateLink>http://www.webserver.com/foowidget.xpi</updateLink>
</r:Description>
</r:RDF>
targetApplication

Obrigatório. Identifica quais aplicativos sua extensão suporta. Veja algumas GUIDs:

Relação de GUIDs
AplicativoGUID
Firefox{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
Thunderbird{3550f703-e582-4d05-9a08-453d09bdfdc6}
Mozilla Suite{86c18b42-e466-45a9-ae7a-9b95ba6f5640}
SeaMonkey{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
Netscape{3db10fab-e461-4c80-8b97-957ad5f8ea47}
Flock{a463f10c-3994-11da-9945-000d60ca027b}

Para que sua extensão suporte o Mozilla Suite e SeaMonkey, é preciso incluir no pacote o arquivo install.js. Futuramente, não será mais preciso incluí-lo.

Entendendo o "Chrome Manifest"

Chrome é o nome dado à interface de pacotes criada pelos navegadores Mozilla. Para acessar arquivos adicionados ao Chrome, basta definir a URI chrome://. Um pacote padrão pode ser acessado através da URI chrome://browser/. Para que nossa extensão seja considerada parte do Chrome, é preciso criar um arquivo chamado "Chrome Manifest".

O "Chrome Manifest" é responsável por indicar a localização dos arquivos utilizados por sua extensão. Esse arquivo tem um formato que deve ser seguido e deve estar localizado na raíz da extensão sob o nome chrome.manifest. Veja um exemplo:

content       pacote   content/
locale        pacote   pt-BR   locale/pt-BR/
locale        pacote   en-US   locale/en-US/
overlay       chrome://browser/content/browser.xul    chrome://pacote/content/browser.xul

As linhas acima indicam o conteúdo da extensão pacote está no diretório content; possui dois idiomas (pt-BR e en-US) e seus arquivos estão localizados no diretório locale; o arquivo que irá exibir nossa extensão no browser é indicado como overlay.

Apesar do suporte à múltiplos idiomas não ser obrigatório, é extremamente recomendado que você o faça. É muito simples e permite que ela seja utilizada por um maior número de pessoas no mundo!

De olho no câmbio

Nada melhor do que a prática para entender como se faz uma extensão. É recomendado que você tenha conhecimentos de Javascript e CSS, já que estes não serão explicados passo-a-passo. Se você não entende nada desses dois itens, existe bastante coisa disponível por !

Nós iremos criar uma extensão que exibe informações sobre o câmbio, com dados disponibilizados pelo site WebServiceX. Para definirmos melhor o que temos que fazer, segue uma lista:

Criando nossos arquivos de configuração

Para iniciar crie um diretório com o nome "exchangenotifier". Esse será nosso diretório-raiz e também o nome de nosso pacote (daqui para frente referenciado como "raíz", certo?). Crie um arquivo com o nome "install.rdf" e adicione o seguinte conteúdo:

<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
	<Description about="urn:mozilla:install-manifest">
		<em:id>exchangenotifier@simplesideias.com.br</em:id>
		<em:name>Exchange Notifier</em:name>
		<em:version>1.0</em:version>
		<em:description>Money exchange. Information powered by WebserviceX</em:description>
		<em:creator>Nando Vieira</em:creator>
		<em:homepageURL>http://simplesideias.com.br/</em:homepageURL>
		<em:optionsURL>chrome://exchangenotifier/content/settings.xul</em:optionsURL>
		<em:type>2</em:type>

		<em:targetApplication>
			<Description>
				<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
				<em:minVersion>0.9</em:minVersion>
				<em:maxVersion>2+</em:maxVersion>
			</Description>
		</em:targetApplication>
	</Description>
</RDF>

Não se preocupe em colocar a descrição em português. Na segunda parte deste artigo iremos adicionar suporte a múltiplos idiomas.

Agora, criar nosso arquivo "Chrome Manifest"; crie na raíz um arquivo chamado "chrome.manifest" com o seguinte conteúdo:

content     exchangenotifier   content/
overlay     chrome://browser/content/browser.xul    chrome://exchangenotifier/content/browser.xul

Novamente, temos a definição do arquivos que compoem nossa extensão. Vale lembrar que não precisamos definir individualmente cada arquivo. Isso poderia ser maçante no caso de termos uma quantidade muito grande de arquivos como imagens. Bastou definir o diretório (neste caso "content").

Como nossa extensão terá algumas configurações que deverão ser salvas (moedas de conversão, por exemplo), já podemos adicioná-las automaticamente durante o processo de instalação, com valores-padrão. Crie um diretório "default" na raíz com um subdiretório "preferences". Um arquivo .js adicionará estas configurações:

pref('extensions.exchangenotifier.from', '');
pref('extensions.exchangenotifier.to', '');
pref('extensions.exchangenotifier.last_exchange', '');
pref('extensions.exchangenotifier.last_status', '');

Agora, crie um diretório na raíz chamado "content". Veja como está nossa estrutura:

Estrutura

Nosso primeiro arquivo XUL

O arquivo "browser.xul" relacionando no Chrome Manifest irá sobrepor (overlay) a interface do browser. Para indicarmos onde ela irá aparecer, devemos definir o ID do elemento da interface. Neste exemplo iremos exibir um ícone na barra de status. Adicione o código abaixo em "browser.xul".

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://exchangenotifier/content/style.css" type="text/css"?>
<!DOCTYPE overlay>
<overlay id="exn-overlay"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <!-- Aqui vai o código XUL de nossa extensão -->
</overlay>

Essa é, provavelmente, a estrutura mais básica de um arquivo XUL que irá funcionar como "overlay". Temos um arquivo CSS que irá definir a formatação. O elemento overlay tem um ID único definido aqui como exn-overlay.

Você pode abrir este arquivo no Firefox para ver se ele está funcionando. Se tiver algo errado, uma mensagem de erro XML será exibida.

Um problema muito constante ao desenvolver extensões e agravado quando se está começando, é não saber quais são as tags disponíveis. O melhor lugar para se obter estas informações é em XULPlanet. Lá, você tem toda a relação de tags com uma descrição e exemplo de cada uma.

Por acaso, o elemento que precisamos adicionar chama-se statusbar. O elemento statusbar pode ter diversos elementos statusbarpanel, que nada mais são do que aqueles vários "quadradinhos" onde muitas extensões são exibidas.

Exemplos de statusbarpanel

Sabendo disso, já podemos adicionar nossa extensão à barra de status com o seguinte código:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://exchangenotifier/content/style.css" type="text/css"?>
<!DOCTYPE overlay>
<overlay id="exchangenotifier-overlay"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <statusbar id="status-bar">
		<statusbarpanel id="exn-statusbar">
			<image id="exn-icon" />
			<label id="exn-label">–</label>
		</statusbarpanel>
    </statusbar>
</overlay>

Note como é simples a maneira que adicionamos itens ao browser. Todas as tags possuem nomes que remetem ao próprio elemento (statusbar, image, label, button, dialog).

Crie o arquivo "style.css" dentro do diretório "content". É ele que irá cuidar de toda a parte visual de nossa extensão. Adicione o seguinte conteúdo:

#exn-icon {
    list-style-image: url("chrome://exchangenotifier/content/chart_curve.png");
}

A imagem utilizada nesta extensão foi retirada do pacote Silk Icons, disponibilizado por famfamfam.

Visualizando sua extensão

A maneira mais simples de visualizar a extensão durante o desenvolvimento, é movendo o diretório raíz para a pasta de extensões presente no seu perfil. Para quem usa Ubuntu Dapper o caminho padrão é ~/.mozilla/firefox/xxxxxxxx.default. No Windows XP (versão em inglês), o caminho é C:\Documents And Settings\USER\Application Data\Mozilla\Firefox\Profiles\xxxxxxxx.default. Outros sistemas, não tenho a menor idéia. Faça um busca pelo diretório Profiles e você provavelmente encontrará. Leia mais aqui. Depois, basta reiniciar o Firefox para ativar a extensão.

Estrutura

Acesse o about:config e digite "exchangenotifier". Você verá que as preferências que colocamos no arquivo "prefs.js" foram adicionadas.

About:config

É isso aí! Espero que você tenha gostado da primeira parte deste artigo. Se tiver dúvidas ou sugestões, deixe seu comentário! Pegue a extensão que fizemos até agora, baixando o arquivo exchangenotifier-1.xpi.

Referências