开发BREW扩展类

看到一篇文章,觉得比较有指导意义,译过来,希望给大家有些帮助,能力有限,有错误的地方还望大家指出来。共同学习,共同进步。

原文地址:
https://brewx.qualcomm.com/bws/content/gi/common/appseng/en/knowledgebase/docs/extensions.htm

1 简介:
扩展类可以扩充BREW的功能,通常来说,扩展类都是以动态的形式存在并且以OTA方式提供下载,然而在某些情况下,OEM制造商会在他们的设备中添加了一些静态的扩展类,例如:OEM制造商经常会给BREW标准接口类IAddrBook添加许多额外的功能,他们通常会创建自己的IAddrBook接口,并且把新增的额外功能提供给开发者。

2 静态 VS 动态
静态扩展类通常是被包含在OEM制造商的SW版本中,不由第三方开发者提供。从另外一个角度看来,动态扩展则是由OTA方式下载。移动应用和它所需要的扩展类是同时被下载到手机上的(除非手机上已经存在了所需的扩展类),通过MIF文件提供的依存列表信息把所需要的扩展类下载到手机当中。每一个动态扩展都会有一个相关联的引用计数,该引用计数负责监视手机上所有应用对于该扩展类的依赖关系,如果引用计数减少到0,则该扩展类将被从手机内存中移除。静态扩展则不是,它没有引用计数,也永远不会被从手机上删除。

3 特性
扩展类不包含权限设置,它的权限级别继承于父应用,例如:如果某应用使用了一个具有文件操作功能的扩展类,那么该应用就是扩展类的父应用,除非父应用的MIF文件中设置了允许文件操作的权限,否则该扩展类的所有文件操作都会失败,这一点对于扩展来开发人员来说十分重要。
与权限级别相似的是,扩展类中所有对于文件的操作都是通过父应用的上下文来执行的,如此来看,对于父应用不可见的文件,扩展类也是无法操作的。
扩展类即可以是保护类型也可以是未保护类型。对于保护类型来说,如果父应用的MIF文件中的依存关系列表中有显示罗列出该扩展类,那么父应用就可以创建并使用它,反之,则不行;对于非保护类型则可以被所有应用使用,不用考虑该应用是否明确声明了依存关系,这样的扩展类通常被加上一个MIME类型的标记,应用只需要通过外壳查找目标MIME类型的句柄,就可以使用它的功能了。

4 MIF文件
扩展类和应用一样需要MIF文件,然而,他们却在根本上有所不同。首先,一个扩展类的MIF文件不需要定义一个applet,只需要在MIF编辑器的"Externsions"标签栏中的"Exported Classes"中设置其class ID即可。保护类型的属性也在该标签栏中设置。
如果一个应用的运行以来与一个扩展类,那么在该应用的MIF文件中必须把扩展类的class ID设置为依赖,如果没有此类依赖关系,该扩展类将不会在下载应用的时候被一同下载,当该应用运行的时候就会失败。如果扩展类是可选的,就可以不用添加依存关系,然而应用必须能够处理扩展类不存在的情况。

5 声明扩展类的结构体
第一步,开发扩展类首先需要声明虚函数表。
typedef struct IDemoExtension IDemoExtension;
AEEINTERFACE(IDemoExtension)
{
        INHERIT_IQueryInterface(IDemoExtension);
        int (*DisplayTime)(IDemoExtension *po);
        int (*DisplayDate)(IDemoExtension *po);
};

第一行声明了一个IDemoExtension的结构体,该结构体是一个apple结构体,将会返回给正在初始化的应用,其中的宏AEEINTERFACE声明了一个扩展类的虚函数表,从上面的声明看出,虚函数表中有5个函数。BREW的每一个接口类都定义了一个类似于上面定义中的宏INHERIT_XXX,用它来把已继承的函数添加到已存在的函数表中,至少,BREW强烈推荐如上例所示,从IQueryInterface派生而来。宏INHERIT_IQueryInterface添加三个函数到函数表中:AddRef, Release, QueryInterface。我们的例子中添加了DisplayTime和DisplayData两个函数。
下一步我们定义宏来索引我们函数表中的函数
#define IDEMOEXTENSION_AddRef(p)
 AEEGETPVTBL((p),IExtensionCls)->AddRef((p))
#define IDEMOEXTENSION_Release(p)
    AEEGETPVTBL((p),IExtensionCls)->Release((p))
#define IDEMOEXTENSION_QueryInterface(p)
    AEEGETPVTBL((p),IExtensionCls)-> QueryInterface((p),(clsid),(pp))
#define IDEMOEXTENSION_DisplayTime(p)
 AEEGETPVTBL((p),IDemoExtension)->DisplayTime((p))
#define IDEMOEXTENSION_DisplayDate(p)
 AEEGETPVTBL((p),IDemoExtension)->DisplayDate((p))
上面的宏可以供父应用来调用扩展类的函数,宏AEEGETPVTBL能准确地指向函数表,并能方便的调用到函数表中的函数,需要注意的是AEEGETPVTBL是同AEEINTERFACE配合起来使用的,我们一旦声明好虚函数表,那么就应该定义扩展类结构体了。

以上代码的第一行把虚函数表插入了扩展类的结构体定义之中,虚函数表必须总是被定义成为结构体的第一个成员,m_nRefs变量也必须在结构体定义中声明,一个扩展类在应用中将会数次被引用,这个变量用来保存在应用中被引用的总次数,AddRef和Release函数是用来对该变量进行增减操作的,一旦m_nRefs变为0,该扩展类就会释放所有占用的资源。结构体中接下来的三个成员是扩展类的可选成员,可以在扩展类中添加任何所需要的成员变量。
6 定义函数
定义的第一个函数必须是AEEClsCreateInstance,REW总是调用该函数来创建该class的接口,下面的代码表明了普遍实现的方法。
int AEEClsCreateInstance(AEECLSID ClsId, IShell *pIShell,
       IModule *po, void **ppObj)
{
   *ppObj = NULL;
   if( ClsId == AEECLSID_MYEXTENSION) {
  return MyExtension_New(sizeof(IDemoExtension), pIShell, po,
           (IModule **)ppObj);
   }
   return EFAILED;
}
我们的函数首先会检查由BREW传入的参数class ID,如果检查通过了,函数就尝试创建和初始化需要的资源。

int MyExtension_New(int16 nSize, IShell *pIShell, IModule* pIModule,
                                                   IModule ** ppMod) {
   IDemoExtension*            pMe = NULL;
   VTBL(IDemoExtension) *     modFuncs;
   if( !ppMod || !pIShell || !pIModule )
      return EFAILED;
   *ppMod = NULL;
   // Allocate memory for the ExtensionCls object
   if( nSize < sizeof(IDemoExtension) )
      nSize += sizeof(IDemoExtension);
   // Allocate the module's struct and initialize it. Note that the
   // modules and apps must not have any static data.
   // Hence, we need to allocate the vtbl as well.
   if( (pMe = (IDemoExtension*)MALLOC(nSize +                                      
                              sizeof(VTBL(IDemoExtension)))) == NULL )
      return ENOMEMORY;
   modFuncs = (VTBL(IDemoExtension)*)((byte *)pMe + nSize);
   //Initialize individual entries in the VTBL
   modFuncs->AddRef              = MyExtension_AddRef;
   modFuncs->Release             = MyExtension_Release;
   modFuncs->QueryInterface      = MyExtension_QueryInterace;
   modFuncs->DisplayTime         = MyExtension_DisplayTime;
   modFuncs->DisplayDate         = MyExtension_DisplayDate;
   // initialize the vtable
   INIT_VTBL(pMe, IModule, *modFuncs);
   // initialize the data members
   pMe->m_nRefs      = 1;
   pMe->m_pIShell    = pIShell;
   pMe->m_pIModule   = pIModule;
   // Add References and get IDisplay
   ISHELL_AddRef(pIShell);
   IMODULE_AddRef(pIModule);
   // Create an instance of the IDisplay
   if( ISHELL_CreateInstance(pIShell, AEECLSID_DISPLAY,
                         (void **)&pMe->m_pIDisplay) != SUCCESS )
      return EFAILED;
   // Set the pointer in the parameter
   *ppMod = (IModule*)pMe;
   return AEE_SUCCESS;
}

AddRef, Release和QueryInterface是从IQI接口继承过来的,AddRef负责增加引用计数的数值。

static uint32 MyExtension_AddRef(IDemoExtension* pMe) {
   // Increment reference count
   return ++(pMe->m_nRefs);
}

Release函数负责减少引用计数的数值,当引用计数的值变为0的时候,该实例就会从内存中被释放掉。

static uint32 MyExtension_Release(IDemoExtension* pMe) {
   // Decrement reference count
   if( --pMe->m_nRefs != 0 )
      return pMe->m_nRefs;

   // Ref count is zero.  Release memory associated with this object.
   if( pMe->m_pIDisplay )
      IDISPLAY_Release(pMe->m_pIDisplay);

   // Release interfaces
   ISHELL_Release(pMe->m_pIShell);
   IMODULE_Release(pMe->m_pIModule);
   //Free the object itself
   FREE_VTBL(pMe, IModule);
   FREE( pMe );
   return 0;
}

我们最后一个需要定义的函数就是QueryInterface,这个函数返回一个与扩展类相关联的接口,IWeb接口就是一个例子,当一个应用使用该接口完成一个网页请求的时候,底层的一个TCP套接字被创建,为了能够直接控制这个套接字,应用可以通过调用IWeb_QueryInterface函数,传递参数AEECLSID_SOCKET(AEECLSID_SOCKPORT在BREW3.x中),来获得这个接口,该函数将返回一个指针,下面是QueryInterface的一个具体实现。

static int MyExtension_QueryInterface(IDemoExtension* me,
                               AEECLSID class, void** ppo) {
   switch (class) {
      case AEECLSID_QUERYINTERFACE:
      case AEECLSID_MYEXTENSION:
      case AEECLSID_BASE:
         *ppo = me;
         MyExtension_AddRef(me);
         return SUCCESS;
      case AEECLSID_DISPLAY:
         *ppo = me->m_pIDisplay;
          return SUCCESS;
      default:
         *ppo = NULL;
         return ECLASSNOTSUPPORT;
   }
}

7 静态扩展类

上面介绍的这个例子也可以用来创建静态扩展类,然而静态扩展类可以作为全局变量,有了这个特性,下面的代码可以为静态扩展类构造虚函数表。

static const AEEVTBL(IDemoExtension) gvtIDemoExtension = {
   MyExtension_AddRef,
   MyExtension_Release,
   MyExtension_QueryInterface,
   MyExtension_DisplayTime,
   MyExtension_DisplayDate,
};

以上的代码被放置在函数之外,通常是在一个头文件中,初始化扩展类可以简单的用一行代码搞定。

pMe->pvt = &gvtIDemoExtension;

上面的代码初始化了整个虚函数表,不必对于虚函数表中每个函数都初始化一次,然而上面的代码仅对静态扩展类是有效的,一个动态扩展类的地址是在运行时确定的(于之不同的是,静态扩展类的地址是在编译时确定的),因此,虚函数表必须在运行时声明。

8 关于宏
强烈推荐在以上例子中所使用到的宏,然而在BREW中还有许多其他的可以用来创建扩展类的宏。其中很多宏被包含近来是为了向后的兼容性,一些宏例如:QINTERFACE, GET_PVTBL和DECLARE_IBASE都是十分令人气馁的,他们应该分别被AEEINTERFACE, AEEGETPVTBL和INHERIT_IQueryInterface替代。

9 使用扩展类
扩展类可以像标准的BREW APIs一样被创建和释放,每个函数都可以通过头文件的宏定义来调用,同BREW APIs一样,在编译调用扩展类函数的应用的时候需要包含其头文件,下面的例子叙述了如何在应用中调用扩展类的函数。

if(ISHELL_CreateInstance(pMe->a.m_pIShell, AEECLSID_MYEXTENSION,
              (void **) (&(pMe->pIDemoExtension))) != SUCCESS ) {  
   return FALSE;
}

IDEMOEXTENSION_DisplayTime(pMe->pIDemoExtension);
if(pMe->pIDemoExtension) {
   IDEMOEXTENSION_Release(pMe->pIDemoExtension);
   pMe->pIDemoExtension = NULL;
}

10 通过MIME类型使用扩展类
扩展类可以把其自身注册为一个MIME类型的句柄,它的注册最好通过MIF编辑器来完成。

上面提及的例子展示了一个扩展类注册为MYTIME句柄,MIME类型的注册允许在运行时解决class ID的问题,应用可以通过ISHELL_GetHandler函数找到一个MIME类型的class ID,整个函数会遍历所有的MIF文件,寻找以MIME类型方式注册的class ID。
下面这个例子阐述了一段能创建和显示多种不同格式文件的代码,在此例中,有一个抽象类IReader,一个扩展类可以扩充它的接口来显示多种格式的文件。

// An Application will call this function when it intends to
// open a file
void DisplayFile(MyApp* pMe, char* mime, char* file) {
   AEECLSID myClass;
   // This call will create a handler for MYPDF, MYDOC, or
   // MYXML depending on mime
   myClass = ISHELL_GetHandler(pMe->pIShell, AEECLSID_APP, mime);
   // Create necessary Interface
   ISHELL_CreateInstance(pMe->pIShell, myClass, &pMe->pIReader);

   // Ishell Createinstance
   // Each extension implements DisplayFile, The virtual
   // table will point to the correct corresponding function
   // call.  We are ignoring error checking
   IREADER_DisplayFile(pMe->pIReader, file);
}

DisplayFile是一个被所有扩展类实现的扩充IReader的接口,虚函数表在创建扩展类的时候被初始化,这样就使IREADER_DisplayFile可以索引正确的函数来显示文件。

11 更多信息
BREW 2.x 察看AEE.h
BREW 3.x 察看AEEInterface.h

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiyucn/archive/2006/01/14/579565.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值