Este é um tutorial "Olá Mundo" para a criação de um componente XPCOM em JavaScript. Este tutorial não descreve como e por que XPCOM funciona da maneira que faz, ou o que cada bit do código de exemplo faz. Isso foi detalhado em outro lugar. Este tutorial irá mostrar-lhe o que você precisa fazer para obter um componente de trabalho como poucos e como passos mais simples possível.
Implementação
Este componente exemplo, irá expor um único método, que retorna a string "Olá Mundo!".
Definindo a Interface
Se você quiser usar o componente em outras componentes XPCOM, você deve definir as interfaces que você deseja expor. Se você quiser usar o seu único componente de JavaScript, você pode pular para a próxima seção.
Há muitas interfaces já definidas nos aplicativos Mozilla, então você pode não precisar de definir um novo. Você pode procurar as interfaces XPCOM existentes em vários locais no código fonte Mozilla, ou usando XPCOMViewer, uma interface gráfica para navegar interfaces e componentes registrados. Você pode baixar uma versão antiga do XPCOMViewer que funciona com Firefox 1.5 a partir de mozdev mirrors.
Se existe uma interface que atenda às suas necessidades, então você não precisa escrever uma IDL, ou compilar uma biblioteca de tipos, e pode pular para a próxima seção.
Se você não encontrar uma relação pré-existente adequada, em seguida, você deve definir o seu próprio. XPCOM usa um dialeto do IDL para definir interfaces, chamada XPIDL. Aqui está a definição XPIDL para o nosso componente Olá Mundo:
HelloWorld.idl
#include "nsISupports.idl" [scriptable, uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)] interface nsIHelloWorld : nsISupports { string hello(); };
Observe que você deve gerar um novo UUID para cada componente XPCOM que você criar. ver Generating GUIDs para mais informações.
Compilando o Typelib
Sua definição de interface deve ser compilado em um formato binário (XPT), a fim de ser registrado e usado em aplicativos Mozilla. A compilação pode ser feito usando o Gecko SDK. Você pode aprender como obter Mac, Linux e versões do Windows do Gecko SDK lendo o artigo Gecko SDK.
Para o código de fora da árvore
Executar este comando para compilar o typelib. Aqui, {sdk_dir}
é o diretório no qual você descompactou o Gecko SDK.
{sdk_dir}/bin/xpidl -m typelib -w -v -I {sdk_dir}/idl -e HelloWorld.xpt HelloWorld.idl
Isto irá criar o arquivo HelloWorld.xpt typelib no diretório de trabalho atual.
Para um novo componente em Firefox/Thunderbird/B2G
Se você estiver adicionando uma nova funcionalidade para aplicações no repositório mozilla-central, você pode criar um Makefile listando os arquivos IDL e o sistema de compilação irá gerar automaticamente o typelib. A amostra Makefile.in
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
# MODULE specifies where header files from this Makefile are installed
# Use dom if your component implements a DOM API
MODULE = dom
# Name of the typelib
XPIDL_MODULE = dom_apps
# Set to 1 if the module should be part of the Gecko Runtime common to all applications
GRE_MODULE = 1
# The IDL sources
XPIDLSRCS = \
HelloWorld.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk
XPIDL_FLAGS += \
-I$(topsrcdir)/dom/interfaces/base \
-I$(topsrcdir)/dom/interfaces/events \
$(NULL)
Criando o componente usando XPCOMUtils
em Firefox 3 e mais tarde você pode usar importação XPCOMUtils.jsm utilização Components.utils.import para simplificar o processo de escrever o seu componente ligeiramente. A biblioteca importada contém funções para gerar o módulo, a fábrica, e os NSGetModule e QueryInterface funções para você. Nota: ele não faz o trabalho de criar o arquivo de definição de interface ou a biblioteca de tipos para você, então você ainda tem que passar por essas etapas anteriores, caso não tenham sido feito. A biblioteca proporciona um exemplo simples de sua utilização no código fonte (js/src/xpconnect/loader/XPCOMUtils.jsm
), mas aqui é outro usando este exemplo. Para começar, inclua uma linha no topo da sua interface para importar a biblioteca XPCOMUtils:
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
em seguida, implementar a interface da mesma forma que fiz acima, exceto com algumas modificações para que XPCOMUtils pode configurá-lo corretamente:
/*********************************************************** class definition ***********************************************************/ //class constructor function HelloWorld() { // If you only need to access your component from Javascript, uncomment the following line: //this.wrappedJSObject = this; } // class definition HelloWorld.prototype = { // properties required for XPCOM registration: classDescription: "My Hello World Javascript XPCOM Component", classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"), contractID: "@dietrich.ganx4.com/helloworld;1", // [optional] custom factory (an object implementing nsIFactory). If not // provided, the default factory is used, which returns // |(new MyComponent()).QueryInterface(iid)| in its createInstance(). _xpcom_factory: { ... }, // [optional] an array of categories to register this component in. _xpcom_categories: [{ // Each object in the array specifies the parameters to pass to // nsICategoryManager.addCategoryEntry(). 'true' is passed for both // aPersist and aReplace params. category: "some-category", // optional, defaults to the object's classDescription entry: "entry name", // optional, defaults to the object's contractID (unless 'service' is specified) value: "...", // optional, defaults to false. When set to true, and only if 'value' is not // specified, the concatenation of the string "service," and the object's contractID // is passed as aValue parameter of addCategoryEntry. service: true }], // QueryInterface implementation, e.g. using the generateQI helper (remove argument if skipped steps above) QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIHelloWorld]), // Optional, but required if you want your component to be exposed to DOM classInfo: XPCOMUtils.generateCI({classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"), contractID: "@dietrich.ganx4.com/helloworld;1", interfaces: [Ci.nsIHelloWorld], flags: Ci.nsIClassInfo.DOM_OBJECT}), // ...component implementation... // define the function we want to expose in our interface hello: function() { return "Hello World!"; }, };
XPCOMUtils faz o trabalho de criação do módulo e da fábrica para você depois disso. Finalmente, você cria uma matriz de seus componentes a serem criados:
var components = [HelloWorld];
e substituir NSGetFactory / NSGetModule usar essa matriz e XPCOMUtils:
if ("generateNSGetFactory" in XPCOMUtils) var NSGetFactory = XPCOMUtils.generateNSGetFactory(components); // Firefox 4.0 and higher else var NSGetModule = XPCOMUtils.generateNSGetModule(components); // Firefox 3.x
Assim, a versão simplificada do total de seu componente agora parece (é claro que a documentação e os comentários não são uma coisa ruim, mas como um modelo algo menor é bom ter):
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); function HelloWorld() { } HelloWorld.prototype = { classDescription: "My Hello World Javascript XPCOM Component", classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"), contractID: "@dietrich.ganx4.com/helloworld;1", QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIHelloWorld]), hello: function() { return "Hello World!"; } }; var components = [HelloWorld]; if ("generateNSGetFactory" in XPCOMUtils) var NSGetFactory = XPCOMUtils.generateNSGetFactory(components); // Firefox 4.0 and higher else var NSGetModule = XPCOMUtils.generateNSGetModule(components); // Firefox 3.x
Instalação
para extensões:
- Helloworld.js copiar e HelloWorld.xpt (só se você tiver definido e compilou o IDL) para
{extensiondir}/components/
. - Excluir compreg.dat e xpti.dat do seu diretório de perfil.
- reinicie o aplicativo.
Para Firefox:
- Helloworld.js copiar e HelloWorld.xpt (só se você tiver definido e compilou o IDL) para o
{objdir}/dist/bin/components
directory, se correr a partir da fonte. - Excluir compreg.dat e xpti.dat do diretório componentes.
- Excluir compreg.dat e xpti.dat do seu diretório de perfil.
- reinicie o aplicativo.
Usando o Componente
Usando wrappedJSObject
Se você só pretende aceder à sua componente de Javascript, ou seja, você pulou as seções "Definindo a Interface" e "Compilando o Typelib" acima, é comentada a linha "wrappedJSObject" no construtor da classe, e removido o "[Components.interfaces.nsIHelloWorld]" argumento para a chamada para XPCOMUtils.generateQI() em QueryInterface, então você pode acessar o seu componente da seguinte forma:
try { var myComponent = Components.classes['@dietrich.ganx4.com/helloworld;1'] .getService().wrappedJSObject; alert(myComponent.hello()); } catch (anError) { dump("ERROR: " + anError); }
Para mais informações sobre wrappedJSObject, veja aqui.
Usando instanciação XPCOM
try { var myComponent = Components.classes['@dietrich.ganx4.com/helloworld;1'] .createInstance(Components.interfaces.nsIHelloWorld); alert(myComponent.hello()); } catch (anError) { dump("ERROR: " + anError); }
Outros recursos
- Dois fóruns tópicos mozillazine sobre a implementação de componentes XPCOM em JS com algumas explicações, exemplo de código e dicas para solução de problemas:
- Implementing XPCOM components in JavaScript at kb.mozillazine.org
- Using XPCOM in JavaScript without leaking - A must-read.
- An example component
- Older JS+XPCOM notes - inclui algumas informações wrappedJSObject.
- Writing an XPCOM Service in javascript
Tradução para o portugues(Brasil) : Josimar de souza
contato : [email protected]
site : Portal do Barulho