thanks to the author
http://blog.csdn.net/tifa_ai/article/details/77184015
webidl是gecko层写的接口,供gaia调用。
写一个这样的接口,需要写接口文件,实现类,控制调用方式
1.写接口文件,接口文件以webidl为后缀,必须放到dom/webidl目录下面,而且需要在dom/webidl/moz.build中加入文件名,以使编译器能够看见它的存在。
注意,接口名字需要与实现类的头文件名字、cpp文件名字一致。
Gecko/dom/webidl/MozAaaTest.webidl
interface MozAaaTest { void setTestData();
}; |
在dom/webidl/moz.build中添加文件名时,需要注意,该文件中WEBIDL_FILES下的文件名是按字母顺序排序的,如果不按字母顺序添加文件名,会报错。
编写moz.build的例子如下
WEBIDL_FILES =[ ... 'MozAaaTest.webidl', ... ] |
2写实现类,
在gecko/dom下新建文件夹aaatest,接着把所有需要的模块文件都放到这个文件夹里面,最简单的框架就是
l MozAaaTest.h
l MozAaaTest.cpp
l moz.build
下面分别看看这三个文件的写法
2.1头文件MozAaaTest.h
#ifndef mozilla_dom_aaatest_MozAaaTest_h #define mozilla_dom_aaatest_MozAaaTest_h
#include "nsWrapperCache.h" #include "nsPIDOMWindow.h"
namespace mozilla{ namespace dom{ namespace aaatest{
class MozAaaTest final :public nsISupports ,public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MozAaaTest)
MozAaaTest(nsPIDOMWindow* aWindow); //构造函数 virtual~MozAaaTest();//析构函数
nsPIDOMWindow* GetParentObject()const{return mWindow;}
virtual JSObject* WrapObject(JSContext* aCx) override;
/* Impliment the WebIDL interface begin*/ NS_IMETHODIMP SetTestData();
/* Imppliment the WebIDL interface end*/
private:
protected: nsCOMPtr<nsPIDOMWindow> mWindow;
};
}// namespace aaatest }// namespace dom }// namespace mozilla
#endif
|
解析:
(1)预编译防止重复引用
#ifndef mozilla_dom_aaatest_MozAaaTest_h #define mozilla_dom_aaatest_MozAaaTest_h ... #endif |
(2)命名空间必须在mozilla ::dom下面
namespace mozilla{ namespace dom{ namespace aaatest{ ... }// namespace aaatest }// namespace dom }// namespace mozilla |
(3)继承关系
函数继承nsISupports和nsWrapperCache。注意,如果要继承这两个接口,就需要把nsISupports放到nsWrapperCache前面
nsISupports
nsISupports是所有的XPCOM都需要继承的接口,nsISupports提供三个方法。第一个方法QueryInterface可以实时的根据接口uuid获得接口指针,从而利用指针调用接口方法;而AddRef与Release增加了实例的计数功能
nsWrapperCache
如果你的接口不继承别的接口,就需要继承nsWrapperCache,nsWrapperCache把你的类挂载到cycle collector,这样cycle collector就会对你的wrapper cache进行跟踪处理。
(4)GetParentObject
如果你的接口不继承其他类,就需要执行GetParentObject,这样每一个webidl object就会关联到返回的特定窗口。
nsPIDOMWindow* GetParentObject()const{return mWindow;} |
(5)WrapObject。头文件这里只是定义了一下,具体实现在cpp文件
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; |
(6)接口函数
这里的函数名是从webidl文件里面得来的,需要注意的是函数名首字母变为大写
NS_IMETHODIMP SetTestData(); |
2.2 CPP文件的写法
cpp文件的编写参照webidl接口文件和H文件,实现其中申明的函数。需要注意的是 MozAaaTestBinding.h是生成的文件,必须要包含,不然报错。
#include "MozAaaTest.h" #include "mozilla/dom/MozAaaTestBinding.h"
using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::aaatest;
// cycle collector与isupports的宏定义 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozAaaTest) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(MozAaaTest) NS_IMPL_CYCLE_COLLECTING_RELEASE(MozAaaTest)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MozAaaTest, mWindow)
// 构造函数与析构函数的实现
MozAaaTest::MozAaaTest(nsPIDOMWindow* aWindow) : mWindow(aWindow) { printf("aiyan enter MozAaaTest\n"); }
MozAaaTest::~MozAaaTest() { printf("aiyan enter ~MozAaaTest\n"); }
// WrapObject的实现 JSObject* MozAaaTest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return MozAaaTestBinding::Wrap(aCx,this, JS::Handle<JSObject*> aGivenProto); }
// webidl中定义的接口的实现
NS_IMETHODIMP MozAaaTest::SetTestData(){ printf("aiyan enter SetTestData:isSuccessed\n");
return NS_OK; } |
2.3 moz.build的编写
同样的,每个中括号中的文件名都必须按字母顺序排列,另外,FINAL_LIBRARY ='xul'这个库文件必须加上,不然会报错。
EXPORTS.mozilla.dom.aaatest+=[ 'MozAaaTest.h', ]
SOURCES +=[ 'MozAaaTest.cpp', ]
LOCAL_INCLUDES +=[ '/dom/aaatest', ] // # FINAL_LIBRARY ='xul' |
补充说明
(1)文件夹aaatest的添加需要在dom/moz.build中添加路径
DIRS +=['aaatest',] |
(2)配置文件dom/bindings/Bindings.conf,为接口的执行添加入口
'MozAaaTest':{ 'nativeType':'mozilla::dom::aaatest::MozAaaTest', }, |
括号中不添加信息,表示是默认值;
如果你的C++不是mozilla::dom::MyInterface的格式存在,那么需要在nativeType中添加正确的路径,如mozilla::dom::aaatest::MozAaaTest;
如果你的头文件路径不与nativeType中信息一一对应,即如不是mozilla/dom/aaatest/MozAaaTest.h,那么你需要在headerFile中添加正确的头文件路径。
3 模块添加完了,要怎么调用了,最简单的方式就是通过navigator来调用。因为navigator在gaia层的调用关系架构已经搭好。
同样,修改navigator需要修改的文件包括:
l gecko/dom/webidl/Navigator.webidl
l gecko/dom/base/Navigator.h
l gecko/dom/base/Navigator.cpp
修改的原理是在Navigator.webidl中添加一个属性,然后在cpp中去实现这个属性,给我们的模块实例化。
3.1Navigator.webidl
给Navigator添加了一个只读的属性。这里有个权限的检查,后面会介绍我们需要加权限,才能在gaia去用添加的接口。
partial interface Navigator{ [Throws,CheckAnyPermissions="aaatest"] readonly attribute MozAaaTest mozAaaTest; }; |
3.2头文件Navigator.h
在头文件中申明了属性的实现函数GetMozAaaTest,另外申明了一个成员变量mAaaTest用来保存MozAaaTest的实例
// 需要使用到MozAaaTest类 namespace aaatest{ class MozAaaTest; } class Navigator MOZ_FINAL:public nsIDOMNavigator ,public nsIMozNavigatorNetwork ,public nsWrapperCache { public: ... // 属性的实现 aaatest::MozAaaTest* GetMozAaaTest(ErrorResult& aRv); private: ... // 存储MozAaaTest的实例 nsRefPtr<aaatest::MozAaaTest> mAaaTest; } |
3.2CPP文件的添加
从属性的实现函数可以看出来,gaia初始化Navigator.mozAaaTest,就会调用GetMozAaaTest函数,返回MozAaaTest的实例mAaaTest,如果实例没有被初始化,就调用MozAaaTest的构造函数进行初始化。
#include "mozilla/dom/aaatest/MozAaaTest.h"
using namespace aaatest;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAaaTest)
// 属性的实现函数 aaatest::MozAaaTest* Navigator::GetMozAaaTest(ErrorResult& aRv) { LOG("aiyan GetMozAaaTest"); if(!CheckPermission("aaatest")){ LOG("aiyan GetMozAaaTest CheckPermission return false"); aRv.Throw(NS_ERROR_UNEXPECTED); returnnullptr; }
if(!mAaaTest){ mAaaTest =new aaatest::MozAaaTest(mWindow); } else{ LOG("mAaaTest exist just return"); } return mAaaTest; }
// 资源释放 void Navigator::Invalidate() { ... if(mAaaTest){ mAaaTest =nullptr; } } |
4gaia的调用,桥搭好了,现在看看怎么掉
要调用webidl首先需要有一个权限,这个就是我们在前面用到的“aaatest”权限,接着需要在app的manifest.webapp中加入权限,最后才能使用webidl接口。
注意,想要gaia能调用新加入的webidl,需要删除out目录,整编全部代码,不然gaia会找不到接口。
定义权限,在gecko/dom/apps/PermissionsTable.jsm中加入代码
this.PermissionsTable= { "aaatest":{ app: DENY_ACTION, privileged: DENY_ACTION, certified: ALLOW_ACTION }, } |
给app加入权限
在gaia/apps/system/manifest.webapp中加入代码
"permissions":{ ... "aaatest":{}, ... }, |
使用例子
HardwareButtonsBaseState.prototype.process=function(type){
switch(type){ case'enter-button-press': dump("aiyan "+type);
var _aaaTest=navigator.mozAaaTest; _aaaTest.setTestData();
... } } |
注意这里必须先调用mozAaaTest的构造函数,再利用mozAaaTest的实例_aaaTest去调用webidl中定义的函数,这里的函数名必须与webidl中的保持一致,而不是在cpp中的函数名。
1.1
添加webidl 的过程
一添加webidl 文件
Gecko/dom/webidl/MozAaaTest.webidl
Gecko/dom/webidl/moz.build
二添加实现模块
gecko/dom/aaatest/
l MozAaaTest.h
l MozAaaTest.cpp
l moz.build
配置文件gecko/dom/bindings/Bindings.conf,为接口的执行添加入口
dom/bindings/Bindings.conf
三添加调通路
l gecko/dom/webidl/Navigator.webidl
l gecko/dom/base/Navigator.h
l gecko/dom/base/Navigator.cpp
四gaia 调用
gecko/dom/apps/PermissionsTable.jsm
gaia/apps/system/manifest.webapp
如果要从gaia调用已经有的webidl需要满足以下
(1)需要对应APP的在manifest.webapp里面添加权限
如:
"permissions":{
"voicemail":{}
}
改完manifest.webapp最重要的是要全编整个gaia层,单编模块不会起作用:make reset-gaia
(2)如果这样还不能起作用,检查一下调用的app是个什么样的app
在对应的manifest.webapp下,可以看到关键字
“type”:"ceitified"
在gecko/dom/apps/PermissionsTable.jsm里面
可以搜“voicemail”
“voicemail”:{
app:DENY_ACTION
trusted:DENY_ACTION
privileged:DENY_ACTION
certified:ALLOW_ACTION
}
可以看看你的app是否有voicemail这个权限
(3)最后如果还不行,需要看看你调用的方式是否正确,或者接口是否存在。
https://blog.csdn.net/zyt2138/article/details/44955897
向FFOS添加webidl
webidl简介
Web IDL(Interface Definition Language,接口定义语言)该规范定义了一个OMG IDL 3.0的语法子集,用来规范定义的接口。Web IDL 是一个具有多种功能的IDL 变量,便于规范Web平台中的常用脚本对象的操作。
webidl xpidl ipdl 区别
webidl:接口定义文件后缀为.webidl,用于定义webapi,比如gecko/dom/webidl/FMRadio.webidl
xpidl:接口定义文件后缀为.idl,用于定义xpcom组件接口,比如gecko/dom/wifi/nsIWifi.idl
ipdl:接口定义文件后缀为.ipdl,用于定义进程间通信接口,帮助gecko中webidl接口的实现,比如gecko/dom/fmradio/ipc/PFMRadio.ipdl
Gecko内部使用最多的还是基于XPConnect上的DOM Bindings,使用ScriptableHelper来帮助把XPCOM组件暴露在JavaScript上,但这种方式有一些内存管理和速度上的缺点,并且XPIDL(XPCOM界面定义语言)与WebIDL(Web界面定义语言)在语义上有一定的不同,会使各种加速方法和处理语义问题的 Wrapper需要手工地针对不同API进行修改。 因为XPIDL的一些问题,Firefox OS里还提供一种DOM bindings的方法。由于这个问题是在法国巴黎首次讨论的,所以最早被称为“Paris Bindings”。因为这些DOM API实际上不使用XPCOM的许多功能,所以它的速度比原有的XPConnect会快许多。通过WebIDL DOM bindings可以省略掉一些虚函数的开销,还可以节省掉XPCOM处理线程安全的花费,透过新的JIT技术,从JavaScript可以调用DOM API,甚至直接调用C++的实现。未来描述DOM API的语言可能统一为WebIDL。 |
如何向ffos 添加JS 实现的webidl
1. 编写webidl文件
在gecko/dom/webidl 目录下面编写webidl文件
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 http://mozilla.org/MPL/2.0/. */ [JSImplementation="@mozilla.org/mytest;1", NavigatorProperty="mytest" ]
interface MyTest { DOMString sayHello(); }; |
‘@mozilla.org/mytest;1 ‘ contractname,之后和js实现绑定。
NavigatorProperty 设置为navigator的属性
2. 编写manifest文件
在gecko/dom/mytest/ 中创建 MyTest.manifest 文件。
在MyTest.manifest文件中,将webidl接口与javascript实现绑定。
MyTest.manifest 文件如下:
component {50CD146F-75EE-4C5E-88FA-FB3871362156} MyTest.js contract @mozilla.org/mytest;1 {50CD146F-75EE-4C5E-88FA-FB3871362156} |
定义 一个component,然后将其与 @mozilla.org/mytest;1绑定
3. 编写js 文件,MyTest.js
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); function MyTest(){ dump("zyt mytest constractor"); }
MyTest.prototype = { classDescription: "zyt test xpcom", classID: Components.ID("{50CD146F-75EE-4C5E-88FA-FB3871362156}"), contractID: "@mozilla.org/mytest;1", QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]), sayHello : function(){ dump("this is zyt test to say hello"); return"this is my first webidl test"; }, };
this.NSGetFactory= XPCOMUtils.generateNSGetFactory([MyTest]); |
4. 创建dom/mytest/moz.build 文件
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # 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 http://mozilla.org/MPL/2.0/.
EXTRA_COMPONENTS += [ 'MyTest.js', 'MyTest.manifest', ] |
注:该文件必须按字母序排列。否则编译出错。
5. 修改dom/moz.build文件
diff --git a/dom/moz.build b/dom/moz.build --- a/dom/moz.build +++ b/dom/moz.build @@ -81,6 +81,7 @@ PARALLEL_DIRS += [ 'webidl', 'xbl', 'xslt', + 'mytest', ]
if CONFIG['OS_ARCH'] == 'WINNT': |
6. 添加到Firefox OS
修改 gecko/b2g/installer/package-manifest.in
:
;my test @BINPATH@/components/MyTest.js @BINPATH@/components/MyTest.manifest |