技术开发 频道

Symbian 平台技术开发技巧汇总

  【IT168 技术】从事Symbian开发工作也有几个年头了,一直想总结一下开发过程中遇到的问题以及解决技巧,但是总是有这样那样的理由不愿花时间去总结,今天天气不错,心情也挺好,摆出一副专家的气势伏案工作,翻出这几年的工作笔记,打开除了上班时间懒得去碰的电脑,开始了自己的总结大会。

  问题一、如何枚举出正在运行的App

  结合RApaLsSession和TApaTaskList应该可以做到.

  RApaLsSession:

  GetAppIcon()

  GetAppInfo()

  TApaTaskList:

  FindApp()

  问题二、从收件箱读取彩信图片

  mmslist实现了首先以listbox列表的形式列出了收件箱中的所有彩信,选择某一条彩信后可以显示出它的发送端号码和彩信的文本信息;现在我想让它显示发送端号码和彩信图片(假设我的彩信都是图片格式);请教两位应该怎么才能实现读彩信图片并显示的功能。

  下面是读彩信文本信息的代码,你们参考一下:

  void CMmslController::GetMessageL( const TDesC& aItem,

  TDes& aMessageText ) const

  {

  //Read the message Uid from aItem

  TUint32 id = 0;

  TLex lexer( aItem );

  lexer.SkipSpace();

  TChar ch( lexer.Get() );

  while ( ( ch != ‘\t’ ) && ( ch != 0 ) ) // Finding end of 1.st line

  {

  ch = lexer.Get();

  }

  lexer.SkipSpace();

  lexer.Val( id, EHex );

  if( iCurEntries->Find( id ) == KErrNotFound )

  {

  return;

  }

  CMsvEntry* msvEntry = iSession->GetEntryL( id );

  CleanupStack::PushL( msvEntry );

  const TMsvEntry& msgEntry = msvEntry->Entry();

  CBaseMtm* clientMtm = iMtmReg->NewMtmL( msgEntry.iMtm );

  CleanupStack::PushL( clientMtm );

  clientMtm->SwitchCurrentEntryL( msvEntry->EntryId() );

  // An instance of the TDesOverflow derived class used to suppress

  // the panic that would be generated if buffer length was exceeded

  // in calls to AppendFormat

  TOverrideOverFlow noOflo;

  // Text is located in iDescription field.

  aMessageText.AppendFormat( msgEntry.iDescription, &noOflo );

  //aMessageText.AppendFormat( msgEntry.iDetails );

  CleanupStack::PopAndDestroy( 2 ); // clientMtm, msvEntry

  }

  问题三、如何让程序在安装后自动运行

  如何让一个程序(或是一个server)在安装后自动运行于手机中,这是非常容易的,只需在你的PKG文件中,在包含你的app或exe文件的那行末尾加上“FR,RI”。

  “FR”表示“File Run”,而“RI”则表示“Run during Installation”。请注意,务必要先开始rsc,aif,mbm文件的安装,然后才能是APP等(也就是在pkg文件的末尾进行app的安装)

  举例:

  “\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp.rsc” -

  “!:\system\apps\MyApp\MyApp.rsc”

  “\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp_caption.rsc” -

  “!:\system\apps\MyApp\MyApp_caption.rsc”

  “\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp.aif” -

  “!:\system\apps\MyApp\MyApp.aif”

  “\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp.app” -

  “!:\system\apps\MyApp\MyApp.app”,FR,RI

  问题四、全面了解文件类型和从属关系

  下图显示了在一个典型的Symbian程序中各文件的从属关系。

  [attach]457[/attach]

  .hrh文件中包含所有要在.rss、.h和.cpp中使用的枚举类型。它们主要使用在应用程序的菜单、工具栏等地方,下面展示了一个典型的例子:

  //MyApp.hrh

  //

  enum{

  EMyAppCmdOpenFile = 0×6000,

  EMyAppCmdEdit,

  };

  按照惯例这些命令ID值的范围应该从0×6000开始向上。

  .rss文件中是资源文件,这些文件包括所有静态字符串、按钮、菜单和列表等的定义,都使用在应用程序UI中。此外,Nokia Series 60向导还可能生成一个.loc文件,这个文件同.rss文件很相似但只用于描述你程序中的静态字符串,利用它你可以很容易的将程序变成多语言版本。

  .rsg是生成的资源文件。它们是在编译时刻由资源编译器产生的,.cpp文件将包含它们以便处理资源。

  .mbm是symbian位图文件,它里面可以存储几个位图。

  .mbg是在创建.mbm时生成的。这些文件一般包含在那些使用位图的RSS文件中,一个mbg文件包括在.mbm中各位图的ID。

  问题五、如何在网络通讯中正确显示中文

  1。经过对照GB2312/GBK编码表,在程序中定义_LIT8(KTest, “中文测试”);是GB2312/GBK编码

  2。直接从输入框取出的字符串,经过按照byte分析并比较中文和unicode对照表,发现是UTF-16LE(Sixteen-bit UCS Transformation Format, little-endian byte order)编码

  3,中文对服务器的传输建议统一处理成UTF8编码进行,从对话框获得的也一样处理,服务器需要对应识别过来的字符串并做处理。

  问题六、如何动态更改CEikLabel 的text

  CEikLabel* iLabelStatus;

  …..

  iLabelStatus = new (ELeave) CEikLabel;

  iLabelStatus->SetContainerWindowL( *this );

  iLabelStatus->SetTextL( this->iStatusStr );

  ….

  //动态在这里更改

  iLabelStatus->SetTextL(iStatusStr);

  iLabelStatus->DrawNow();

  如果初始化时就无法显示,请对照helloworld代码检查自己label是否设置正确;如果是进度进行中无法显示,请检查CActive是否正确执行,单步DrawNow是否被正确调用。

  问题七、在listbox中怎么处理所选项的事件

  触发事件并不是很复杂的事情,

  TKeyResponse CXXContainer::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)

  {

  TInt code = aKeyEvent.iCode;

  switch(code)

  {

  // is navigator button pressed导航按钮被按下时

  case EKeyOK:

  {

  // pass the key press event to view,

  // then view will pass it to ui class’s handler

  iXXView->ProcessListEvent(iListBox->CurrentItemIndex()) ;

  }

  return (EKeyWasConsumed);

  case EKeyLeftArrow :

  case EKeyRightArrow :

  return (EKeyWasConsumed);

  default:

  // Let Listbox take care of its key handling

  return iListBox->OfferKeyEventL(aKeyEvent, aType) ;

  }

  }

  这个iXXView的ProcessListEvent()函数就是传入当前用户选择的那个list item的index。

  问题八、pkg文件中指定多个操作系统版本

  pkg file定义了安装文件(sis)的内容,它包括应用程序的UID,一个支持的语言列表,目标产品的UID和打包在sis的一组文件:

  ; MyGame.pkg

  ; Specifies an installation file for MyGame ///////为MyGame文件制定一个安装文件

  ;Languages

  &EN

  ;Header

  #,(0×1000ABCD),1,0,0

  ; Required line for Series 60 devices. Defines the target product

  ; UID.

  (0×101F6F88), 0, 0, 0,

  “\epoc32\release\thumb\urel\MyGame.app”-“!:\system\apps\MyGame\MyGame.app”

  “\epoc32\release\thumb\urel\MyGame.rsc”-“!:\system\apps\MyGame\MyGame.rsc”

  “\epoc32\release\thumb\urel\MyGame.mbm”-“!:\system\apps\MyGame\MyGame.mbm”

  “\epoc32\release\thumb\urel\MyGame.aif”-“!:\system\apps\MyGame\MyGame.aif”

  “..\MyGame\MyGameSample.wav”-“!:\system\apps\MyGame\MyGameSample.wav”

  Product UID定义了应用程序的目标环境,大部分的s60版本是向下兼容的。

  参见下表:

  Nokia 7650 0×101F6F87

  Nokia 3650 0×101F7962

  Nokia 9210/9290 0×10005E33

  Nokia N-gage 0×101F8A64

  Siemens SX1 0×101F9071

  Series 60 Platform v0.9 0×101F6F88

  Series 60 Platform v1.0 0×101F795F

  Series 60 Platform v1.1 0×101F8201

  Series 60 Platform v1.2 0×101F8202

  Series 60 Platform v2.0 0×101F7960

  如果程序需要依据各不同的平台来进行安装,那就可以使用条件语句块来处理,这时pkg里的语句如下:

  ;

  ; Files to install

  ;

  IF MachineUID=0×101fb3dd

  ; Nokia 6600 specific files

  “..\MyFiles\FileFor6600.dat”-“!:\system\apps\MyGame\MyData.dat”

  ELSEIF MachineUID=0×101f466a

  ; Nokia 3650 specific files

  “..\MyFiles\FileFor3650.dat”-“!:\system\apps\MyGame\MyData.dat”

  ELSE

  ; Files for other devices

  “..\MyFiles\FileForOthers.dat”-“!:\system\apps\MyGame\MyData.dat”

  ENDIF

  就可以生成一个支持多平台的安装文件,除了机器UID外,还有很多属性,如内存和CPU的标识:

  注意,机器UID和Product UID是不同的,见下:

  Nokia 7650 0×101F4FC3

  Nokia 3650 0×101F466A

  Nokia 6600 0×101FB3DD

  Nokia 9210/9290 0×10005E33

  Nokia N-Gage 0×101F8C19

  Win32 Emulator 0×10005F62

  可以使用如下的代码来找出该设备的机器UID:

  #include //and link with hal.lib

  TInt machineUid = 0;

  HAL::Get(HALData::EmachineUid, machineUid);

  问题九、如何按字节读取文件

  1.RFile::Read()

  TInt Read(TDes8& aDes,TInt aLength) const;

  Description

  Reads specified number of bytes of binary data from file — synchronous overload.

  2.Typedef TText8

  typedef unsigned char TText8;

  问题十、如何取出Symbian手机中的信息

  方法有两个:

  1 确定出他们的路径,用文件的方式读;

  2 用系统给这两个部分提供的API

  通讯录方面的(别人的代码网上找的):

  _LIT(KNameLabel,”Name”);

  _LIT(KMobileLabel,”Mobile”);

  _LIT(KName,”Steve”);

  _LIT(KMobile,”+8613900000000″);

  // Open the default contacts database:

  CContactDatabase* contactsDb = CContactDatabase::OpenL();

  CleanupStack::PushL(contactsDb);

  // Create a contact card and add some fields:

  CContactItem* contact = CContactCard::NewLC();

  CContactItemField* field = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldFamilyName);

  field->SetMapping(KUidContactFieldVCardMapUnusedN);

  field->SetLabelL(KNameLabel);

  field->TextStorage()->SetTextL(KName);

  contact->AddFieldL(*field);

  CleanupStack::Pop();

  field = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldPhoneNumber);

  field->SetMapping(KUidContactFieldVCardMapTEL);

  field->SetLabelL(KMobileLabel);

  field->TextStorage()->SetTextL(KMobile);

  contact->AddFieldL(*field);

  CleanupStack::Pop();

  // Add the new contact to the database and set it as the own card:

  contactsDb->AddNewContactL(*contact);

  contactsDb->SetOwnCardL(*contact);

  CleanupStack::PopAndDestroy(2); // contact contactsDb

  短信的:

  CMsvEntry或 CMsvServerEntry

  问题十一、怎么使用BUTTON 类创建一个 BUTTON

  S60里面好像没有BUTTON的类吧

  1.好像没有必要做BUTTON,触发事件使用MENU就可以了

  2.如果非要做的话,可以尝试的下面的简单方法

  2.1 使用一个LABEL(设置一下边框属性可以使这个LABEL像一个所谓的BUTTON)

  2.2 可以在该LABEL的所处CONTAINER的

  OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);

  处理KEY事件(判断该LABEL拥有FOCUS)

  问题十二、图标资源的读取与储存结构

  可以在AknView类中定义如下的图标数组进行储存图标数据结构,这种结构有图表位图和蒙板(mask)

  CArrayPtr* iIconArray;

  具体实现方法:

  iIconArray->AppendL(CEikonEnv::Static()->CreateIconL(iMbmFile, EMbmFile1, EMbmFile1_mask));

  在需要贴图标的地方用这个数组句柄引用即可

  问题十四、一段左软键菜单的控制代码

  要求:1点了左软键之后,就相当与点了ok键。

  2 :把左软键菜单的地方由option改为select

  // My.rss

  RESOURCE EIK_APP_INFO

  {

  menubar = r_bmpmanip_menubar;

  // cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT;

  cba = R_AVKON_SOFTKEYS_SELECT_BACK; // see “epoc32\include\avkon.rsg”

  }

  // MyAppUi.cpp

  void CMyAppUi::HandleCommandL(TInt aCommand)

  {

  switch(aCommand)

  {

  case EAknSoftkeySelect: // see “epoc32\include\avkon.hrh”

  {

  // left softkey is pressed…

  }

  …

  }

  }

  }

  问题十五、如何在CAknGrid上绘制背景图

  从CAknGrid派生自己的子类,然后自己draw,如:

  void CYourGrid:raw(const TRect& aRect) const

  {

  CWindowGc& gc = SystemGc();

  gc.DrawBitmap(aRect, aYourBitmap);

  CAknGrid:raw(aRect);

  }

  问题十六、两种从资源文件中读取常量的方法

  第一种 是老的方法了 要先 #include 才可以用

  TBuf<64> buf;

  CEikonEnv::Static()->ReadResource(buf,R_APP_LABEL);

  R_APP_LABEL 就是我们在资源文件中定义的常量

  第二种 新方法 要先 #include

  HBufC* buf;

  buf=StringLoader::LoadLC(R_APP_LABEL);

  在此之前要求先把资源文件给加进来噢, 格式 #include < 项目名.rsg>

  问题十七、如何取得imei

  #ifndef __WINS__

  TPlpVariantMachineId imei;

  PlpVariant::GetMachineIdL(imei);

  aImei.Copy(imei);

  #else

  问题十八、如何在Series 60窗体上绘制标签

  这是一种在Series 60窗体上显示标签的方法。你可以在电量图标或信号图标旁边显示一个标签,为此需要用程序实现。我使用了从CCoeControl继承的CIndicatorIcon 这个类。你需要象这样创建ConstructL():

  void CIndicatorIcon::ConstructL()

  {

  iMyWindowGroup = RWindowGroup(iCoeEnv->WsSession());

  User::LeaveIfError(iMyWindowGroup.Construct((TUint32)&iMyWindowGroup));

  iMyWindowGroup.SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront);

  iMyWindowGroup.EnableReceiptOfFocus(EFalse);

  CreateWindowL(&iMyWindowGroup);

  // 默认设置指示标签静止

  SetIndicatorIconL(EIndicatorIconAppActive);

  ActivateL();

  }

  在ConstructL()中,我调用了另一个函数 SetIndicatorIconL()设置标签:

  void CIndicatorIcon::SetIndicatorIconL(TIndicatorIcon aIndicatorIconType, TBool aRedraw)

  {

  switch(aIndicatorIconType)

  {

  case EIndicatorIconEmpty:

  iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_empty);

  iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_empty_mask);

  break;

  case EIndicatorIconAppActive:

  iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_bt_connect_on);

  iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_bt_connect_on_mask);

  break;

  case EIndicatorIconAppInactive:

  iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_bt_audio);

  iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_bt_audio_mask);

  break;

  default:

  break;

  }

  SetRect(TRect(TPoint(KIndicatorPosX, KIndicatorPosY),iIndicator->SizeInPixels()));

  // 如果 aRedraw == ETrue 从新绘制画布

  if(aRedraw)

  {

  DrawNow();

  }

  }

  你需要跳过CCoeControl的Draw()函数代码如下 :

  void CIndicatorIcon::Draw(const TRect& aRect) const

  {

  CWindowGc& gc = SystemGc();

  gc.Clear();

  gc.SetBrushStyle(CGraphicsContext::ENullBrush);

  gc.BitBltMasked(TPoint(aRect.iTl.iX, aRect.iTl.iY),

  iIndicator,

  TRect(TPoint(0, 0), iIndicator->SizeInPixels()),

  iIndicatorMask,

  ETrue);

  }

  现在把这些行加入到程序AppUi类的ConstructL()中:

  iIndicatorIcon = CIndicatorIcon::NewL();

  // 下一行将画标签并绘制到屏幕上

  iIndicatorIcon->SetIndicatorIconL(CIndicatorIcon::EIndicatorIconAppInactive, ETrue);

  问题十九、判断E盘是否可用

  TDriveInfo driveInfo;

  TInt error = fs.Drive(driveInfo, EDriveE);

  User::LeaveIfError(error);

  if (driveInfo.iDriveAtt == KDriveAbsent)

  {

  // drive E is absent

  }

  Reference: “How to retrieve drive and volume information”

  http://www.symbian.com/developer/techlib/v8.1adocs/doc_source/guide/Base-subsystem-guide/N1007E/FileServerClientSide/FileServerClientSideGuide2/DriveAndVolumeExample.guide.html

  问题二十、读取symbian上文件的例子

  RFile igpFile;

  RFs fs;

  TInt aSeek = 0;

  TInt aFileSize;

  TBuf16 igpName16;

  TParse parse ;

  parse.Set(CEikonEnv::Static()->EikAppUi()->Application()->AppFullName(), NULL, NULL);

  TBuf16<128> igpFullName ;

  igpFullName.Copy (parse.DriveAndPath()) ;

  igpFullName.Append (_L(”dice1.igp”));

  fs.Connect();

  // Write to file for later usage

  igpFile.Open( fs,

  igpFullName,

  EFileRead | EFileStream );

  igpFile.Seek( ESeekEnd, aSeek );

  aFileSize = aSeek;

  aSeek = 0;

  igpFile.Seek( ESeekStart, aSeek );

  aFileBuffer = HBufC8::NewL( aFileSize );

  igpFile.Read( aFileBuffer->Des (), aFileSize );

  igpFile.Close();

  fs.Close();

0
相关文章