记录与分享,鉴于gecko中编写XPCOM组件的文档都极度过时(基本是基于2006年版的变体),我搬砖尝试好久才写出两个组件。老文档代码部分参考价值不高,下面将自己写xpcom组件的成果分享如下,
一篇写js实现的,一篇写c++实现的。
ffos (gecko):如何在gecko 中编写XPCOM组件(一)--javascript 实现方式
ffos (gecko):如何在gecko 中编写XPCOM组件(二)--C++ 实现方式
xpcom refference links XPCM相关供有需要的搬砖同道参考,有错误的地方,欢迎指正。
关于XPCOM的扫盲材料可参考MDN,或者
说明:
开发环境,ubuntu + FFOS 源码。
uuid 用uuidgen 命令生成。
涉及到的目录及文件及其作用原理:
ffos 源码中:
一.组件编写
1.js 组件最终目录结构:
gecko/dom/simplejs/
simplejs
├── moz.build
├── nsISimplejs.idl
├── nsIUseComponent.idl
├── Simplejs.js
├── Simplejs.manifest
├── UseComponent.js
└── UseComponent.manifest
2.组件实现:
(1)nsISimplejs.idl 接口定义文件
#include "nsISupports.idl"
[scriptable, uuid(ce32e3ff-36f8-425f-94be-d85b26e634ee)]
interface nsISimpleComponent : nsISupports
{
attribute string yourName;
void write();
void changejs(in string aValue);
};
(2)Simplejs.js nsISimplejs.idl的实现文件
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function SimpleComponentImpl() {
debug("yahaha,constructor SimpleComponentImpl constructor in simplecomponent.js################");
}
//dump("yahaha,dump,im SimpleComponentImpl in simplecomponent.js######################### before prototype");
SimpleComponentImpl.prototype = {
contractID : "@mozilla.org/simplejs;1",
classID: Components.ID("{cc587afa-0696-469f-9eff-9dac0dd727fe}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleComponent]),
get yourName(){
return this.mName;
},
set yourName(aName){
return this.mName = aName;
},
write: function(){
dump("yahaha,SimpleComponentImpl.write()");
dump("Hello " + this.mName + "\n");
},
changejs: function(aValue){
this.mName = aValue;
dump("Hello " + this.mName + "\n");
},
mName: "Anonymous!",
};//the implement of interfaces in .idl
//dump("yahaha,dump,in simplecomponent.js###############before generateNSGetFactory");
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SimpleComponentImpl]);//get factory
//dump("yahaha SimpleComponent.js ooooooooooooooooooooooooooooooooooooooooo");
(3)Simplejs.manifest 组件注册清单文件
# Simplejs.js
component {cc587afa-0696-469f-9eff-9dac0dd727fe} Simplejs.js
contract @mozilla.org/simplejs;1 {cc587afa-0696-469f-9eff-9dac0dd727fe}
category profile-after-change simplecomponent @mozilla.org/simplejs;1
(4)在gecko/b2g/installer/package-manifest.in
dom_simplejs.xpt是moz.build 指定生成的xpt模块。见moz.build部分。
添加:
@RESPATH@/components/dom_simplejs.xpt
@RESPATH@/components/Simplejs.js
@RESPATH@/components/Simplejs.manifest
(5)moz.build
编译文件。写法如下:
# vim: set filetype=python:
XPIDL_MODULE = 'dom_simplejs'
XPIDL_SOURCES += [
'nsISimplejs.idl',
]
EXTRA_COMPONENTS += [
'Simplejs.js',
'Simplejs.manifest',
]
include('/ipc/chromium/chromium-config.mozbuild')
ALLOW_COMPILER_WARNINGS=True
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
(6)在gecko/dom/ 目录下在moz.build中将simplejs文件夹添加进去
DIRS += [
... 这里省略很多目录...
'simplejs',
]
开始编译,通过,刷机。
以上,js 实现的组件的实现及注册添加完成。
二.调用组件
理论上,可以在gecko 源码中任何组件中调用注册好的js 组件。这里我自己再写一个组件来调用刚刚写好的组件就好。
流程跟上面的完全一样。仍然在gecko/dom/simplejs/目录下
(1)nsIUseComponent.idl 其实可有可无,目的是调用我们写了的组件,具体的接口我没去实现。
#include "nsISupports.idl"
[scriptable, uuid(6632e3ff-36f8-425f-94be-d85b26e634ee)]
interface nsIUseComponent : nsISupports
{
void sayhi();
};
(2)UseComponent.js
接口实现文件,其实这里我没去实现,醉翁之意不在酒,主要为了调用写成功了的组件。
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const USECOMPONENT_CONTRACTID = "@mozilla.org/usecomponent;1";
const USECOMPONENT_CID =
Components.ID("{1ff24790-5e74-11e1-b86c-0800200c9a66}");
//
//test of javascript component
///
dump("yahaha,========>start: javascript component==================>");
var usecompo =Cc["@mozilla.org/simplejs;1"].createInstance(Components.interfaces.nsISimpleComponent);
var result = usecompo.yourName;//the interface name in .idl
dump("yahaha,...result: yourName = "+result);
usecompo.changejs("yahaha,change after yourName");//call changejs() interface
dump("yahaha,========>end: javascript component====================>\n ");
///Test of other exist cpp component
dump("yahaha,==========>start test1....instance of other cpp component in usecomponent.js ");
var nfcservi =Cc["@mozilla.org/nfc/service;1"].createInstance(Components.interfaces.nsINfcService);
dump("yahaha,nfc,,,,,,"+nfcservi);
dump("yahaha,=========>end test1 ===================================>\n ");
///
//the implement part of this component itself
function useComponentImpl(){
dump("yahaha,this is a null component in useComponentImpl");
}
useComponentImpl.prototype={
//const USECOMPONENT_CONTRACTID = "@mozilla.org/usecomponent;1";
//const USECOMPONENT_CID =Components.ID("{1ff24790-5e74-11e1-b86c-0800200c9a66}");
contractID : USECOMPONENT_CONTRACTID,
classID: USECOMPONENT_CID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUseComponent]),
duuuump:function(){ dump("yahaha, hello world???");
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([useComponentImpl]);//part of register code
(3)UseComponent.manifest
注册清单文件。
component {1ff24790-5e74-11e1-b86c-0800200c9a66} UseComponent.js
contract @mozilla.org/usecomponent;1 {1ff24790-5e74-11e1-b86c-0800200c9a66}
category profile-after-change usecomponent @mozilla.org/usecomponent;1
(4)在gecko/b2g/installer/package-manifest.in
添加:
@RESPATH@/components/dom_simplejs.xpt
@RESPATH@/components/UseComponent.js
@RESPATH@/components/UseComponent.manifest
而两个组件所添加的合起来如下:
@RESPATH@/components/dom_simplecpp.xpt
@RESPATH@/components/dom_simplejs.xpt
@RESPATH@/components/Simplejs.js
@RESPATH@/components/Simplejs.manifest
@RESPATH@/components/UseComponent.js
@RESPATH@/components/UseComponent.manifest
(5)moz.build
编译文件。两个组件的编译文件如下:
# vim: set filetype=python:
XPIDL_MODULE = 'dom_simplejs'
XPIDL_SOURCES += [
'nsISimplejs.idl',
'nsIUsecomponent.idl',
]
EXTRA_COMPONENTS += [
'Simplejs.js',
'Simplejs.manifest',
'UseComponent.js',
'UseComponent.manifest',
]
include('/ipc/chromium/chromium-config.mozbuild')
ALLOW_COMPILER_WARNINGS=True
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
编译通过,刷机,adb logcat 看log.
最后的adb logcat结果:
adb logcat|grep -in yahaha
360:I/Gecko ( 180): yahaha,dump,im SimpleComponentImpl in simplecomponent.js######################### before prototype
361:I/Gecko ( 180): yahaha SimpleComponent.js ooooooooooooooooooooooooooooooooooooooooo
363:I/Gecko ( 180): yahaha,========>start: javascript component==================>
364:I/Gecko ( 180): yahaha,...result: yourName = Anonymous!
365:I/Gecko ( 180): Hello yahaha,change after yourName
366:I/Gecko ( 180): yahaha,========>end: javascript component====================>
368:I/Gecko ( 180): yahaha,==========>start test1....instance of other cpp component in usecomponent.js
369:I/Gecko ( 180): yahaha,nfc,,,,,,[xpconnect wrapped nsINfcService]
370:I/Gecko ( 180): yahaha,=========>end test1 ===================================>
///分割线//
以下是草稿及踩的坑,不用看。
最后的log结果:
360:I/Gecko ( 180): yahaha,dump,im SimpleComponentImpl in simplecomponent.js######################### before prototype
361:I/Gecko ( 180): yahaha SimpleComponent.js ooooooooooooooooooooooooooooooooooooooooo
363:I/Gecko ( 180): yahaha,========>start: javascript component==================>
364:I/Gecko ( 180): yahaha,...result: yourName = Anonymous!
365:I/Gecko ( 180): Hello yahaha,change after yourName
366:I/Gecko ( 180): yahaha,========>end: javascript component====================>
368:I/Gecko ( 180): yahaha,==========>start test1....instance of other cpp component in usecomponent.js
369:I/Gecko ( 180): yahaha,nfc,,,,,,[xpconnect wrapped nsINfcService]
370:I/Gecko ( 180): yahaha,=========>end test1 ===================================>
372:I/Gecko ( 180): yahahacpp,==========>start,test of cpp component==================>
373:I/ ( 180): yohoho,yahahacpp,log from gecko dom simplecpp.cpp component,nsSimplecpp()
374:I/Gecko ( 180): yahahacpp,before change()
375:I/ ( 180): yohoho,yahahacpp,log from gecko dom simplecpp.cpp,Change()
377:I/ ( 180): yahaha,log from simplecpp.cpp after Changechange()
378:I/Gecko ( 180): yahahacpp,============>end of cpp component test====================>
380:I/ ( 180): yohoho,yahahacpp,log from simplecpp.cpp component,Usecomponent()
382:I/ ( 180): yahaha,log from simplecpp.cpp Usecomponent()
383:I/Gecko ( 180): yahahacpp,after Simplecpp.usecomponent() result of usecomponent:undefined
384:I/Gecko ( 180): yahaha,this is a null component in useComponentImpl
在gecko/b2g/installer/package-manifest.in
添加:
@RESPATH@/components/dom_simplecpp.xpt
@RESPATH@/components/dom_simplejs.xpt
@RESPATH@/components/Simplejs.js
@RESPATH@/components/Simplejs.manifest
@RESPATH@/components/UseComponent.js
@RESPATH@/components/UseComponent.manifest
UseComponent.js 组件调用文件
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const USECOMPONENT_CONTRACTID = "@mozilla.org/usecomponent;1";
const USECOMPONENT_CID =
Components.ID("{1ff24790-5e74-11e1-b86c-0800200c9a66}");
//
/*修改大纲:
1. cpp component unfine ,rewrite it by imitate
log in other cpp component to see
1)the register and
2)the call
2. use other component to repaire,
change the name of component and
call it in js
3. js call the component in wrong method ,so get failure X
4. call it from an running cpp component such as nfc
5. get how the component call from register if no js to use it X
there should be a js function to call the component ,instance it
*/
///
//dump("yahaha,中文中文中文中文");
/*
*var debug;
*var DEBUG = 1;// 1 to turn on the debuge,0 to turn off it
*function updateDebug() {
* if (DEBUG) {
* debug = function (s) {
* dump("-*-yahahaaaaaaaaaa usecomponent.js ooooooooo : " + s + "\n");
* };
* } else {
* debug = function (s) {};
* }
*};
*updateDebug();
*/
/*
*
*var debug = function (s) {
* dump("-*-yahahaaaaaaaaaa usecomponent.js ooooooooo : " + s + "\n");
* };
*/
//test of javascript component
///
dump("yahaha,========>start: javascript component==================>");
var usecompo =Cc["@mozilla.org/simplejs;1"].createInstance(Components.interfaces.nsISimpleComponent);
var result = usecompo.yourName;//the interface name in .idl
//var result = usecompo.yourName('HACKER_EELLO');
dump("yahaha,...result: yourName = "+result);
usecompo.changejs("yahaha,change after yourName");
dump("yahaha,========>end: javascript component====================>\n ");
///Test of other exist component
dump("yahaha,==========>start test1....instance of other cpp component in usecomponent.js ");
var nfcservi =Cc["@mozilla.org/nfc/service;1"].createInstance(Components.interfaces.nsINfcService);
dump("yahaha,nfc,,,,,,"+nfcservi);
dump("yahaha,=========>end test1 ===================================>\n ");
///summary///
/*
the component ,any component can be instance at once by a lot of programs
this is the core techknowledge of xpcom
and you can instance it in any language you like which surpport xpcom
*/
/
//use c++ component
dump("yahahacpp,==========>start,test of cpp component==================>");
var Simplecpp =Cc["@mozilla.org/simplecpp;1"].createInstance(Components.interfaces.nsISimplecpp);
/log messages///
//[JavaScript Error: "NS_ERROR_XPC_BAD_IID: Component returned failure code: 0x80570018 (NS_ERROR_XPC_BAD_IID) [nsIJSCID.createInstance]" {file: "jar:file:///system/b2g/omni.ja!/components/usecomponent.js" line: 68}]
/*
*
*in xpc.msg
*XPC_MSG_DEF(NS_ERROR_XPC_BAD_IID , "Invalid InterfaceID")
*XPC_MSG_DEF(NS_ERROR_XPC_BAD_CID , "Invalid ClassID or ContractID")
*
XPC_MSG_DEF(NS_ERROR_XPC_NATIVE_RETURNED_FAILURE , "Component returned failure code:")
*/
bug analyze/
/*
说明c++里面没注册好?这个位置已经不是注册,而是调用,调用时实例化对象失败了。。。
so the reason why didnt work is that the component itself has some problems
//var usecompo =Cc["@mozilla.org/simplecomponent;1"].createInstance(Components.interfaces.nsISimpleComponent);
//here error take place ,cannot create instance of simplecpp component
//no no ,can instance but the component return bad value the component itself wrong
能找到组件,但是组件返回错误代码,
能通过注册,能通过contract id 找到组件,
问题在于组件本身,它返回了错误的代码,
说明组件写的有问题。可以通过瞎改其他有效组件来验证
*/
//reason analyze : component must be unfinished,
//1.create cpp component ....maybe something wrong
//2.register component ....the method to register component maybe wrong
//3.use component ....the method to use component can be sure right
bug fixed///
/*
*
* bug fixed
*the real reason is that xpt hasnt add into package-manifest,
*for cpp component it seemed to be nessysery
*for js component ,i forget to add it ,but can instance component success
vim gecko/b2g/installer/package-manifest.in
what is the file do
*/
/
dump("yahahacpp,before change()");
var result_simplecpp = Simplecpp.change("daye");
//dump("yahahacpp,after change() ");
//var result_simplecpp1 = Simplecpp.yourName;
//dump("yahahacpp,after :yourName: "+result_simplecpp1);
//Simplecpp.write();
//dump("yahahacpp,after Simplecpp.write()");
dump("yahahacpp,============>end of cpp component test====================>\n ");
var atest = Simplecpp.usecomponent("Atest");//cannot use with unknown reason
dump("yahahacpp,after Simplecpp.usecomponent() result of usecomponent:"+atest);
///
function useComponentImpl(){
dump("yahaha,this is a null component in useComponentImpl");
}
useComponentImpl.prototype={
//const USECOMPONENT_CONTRACTID = "@mozilla.org/usecomponent;1";
//const USECOMPONENT_CID =
//Components.ID("{1ff24790-5e74-11e1-b86c-0800200c9a66}");
contractID : USECOMPONENT_CONTRACTID,
//"@mozilla.org/simplejs;1",
classID: USECOMPONENT_CID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUseComponent]),
duuuump:function(){ dump("yahaha, hello world???");
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([useComponentImpl]);