ffos(gecko):gecko下XPCOM组件开发参考文档(合)

前面分开写了js 和C++ 的实现,

ffos (gecko):如何在gecko 中编写XPCOM组件(一)--javascript 实现方式

ffos (gecko):如何在gecko 中编写XPCOM组件(二)--C++ 实现方式

xpcom refference links XPCM相关

整理了文档,一起贴上来。

geckoXPCOM组件参考文档

 

版本历史

版本号

作者

日期

备注

V1.0

h

2018.07.06


目录

目录 1

摘要 1

1. XPCOM技术 2

1.1 XPCOM是什么 2

1.2 XPCOM 架构 2

2. XPCOM组件开发 3

2.1 javascript实现方式 5

2.2 C++实现方式



摘要

XPCOMgecko核心技术本文尝试gecko添加两个简单XPCOM组件展示XPCOM基本开发示例提供一些参考

1. XPCOM 技术

1.1 XPCOM是什么

XPCOM 的目标是使软件的不同部分分别开发, 相互独立. 为了是应用的不同组件之间能够互操作, XPCOM 把组件的实现与接口(后面讨论接口)分开. 同时 XPCOM 还提供了加载和操纵这些组件的库和工具以及服务, 以帮助开发人员编写跨平台的代码和组件版本管理; 因此组件可以在不破坏应用或者重新生成应用的同时被替换被更新. 通过使用 XPCOM, 开发人员创建的组件可以在不同的应用中被重用, 或者替换当前应用中的组件以改变应用的功能.

XPCOM 不只提供组件软件开发的支持, 它同时提供一个开发平台的大多数功能的支持:

组件管理

文件抽象

对象消息传递

内存管理

可以 XPCOM 想象成一个 组件开发平台, 它提供了上面的这些特性

Gecko 应用核心技术相当microsoft COM技术又是借鉴广,理解,扩展gecko 本身js实现提供webidl接口的实现文件调用,可以下层进行封装

1.2 XPCOM架构

Gecko XPCOM关系可以简单粗暴理解gecko=XPCOM组件

2. XPCOM 组件开发

介绍geckoXPCOM 组件写法框架 

2.1 javascript实现方式

涉及到的目录及文件及其作用原理:

2.1.1 js组件编写

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.jsnsISimplejs.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.manifest

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.xptmoz.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 实现的组件的实现及注册添加完成。

2.1.2 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 existcpp 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

 

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 ===================================>

2.2 C++ 实现方式

2.2.1 C++ 组件编写

gecko/dom/一个文件simplecpp,simplecpp添加gecko/dom/moz.build

DIRS += [

... 这里省略很多目录...

'simplecpp',

]

最后整个目录结构如下:

simplecpp/

├── moz.build

├── nsISimplecpp.idl

├── Simplecpp.cpp

└── Simplecpp.h

(1)nsISimplecpp.idl接口定义

nsISimplecpp.idl

#include "nsISupports.idl"

[scriptable, uuid(fd306b58-02de-4dc7-a512-f1ade5cf6840)]

interface nsISimplecpp : nsISupports

{

    attribute string yourName;

    void write( );

    void change(in string aValue);

    void usecomponent(in string aValue1);

};

(2)Simple.h

nsISimplecpp.hnsISimplecpp.idl 生成的文件objdir-gecko/dist/include/文件里面包含了组件实现文件头文件模板cpp文件模板。/*Header file*/开始代码复制实现文件头文件

/* Use the code below as a template for the implementation class for this interface. */

/* Header file */ 这里开始

class nsSimplecpp : public nsISimplecpp

{

public:

  NS_DECL_ISUPPORTS

  NS_DECL_NSISIMPLECPP

 

  nsSimplecpp();

 

private:

  ~nsSimplecpp();

 

protected:

  /* additional members */

};

完整头文件如下:

#ifndef mozilla_dom_simplecpp_simplecpp_h

#define mozilla_dom_simplecpp_simplecpp_h

 

#include "nsCOMPtr.h"

#include "nsISimplecpp.h"

 

namespace mozilla {

class nsSimplecpp final: public nsISimplecpp//nsISimplecpp 接口类中继承一个类

{

public:

  NS_DECL_ISUPPORTS

  NS_DECL_NSISIMPLECPP

  //static already_AddRefed<nsSimplecpp> FactoryCreate();

  nsSimplecpp();

private:

  virtual  ~nsSimplecpp();

protected:

  /* additional members */

};//扩展按需要添加函数进行扩展

}//naemspace mozilla

 

#endif

 (3) Simple.cpp

/* Implementation file */开始/* End of implementation class template. */之间的代码复制实现文件Simple.cpp.

/* Implementation file */

NS_IMPL_ISUPPORTS(nsSimplecpp, nsISimplecpp)

 

nsSimplecpp::nsSimplecpp()

{

  /* member initializers and constructor code */

}

 

nsSimplecpp::~nsSimplecpp()

{

  /* destructor code */

}

 

/* attribute string yourName; */

NS_IMETHODIMP nsSimplecpp::GetYourName(char * *aYourName)

{

    return NS_ERROR_NOT_IMPLEMENTED;

}

NS_IMETHODIMP nsSimplecpp::SetYourName(const char * aYourName)

{

    return NS_ERROR_NOT_IMPLEMENTED;

}

 

/* void write (); */

NS_IMETHODIMP nsSimplecpp::Write()

{

    return NS_ERROR_NOT_IMPLEMENTED;

}

 

/* void change (in string aValue); */

NS_IMETHODIMP nsSimplecpp::Change(const char * aValue)

{

    return NS_ERROR_NOT_IMPLEMENTED;

}

 

/* void usecomponent (in string aValue1); */

NS_IMETHODIMP nsSimplecpp::Usecomponent(const char * aValue1)

{

    return NS_ERROR_NOT_IMPLEMENTED;

}

/* End of implementation class template. */

具体的实现文件如下

#include "Simplecpp.h"

#include "utils/Log.h"

#include "nsISimplejs.h"//test of call js component in cpp,failed

#include <cutils/properties.h>

#include "mozilla/dom/ToJSValue.h"

#include "mozilla/ModuleUtils.h"

#include "nsAutoPtr.h"

 

#define NS_SIMPLECPP_CID \

{0x668abcee, 0x29cc, 0x43e9, \

    { 0x8a, 0x97, 0x9d, 0x3c, 0x0b, 0x67, 0xae, 0x8b }}

#define NS_SIMPLECPP_CONTRACTID "@mozilla.org/simplecpp;1"

 

using namespace mozilla::dom;

namespace mozilla {

 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Implementation file */

NS_IMPL_ISUPPORTS(nsSimplecpp, nsISimplecpp)

 

nsSimplecpp::nsSimplecpp()

{   

    MOZ_ASSERT(NS_IsMainThread());

    //MOZ_ASSERT(!gnsSimplecpp);

    ALOGI("yohoho,yahahacpp,log from gecko dom simplecpp.cpp component,nsSimplecpp()");

  /* member initializers and constructor code */

}

 

nsSimplecpp::~nsSimplecpp()

{

  /* destructor code */

}

 

/* attribute string yourName; */

NS_IMETHODIMP nsSimplecpp::GetYourName(char * *aYourName)

{

    ALOGI("yohoho,yahahacpp,log from gecko dom simplecpp component,GetYourName()");

    //return "MarkTwin";

    return NS_OK;

}

 

NS_IMETHODIMP nsSimplecpp::SetYourName(const char * aYourName)

{

    ALOGI("yohoho,yahahacpp,log from gecko dom simplecpp component,SetYourName()");

    return NS_OK;

}

 

/* void write (); */

NS_IMETHODIMP nsSimplecpp::Write()

{

    ALOGI("yohoho,yahahacpp,log from gecko dom simplecpp.cpp component,Write()");

    return NS_OK;

}

 

/* void change (in string aValue); */

NS_IMETHODIMP nsSimplecpp::Change(const char * aValue)

{

    ALOGI("yohoho,yahahacpp,log from gecko dom simplecpp.cpp,Change()");

    nsCOMPtr<nsISimpleComponent> SimpleService=

        do_CreateInstance("@mozilla.org/simplejs;1");

    if (!SimpleService) {

        ALOGI("yahaha,no Component available");

          }

    SimpleService->Changejs("anonymous====>");// in .h unfinished

    ALOGI("yahaha,log from simplecpp.cpp after Changechange()");

    return NS_OK;

}

 

 

//use the js component, cannot use this function with unknown reason  

/* void usecomponent (in string aValue1); */

NS_IMETHODIMP nsSimplecpp::Usecomponent(const char * aValue1)

{

    ALOGI("yohoho,yahahacpp,log from simplecpp.cpp component,Usecomponent()");

        nsCOMPtr<nsISimpleComponent> SimpleService=

        do_CreateInstance("@mozilla.org/simplejs;1");

    if (!SimpleService) {

        ALOGI("yahaha,no Component available");

          }

    //SimpleService->yourName;

    //SimpleService->changejs("anonymous====>");//if cannot use idl interface ,what make u to use js component  

    ALOGI("yahaha,log from simplecpp.cpp Usecomponent()");

    return NS_OK;

}

/* End of implementation class template. */

 

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//register the component

//以下是组件注册部分,十分重要,不进行注册,你的组件写的就是些废代码,编译不报错也没用,其他组件不能调用。这一部分也可以跟其他组件合一起集中注册,按此结构即可。

/*

 *NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSimplecpp,

 *                                         nsSimplecpp::FactoryCreate)

//SINGLETON模式一个FactoyCreate()

  */

 

NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimplecpp)//构造

 

NS_DEFINE_NAMED_CID(NS_SIMPLECPP_CID);//定义你CID

 

static const mozilla::Module::CIDEntry knsSimplecppCIDs[] = {

        { &kNS_SIMPLECPP_CID, false, nullptr, nsSimplecppConstructor },

        { nullptr }

    };

 

static const mozilla::Module::ContractIDEntry knsSimplecppContracts[] = {

    { NS_SIMPLECPP_CONTRACTID, &kNS_SIMPLECPP_CID },

    { nullptr }

};

 

static const mozilla::Module knsSimplecppModule = {//你的组件模块信息

    mozilla::Module::kVersion,

    knsSimplecppCIDs,

    knsSimplecppContracts,

    nullptr

};

 

}// namespace mozilla

 

NSMODULE_DEFN(nsSimplecppModule) = &mozilla::knsSimplecppModule;//注册你的组件

(4)moz.build

以下格式文件编译

# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-

# vim: set filetype=python:

#idl接口文件这里

XPIDL_SOURCES += [

    'nsISimplecpp.idl',

]

给你组件模块生成相应的.xpt,这里生成dom_simplecpp.xpt

#objdir-gecko/dist/bin/components/dom_simplecpp.xpt

XPIDL_MODULE = 'dom_simplecpp'

 

EXPORTS.mozilla.dom.simplecpp += [

    'Simplecpp.h',

]

 

UNIFIED_SOURCES += [

    'Simplecpp.cpp',

]

 

include('/ipc/chromium/chromium-config.mozbuild')

#哪个

FINAL_LIBRARY = 'xul'

 

if CONFIG['GNU_CXX']:

    CXXFLAGS += ['-Wshadow']

此,C++组件编写完成。

 

2.2.C++ 组件调用

C++组件注册完成之后同样前面的js组件调用

基于上个组件修改gecko/dom/simplejs/UseComponent.js 添加C++组件测试部分

"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);//创建@mozilla.org/simplejs组件实例之后通过Components.interfaces.nsISimpleComponent找到定义的接口然后用你定义接口接口函数

var result = usecompo.yourName;//the interface name in .idl

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 ");

 

 

 

//test of c++ component

////////////////////////////////////////////////////////////////

dump("yahahacpp,==========>start,test of cpp component==================>");

var Simplecpp =Cc["@mozilla.org/simplecpp;1"].createInstance(Components.interfaces.nsISimplecpp);

 

dump("yahahacpp,before change()");

var result_simplecpp = Simplecpp.change("daye");

dump("yahahacpp,============>end of cpp component test====================>\n ");

 

var atest = Simplecpp.usecomponent("Atest");

dump("yahahacpp,after Simplecpp.usecomponent() result of usecomponent:"+atest);

///////////////////////////////////////////////////////////////////

//以下代码有疑问参看js 组件实现部分

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]);

编译刷机测试相应组件正常调用最后log如下

357:I/Gecko   (  180): yahaha,========>start: javascript component==================>

358:I/Gecko   (  180): yahaha,...result: yourName = Anonymous!

359:I/Gecko   (  180): Hello yahaha,change after yourName

360:I/Gecko   (  180): yahaha,========>end: javascript component====================>

362:I/Gecko   (  180): yahaha,==========>start test1....instance of other cpp component in usecomponent.js

363:I/Gecko   (  180): yahaha,nfc,,,,,,[xpconnect wrapped nsINfcService]

364:I/Gecko   (  180): yahaha,=========>end test1 ===================================>

366:I/Gecko   (  180): yahahacpp,==========>start,test of cpp component==================>

367:I/        (  180): yohoho,yahahacpp,log from gecko dom simplecpp.cpp component,nsSimplecpp()

368:I/Gecko   (  180): yahahacpp,before change()

369:I/        (  180): yohoho,yahahacpp,log from gecko dom simplecpp.cpp,Change()

371:I/        (  180): yahaha,log from simplecpp.cpp after Changechange()

372:I/Gecko   (  180): yahahacpp,============>end of cpp component test====================>

374:I/        (  180): yohoho,yahahacpp,log from simplecpp.cpp component,Usecomponent()

376:I/        (  180): yahaha,log from simplecpp.cpp Usecomponent()

377:I/Gecko   (  180): yahahacpp,after Simplecpp.usecomponent() result of usecomponent:undefined

378:I/Gecko   (  180): yahaha,this is a null component in useComponentImpl

猜你喜欢

转载自blog.csdn.net/hunter___/article/details/80947113