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 MOZ_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) MOZ_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 |
namespace mozilla { namespace dom { namespace aaatest { ... }// namespace aaatest }// namespace dom }// namespace mozilla |
函数继承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;} |
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; |
这里的函数名是从webidl文件里面得来的,需要注意的是函数名首字母变为大写
NS_IMETHODIMP SetTestData(); |
2.2 CPP文件的写法
cpp文件的编写参照webidl接口文件和H文件,实现其中申明的函数。需要注意的是 MozAaaTestBinding.h是生成的文件,必须要包含,不然报错。
#include "MozAaaTest.h" #include "mozilla/dom/MozAaaTestBinding.h"
usingnamespace mozilla; usingnamespace mozilla::dom; usingnamespace 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) { return MozAaaTestBinding::Wrap(aCx,this); }
// 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',] |
'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,CheckPermissions="aaatest"] readonly attribute MozAaaTest mozAaaTest; }; |
在头文件中申明了属性的实现函数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; } |
从属性的实现函数可以看出来,gaia初始化Navigator.mozAaaTest,就会调用GetMozAaaTest函数,返回MozAaaTest的实例mAaaTest,如果实例没有被初始化,就调用MozAaaTest的构造函数进行初始化。
#include "mozilla/dom/aaatest/MozAaaTest.h"
usingnamespace 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; } } |
要调用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 }, } |
在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();
... } } |
1.1