Construyendo una extensión

Introducción

Este tutorial te guiará a través de los pasos requeridos para desarrollar una extensión muy básica - una que agrega un panel con una barra de estado con el texto "Hola, Mundo!" al navegador de Firefox.

Nota: La extensión creada por este tutorial no funcionará en versiones de Firefox que no contengan una barra de estado estática (esto es, Firefox 4 en adelante). Puedes encontrar un tutorial más actualizado en The Essentials of an Extension de la XUL School.

Desde Firefox 4 (y otras aplicaciones basadas en Mozilla 2) existen dos tipos de extensiones:

  • Las extensiones tradicionales, clásicas o XUL son más poderosas, pero más complicadas de construir y requieren un reinicio para su instalación.
  • Extensiones sin reinicio, o bootstrapped extensions que no requieren un reinicio para instalarse pero son más limitadas que las extensiones tradicionales. El Add-on SDK y el Add-on Builder pueden ser usados para construir fácilmente extensiones sin reinicio.

Este artículo explica como construir una extensión tradicional para Firefox. Para información sobre bootstrapped extensions o sin reinicio, mira Bootstrapped extensions.

Para un tutorial sobre construcción de extensiones para Thunderbird, mira Construyendo una extensión para Thunderbird.

Inicio Rápido

Una extensión Hola Mundo similar que puedes generar con el Extension Wizard es explicado línea por línea en otro tutorial desde la MozillaZine Knowledge Base (Base de Conocimiento MozillaZine).

Configurando un Ambiente de Desarrollo

Las extensiones son empaquetadas y distribuidas en archivos ZIP o Bundles, con la extensión de archivos XPI.

Un ejemplo del contenido dentro de un archivo XPI típico :

my_extension.xpi:                         //Igual a una carpeta llamada my_extension/
          /install.rdf                    //Información general sobre tu extensión
          /chrome.manifest                //Registra tu contenido con el motor Chrome
          /chrome/
          /chrome/content/                //Contenido de tu extensión, por ejemplo, archivos XUL and JavaScript
          /chrome/icons/default/*         //Iconos por defecto de tu extensión
          /chrome/locale/*                //Construyendo una Extensión# Localización
          /defaults/preferences/*.js      //Construyendo una Extensión# Archivos por defecto
          /plugins/*
          /components/*
          /components/cmdline.js

Desearemos construir una estructura de archivos similar a la anterior para nuestro tutorial, así que comencemos creando una carpeta para tu extensión en algún lugar de tu disco duro (por ejemplo, C:\extensions\my_extension\ or ~/extensions/my_extension/). Dentro de la nueva carpeta para la extensión, crea otra carpeta llamada chrome, y dentro de la carpeta chrome, crea una carpeta llamada content.

Dentro del directorio raíz de la carpeta de tu extensión, crea dos archivos de texto nuevos, llamados chrome.manifest e install.rdf. En el directorio chrome/content, crea un nuevo archivo de texto vacío llamado sample.xul.

Deberías concluir con esta estructura de directorio:

  • install.rdf
  • chrome.manifest
  • chrome\
    • content\
      • sample.xul

<pre> #!/bin/sh h=$HOME/moExt mkdir -p $h/my_extension/chrome/content touch $h/my_extension/chrome.manifest $h/my_extension/install.rdf </pre> Por favor lee la información adicional sobre configuración de un ambiente de desarrollo en el artículo Configurando un ambiente de desarrollo.

Gecko 1.9.2 note
Starting in Gecko 1.9.2 (Firefox 3.6), you can also simply include an icon, named icon.png, in the base directory of the add-on. This allows your add-on's icon to be displayed even when the add-on is disabled, or if the manifest is missing an iconURL entry.

Crear el Manifiesto de Instalación

Abre el archivo llamado install.rdf que creaste en el tope de la jerarquía de carpetas de tu extensión y agrega dentro lo siguiente:

<?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>sample@example.net</em:id>
    <em:version>1.0</em:version>
    <em:type>2</em:type>
   
    <!-- Target Application this extension can install into, 
         with minimum and maximum supported versions. --> 
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>1.5</em:minVersion>
        <em:maxVersion>4.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
   
    <!-- Front End MetaData -->
    <em:name>sample</em:name>
    <em:description>A test extension</em:description>
    <em:creator>Your Name Here</em:creator>
    <em:homepageURL>http://www.example.com/</em:homepageURL>
  </Description>      
</RDF>
  • sample@example.net – el ID de la extensión. Este es un valor con el que identificas tu extensión en formato de direccón de correo electrónico (nota que no debería ser tu email). Hazlo único. También podrías usar un GUID. NOTA: Este parámetro DEBE estar en formato de dirección de correo electrónico, aunque NO tiene que ser una dirección válida. (example@example.example)
  • Especifica <em:type>2</em:type> – el 2 declara que está instalando una extensión. Si fueras a instalar un tema (theme) sería 4 (mira Install Manifests#type para otros tipos de códigos).
  • {ec8030f7-c20a-464f-9b0e-13a3a9e97384} – ID de la aplicación Firefox.
  • 1.5 – el número exacto de la versión más antigua de Firefox para la cual estableces que esta extensión funcionará. Nunca uses un * en minVersion; es muy seguro que no hagas lo que esperas.
  • 4.0.* – la versión máxima de Firefox para la cual dices que esta extensión funcionará. En este caso, "4.0.*" indica que la extensión funciona con Firefox 4.0 y cualquier entrega 4.0.x subsecuente. Este número necesita ser menor o igual a la versión anunciada de Firefox. Por defecto, Firefox 10 y posteriores no fuerzan una restricción contra maxVersion (aunque comenzando en Firefox 11, valores muy antiguos de maxVersion son todavía forzados). Puedes forzan a la aplicación a hacerlo usando <em:strictCompatibility>.
Nota: si obtienes un mensajes que install.rdf está mal formado, es útil cargarlo en Firefox usando el comando Archivo->Abrir Archivo que reportará los errores XML para ti.

Las extensiones diseñadas para funcionar con Firefox 2.0.0.x como la última deben configurar la máxima versión a "2.0.0.*". Las extensiones diseñadas para funcionar con Firefox 1.5.0.x como la última deben configurar la máxima versión a "1.5.0.*"

Mira Manifiestos de Instalación para una lista completa de las propiedades requeridas y opcionales.

Guarda el archivo.

Extendiendo el Navegador con XUL

La interfaz de usuario de Firefox está escrita en XUL y JavaScript. XUL es una grática XML que provee widgets de interfaz como botones, menús, barras de herramientas, árboles, etc. Las acciones de los usuarios están ligadas a funcionalidad usando JavaScript.

Para extender el navegador, modificamos partes de la interfaz de usuario del navegador, agregando o modificando widgets. Agreramos widgets insertando nuevos elementos XUL DOM en la ventana del navegador y los modificamos usando script y vinchulando manejadores de eventos.

El navegador es implementado en un archivo XUL llamado browser.xul ($FIREFOX_INSTALL_DIR/chrome/browser.jar contiene content/browser/browser.xul). En browser.xul podemos encontrar la barra de estado, que se parece a algo como esto:

<toolbarpalette id="BrowserToolbarPalette">
 ... <toolbarbutton>s ...
</toolbarpalette>

<statusbar id="status-bar"> es un  "punto de fusión" para un XUL Overlay.

XUL Overlays

Los XUL Overlays son una forma de enlazar en tiempo de ejecución otros widgets de la interfaz de usuario a un documento XUL. Un XUL Overlay es un archivo .xul  que especifíca fragmentos XUL a insertar en puntos de fusión específicos dentro de un documento "maestro". Estos fragmentos pueden especificar la inserción, eliminación o modificación de widgets.

Ejemplo de un Documento XUL Overlay

<?xml version="1.0"?>
<overlay id="sample" 
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 <toolbarpalette id="BrowserToolbarPalette">
  <toolbarbutton id="my-button" label="Hello, World"  />
 </toolbarpalette>
</overlay>

La <toolbarpalette> llamada BrowserToolbarPalette especifica el "punto de fusión" que queremos enlazar dentro de la ventana del navegador.

El hijo <toolbarbutton> es un nuevo widget que queremos insertar dentro de un punto de fusión.

Copia el código de ejemplo anterior y guardalo en tu archivo llamado sample.xul dentro de la carpeta chrome/content que has creado.

Para más información sobre fusionar widgets y modificar la interfaz de usuario usando Overlays, mira debajo.

Chrome URIs

Los archivos XUL son parte de "Paquetes Chrome" - envoltorios de componentes de interfaz de usuario que son cargados a través de URIs chrome://. En lugar de cargar el navegador desde el disco usando una URI file://  (ya que la ubicación de Firefox en el sistema puede cambiar de plataforma a plataforma y de sistema a sistema), los desarrolladores de Mozilla encontraron una solución para crear URIs para contenido XUL que la aplicación instalada conoce.

La ventana del navegador es: chrome://browser/content/browser.xul. Prueba tipiando esta URL en la barra de navegación de Firefox!

Las Chrome URIs constan de varios componentes:

  • Primero, el esquema URI (chrome) que le comunica a la librería de red de Firefox que es una Chrome URI. Indica que el contenido de la URI debería ser tratada como un (chrome). A diferencia de (chrome), (http) le comunica a Firefox que debe tratar la URI como una página web.
  • Segundo, un nombre de paquete (en el anterior ejemplo, browser) que identifica el envoltorio de componentes de interfaz de usuario. Este debería ser lo más único posible para tu aplicación, para evitar colisiones entre extensiones.
  • Tercero, el tipo de dato que es requerido. Existen tres tipos: content (XUL, JavaScript, XBL bindings, etc. que forman la estructura y el comportamiento de una aplicación de interfaz de usuario), locale (DTD, archivos .properties, etc que contienen strings para la localización de la interfaz de usuario) , y skin (CSS e imágenes que forman el tema de la interfaz de usuario).
  • Finalmente, la dirección del archivo a cargar.

Así que, chrome://foo/skin/bar.png carga el archivo bar.png desde la sección skin del tema foo.

Cuando cargas contenido usando una Chrome URI, Firefox usa el Chrome Registry (Registro de Chrome) para traducir estas URIs en los archivos fuente actuales dentro del disco (o en paquetes JAR).

Crea un Manifiesto Chrome

Para más información de Manifiestos Chrome y las propiedades que soportan, mira Referencia de Manifiestos Chrome.

Abre el archivo denominado chrome.manifest que has creado junto al directorio chrome en la raíz de la jerarquía de carpetas de tu extensión.

Agrega este código:

content     sample    chrome/content/

(No te olvides de la barra, "/"! Sin ella, el paquete no será registrado.)

Esto especifica:

  1. tipo de material dentro del paquete chrome.
  2. nombre del paquete chrome (asegúrate de usar todos caracteres en minúscula para ele nombre del paquete ("sample") ya que Firefox/Thunderbird no soporta doesn't support caracteres mixtos en la versión 2 y anteriores - bug 132183)
  3. ubicación de los archivos de paquetes chrome.


Entonces, esta línea establece que para un paquete chrome sample, podremos encontrar sus archivos de contenido (content) en la ubicación chrome/content que es una dirección relativa a la ubicación del manifiesto chrome.manifest.

Tenga en cuenta que los archivos de contenido (content), localización (locale), y apariencia (skin) deben mantenerse dentro de carpetas llamadas content, locale, and skin dentro del subdirectorio chrome.

Guarda el archivo. Cuando ejecutes Firefox con tu extensión (más adelante en este tutorial), esto va a registrar el paquete chrome.

Registrar un Overlay

Necesitas que Firefox fusione tu overlay (capa) con la ventana del navegador siempre que se despliegue una. Así que agrega esta linea al archivo chrome.manifest:

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

Esto le dice a Firefox que fusione sample.xul en browser.xul cuando se cargue browser.xul.

Prueba

Primero, necesitamos comunicarle a Firefox sobre nuestra extensión. Durante la fase de desarrollo para versiones de Firefox 2.0 y posteriores, puedes señalar a Firefox hacia la carpeta donde estés desarrollando la extensión, y la cargará cada vez que reinicies Firefox.

  1. Ubica tu carpeta de perfil y dentro el perfil con el que quieres trabajar (ej., Firefox/Profiles/<profile_id>.default/).
  2. Abra la carpeta extensions/, creandola de ser necesario.
  3. Crea un nuevo archivo de texto y coloca dentro la dirección completa de tu carpeta de desarrollo (ej., C:\extensions\my_extension\ or ~/extensions/my_extension/). Los usuarios de Windows deberían conservar la dirección de la barra, y todos deberían acordarse de incluir una barar de cierre y eliminar cualquier espacio.
  4. Guarda el archivo con la id de tu extensión como su nombre (ej., sample@example.net). Sin extensión de archivo.

Ahora deberías estar listo opara probar tu extensión!

Ejecuta Firefox. Firefox detectará el texto de enlace hacia el directorio de tu extensión e instalará la Extensión. Cuando aparezca la ventana del navegador deberías ver el texto "Hello, World!" en la parte derecha del panel con la barra de estado.

Ahora puedes volver y hacer cambios al archivo .xul, cierra y reinicia Firefox, y deberían aparecer.

Empaquetamiento

Ahora que tu extensión funciona, puedes empaquetarla para su despliegue e instalación.

Comprime (zip) los contenidos (contents) de la carpeta de tu extensión (no la carpeta de extensión misma), y renombra el archivo zip para que tenga la extensión .xpi. En Windows XP, puedes hacer esto fácilmente seleccionando todos los archivos y subcarpetas en la carpeta de tu extensión, haciendo click derecho y seleccionando "Enviar a -> Carpeta comprimida (zip)". Se creará un archivo .zip para ti. Sólo renombralo y ya terminaste!

En Mac OS X, puedes hacer click derecho en los contenidos (contents) de la carpeta de la extensión y elegir "Crear archivo de..." para hacer un archivo zip. Sin embargo, ya que Mac OS X agrega archivos ocultos a las carpetas para rastrear los metadatos de los archivos, deberías usar la Terminal, eliminar los archivos ocultos (cuyos nombre comienzan con un punto), y luego usar el comando zip en la linea de comandos para crear el archivo zip.

En Linux, podrías también usar la herramienta zip de linea de comandos.

Si tienes el 'Extension Builder' (Constructor de Extensiones) instalado, puede compliar el archivo .xpi para ti (Tools -> Extension Developer -> Extension Builder). Simplemente navega al directorio donde está tu extensión (install.rdf, etc.), y presiona el botón Build Extension. Esta extensión tiene una gran cantidad de herramientas para facilitar el desarrollo.

Ahora carga el archivo .xpi en tu servidor, asegúrate de que es servido como una application/x-xpinstall. Puedes obtener un enlace al mismo y permitir que las personas lo descarguen e instalen. Con el propósito de simplemente testearnuestro archivo .xpi, podemos sólo arrastrarlo en la ventana de extensiones, en Herramientas -> Extensiones para Firefox 1.5.0.x, o  Herramientas -> Complementos para versiones posteriores.

Instalando desde una página web

Existen muchas formas de instalar extensiones desde páginas web, incluyendo enlace directo hacia archivos XPI y usando el objeto InstallTrigger. Los autores web y de extensiones son alentados a usar el  método InstallTrigger para instalar XPIs, ya que provee la mejor experiencia a los usuarios.

Usando addons.mozilla.org

Los Complementos para Firefox es un sitio de distribución donde puedes alojar tu extensión gratuitamente. tu extensión será alojada en un espejo (mirror) de la red de Mozilla para garantizar tu descarga a pesar de que pueda ser muy popular. El sitio de Mozilla también provee una sencilla instalación para los usuarios, y automáticamente hará que tus versiones más nuevas estén disponibles cuando las cargues. Además, los Complementos para Firefox permiten a los usuarios comentar y proveer una retroalimentación en tu extensión. Es altamente recomendado que uses los Complementos de Firefox para distribuir tus extensiones!

Visita http://addons.mozilla.org/developers/ para crearte una cuenta y comenzar a distribuir tus extensiones!

Nota: Tu Extensión será enviada más rápidamente y descargada más veces si tienes una buena descripción y algunas capturas de pantalla de la extensión en acción.

Instalando Extensiones Usando una Instalador Separado

Es posible instalar extensiones en un directorio especial y será instalado la próxima vez que la aplicación comience. La extensión estará disponible para cualquier perfil. Mira  lnstalando extensiones para más información.

En Windows, la información sobre extensiones puede ser agregada al registro, y las extensiones serán recogidas automáticamente la proxima vez que la aplicación comience. Esto permite a los instaladores de aplicaciones agregar fácilmente ganchos de integración como extensiones. Mira Agregando Extensiones usando el Registro de Windows para más información.

Más sobre XUL Overlays

Además de agregar widgets de interfaz de usuario al punto de fusión, puedes usar los fragmentos XUL dentro de los Overlays para controlar la posición de los widgets insertados:

<toolbarbutton position="1" ...  />

<toolbarbutton insertbefore="other-id" ...  />

<toolbarbutton insertafter="other-id" ...  />

Creando Nuevos Componentes de Interfaz de Usuario

Puedes crear tus propias ventanas y cuadros de diálogo como archivos .xul separados, brindando funcionalidad a través de la implementación de acciones de usuarios en archivos .js, usando métodos DOM  para manipular widgets de interfaz de usuario. Puedes usar reglas de estilos en archivos .css para enlazar imágenes, establecer colores, etc.

Mira la documentación XUL con más recursos para los desarrolladores XUL.

Archivos por Defecto

Los archivos por defecto que usas para sembrar un perfil de usuario deberían ser ubicados en defaults/ debajo de la raíz de la jerarquía de carpetas de tu extensión. Los archivos .js de preferencias por defecto deberían ser almacenados en defaults/preferences/ - si los ubicas aquí serán cargados automáticamente por el sistema de preferencias de Firefox cuando arranque, y así podrás accederlos usando la API de Preferencias.

Un archivo de preferencia por defecto de ejemplo:

pref("extensions.sample.username", "Joe"); //a string pref
pref("extensions.sample.sort", 2); //an int pref
pref("extensions.sample.showAdvanced", true); //a boolean pref

Componentes XPCOM

Firefox soporta componentes XPCOM en las extensiones. Puedes crear tus propios componentes fácilmente en JavaScript o en C++ (usando Gecko SDK).

Ubica todos tus archivos .js o .dll en el directorio components/ - son registrados automáticamente la primera vez que se ejecute Firefox luego de que tu extensión es instalada.

Para más información mira Cómo Construir un Componente XPCOM en Javascript, Cómo construir un componente XPCOM binario usando Visual Studio, y el libro Creando Componentes XPCOM.

Línea de Comandos de la Aplicación

Uno de los posibles usos de los componentes XPCOM personalizados, es agregar un manejador de líneas de ocmandos para Firefox o Thunderbird. Puedes usar esta técnica para ejecutar tu extensión como una aplicación:

 firefox.exe -myapp

I should move the useful parts of this to the Command Line page. -Nickolay This is done by adding a component containing the function... function NSGetModule(comMgr, fileSpec) { return myAppHandlerModule; } This function is run by firefox each time firefox is started. Firefox registers the myAppHandlerModule's by calling its 'registerSelf()'. Then it obtains the myAppHandlerModule's handler factory via 'getClassObject()'. The handler factory is then used to create the handle using its 'createInstance(). Finally, the handle's 'handle(cmdline)' processes the command line cmdline's handleFlagWithParam() and handleFlag(). Mira Chrome: Línea de Comandos y un foro de discusión para más detalles.

Localización

Para soportar más de un lenguaje, deberías separar los strings (cadenas de caracteres) de tu contenido usando entidades y envoltorios de strings. Es mucho más fácil hacer esto mientras estás desarrollando tu extensión, en lugar de volver y hacerlo después!

La información de localización es almacenada en el directorio locale para tu extensión. Por ejemplo, para agregar un locale a tu extensión de ejemplo, crea dos directorios anidados "locale/en-US" en chrome (donde está ubicado el directorio "content") y agrega la siguiente línea al archivo chrome.manifest:

locale sample en-US chrome/locale/en-US/

Para crear valores de atributo localizables en XUL, puedes ubicar los valores en un archivo .dtd (sample.dtd para tu extensión de prueba). Este archivo debería ser ubicado en el directorio locale y se parece a esto:

<!ENTITY  my-panel.label  "Hello, World">

Luego incluyélo el comienzo de tu documento XUL (pero debajo de"<?xml version"1.0"?>"), como se ve a continuación:

<?xml version="1.0"?>
<!DOCTYPE window SYSTEM "chrome://packagename/locale/filename.dtd">
...

donde window es el valor localName (nombre local) del elemento raíz del documento XUL, y el valor de la propiedad SYSTEM es la URI chrome hacia el archivo de entidad.

Para nuestra extensión de ejemplo, reemplaza window con overlay (elemento raíz), packagename con sample, y filename.dtd con sample.dtd.

Para usar las entidades, modifica tu XUL para que se vea así:

<statusbarpanel id="my-panel" label="&my-panel.label;"  />

El Registro de Chrome se asegurará que el archivo de entidad es cargado desde el envoltorio de localización que se corresponda con la configuración regional seleccionada.

Para los strings que usas en script, crea un archivo .propertie, un archivo de texto que tiene un string en cada lína en este formato:

clave=valor

y luego usa nsIStringBundleService/nsIStringBundle o el tag stringbundle para cargar valores en el script.

Entendiendo el Navegador

Usa el Inspector DOM para inspeccionar la ventana del navegador o cualquier otra ventana XUL que quieras extender.

Nota: El Inspector DOM no es parte de la instalación Estándar de Firefox. Desde Firefox 3 Beta 4, el Inspector DOM está disponible desde Los Complementos de Firefox como una extensión por separado. Para versiones anteriores, debes reinstalar con la dirección de instalación Personalizada y seleccionar Inspector DOM (o Developer Tools en Firefox 1.5) si no hay un ítem "Inspector DOM" en el menú de herramientas de tu navegador.

Usa el botón apunta-y-clickea sobre un nodo en el tope izquierdo de la barra de herramientas del Inspector DOM para clickear sobre un nodo en la ventana XUL, para seleccionar visualmente. Cuando haces esto, el inspector salta en el árbol de jerarquía DOM hacia el nodo que ha sido clickeado.

Usa el panel lateral derecho del Inspector DOM para descubrir puntos de fusión con ids que puedas usar para insertar tus elementos desde overlays. Si no puedes encontrar un elemento con un id que puedas fusionar, podrías necesitar enlazar un script en tu overlay e insertar tus elementos cuando se dispare el evento load en la ventana XUL maestra.

Depurando Extensiones

Herramientas Analíticas para Depuración

  • El inspector DOM - inspecciona atributos, estructura DOM, reglas de estilo CSS que están activas (ej., averigua porqué tus reglas de estilo no parecen estar funcionando para un elemento - una herramienta invaluable!)
  • Venkman - configura puntos de quiebre (breakpoints) en JavaScript e inspecciona pilas de llamadas.
  • Components.stack.caller> en JavaScript - accede a la pila de llamada de una función

Depuración con printf

Depuración avanzada

  • Ejectua un build de Firefox para depuración y configura puntos de quiebre en Firefox mismo, o tus componentes en C++. Para el desarollador experimentado, esta es frecuentemente la forma más rápida de diagnosticar un problema. Mira Build Documentation y Developing Mozilla para más información.
  • Mira Depurando una Aplicación XULRunner para más consejos útiles.

Más Información

Etiquetas y colaboradores del documento

 Colaboradores en esta página: martin.weingart, Josele89
 Última actualización por: martin.weingart,