首先和以前各篇文章一样,我们先简要介绍几个重要的类: CMsvSession 该类代表客户端(客户端MTM、用户接口MTM或者客户端消息应用程序)与消息服务器端的通讯通道。每一个客户端线程对应一个该类的实例,CMsvSession提供客户端能及时获取消息服务端消息的有效方式。一个消息客户端应用必须在正常使用任何MTM或CMsvEntry对象前,使用OpenSyncL()或者OpenASyncL()来新建一个session对象。 CClientMtmRegistry Registry掌握了客户端所有目前可用的MTM有关的细节,消息客户端可以使用该类获得从CBaseMtm继承de对象。 CBaseMtm 这个类主要用来操作sms的内容,比如可以新建、修改sms;具体是使用方法下面将会借助代码说明,更详细的内容你也可以查看具体sdk的help。 CMsvEntry 相当于一个特定消息服务器的入口,当前entry与其的具体内容相关联。CMsvEntry包含两个部分的功能:一是可以允许访问与这个entry关联的,不同类型的数据;而是运行访问它的子entry。该类只在客户端使用,服务器端使用CMsvServerEntry。 TMsvEntry 用于代表消息服务器的一个入口,主要用于sms的新建。首先和以前各篇文章一样,我们先简要介绍几个重要的类: CMsvSession 该类代表客户端(客户端MTM、用户接口MTM或者客户端消息应用程序)与消息服务器端的通讯通道。每一个客户端线程对应一个该类的实例,CMsvSession提供客户端能及时获取消息服务端消息的有效方式。一个消息客户端应用必须在正常使用任何MTM或CMsvEntry对象前,使用OpenSyncL()或者OpenASyncL()来新建一个session对象。 CClientMtmRegistry Registry掌握了客户端所有目前可用的MTM有关的细节,消息客户端可以使用该类获得从CBaseMtm继承de对象。 CBaseMtm 这个类主要用来操作sms的内容,比如可以新建、修改sms;具体是使用方法下面将会借助代码说明,更详细的内容你也可以查看具体sdk的help。 CMsvEntry 相当于一个特定消息服务器的入口,当前entry与其的具体内容相关联。CMsvEntry包含两个部分的功能:一是可以允许访问与这个entry关联的,不同类型的数据;而是运行访问它的子entry。该类只在客户端使用,服务器端使用CMsvServerEntry。 TMsvEntry 用于代表消息服务器的一个入口,主要用于sms的新建。
下面还是看几段例程吧 TMsvSelectionOrdering sort; sort.SetShowInvisibleEntries(ETrue); //全部内容排序,包括隐藏 //设置入口为outbox,也就是发信箱 CMsvEntry* entry = CMsvEntry::NewL(*iSession,KMsvGlobalOutBoxIndexEntryId,sort); CleanupStack::PushL(entry); //选择全部内容 CMsvEntrySelection* entries = entry->ChildrenL(); CleanupStack::PushL(entries);
TTime time; //得到首信息的时间,At(0)代表首信息,取其他的可以给出相应的index time = entry->ChildDataL(entries->At(0)).iDate; //弹出对话框,有首信息接收人的号码信息 CAknInformationNote* informationNote = new (ELeave) CAknInformationNote; informationNote->ExecuteLD(entry->ChildDataL(entries->At(0)).iDetails);
CleanupStack::PopAndDestroy(2);
---------------------------------------- 注意:一些变量没有做介绍,比如iSession,这是因为前面的文章有提到过! ----------------------------------------上面这段例程的作用就是让大家了解一下如何获取并操作sms。 简单说一下:首先定义一个消息服务器的入口,关联着outbox;然后取出outbox中所有的短信内容,并存储到CMsvEntrySelection型指针指向的list中,操作list便可方便的操作outbox中的sms。 下面讲述了如果取单个sms的具体内容,这些都是公共变量,可以利用它们来获取sms的具体细节: ---------------------------------------- TTime iDate (类型和名称) Time (描述)短信时间 --------------------------------------------------------------------- TPtrC iDescription Description 短信内容 --------------------------------------------------------------------- TPtrC iDetails Details 发送或接受人号码 --------------------------------------------------------------------- TInt32 iError Error --------------------------------------------------------------------- TUid iMtm MTM ---------------------------------------------------------------------TInt32 iMtmData1 MTM data 1: this can be used for any purpose by an MTM. --------------------------------------------------------------------- TInt32 iMtmData2 MTM data 2: this can be used for any purpose by an MTM. --------------------------------------------------------------------- TInt32 iMtmData3 MTM data 3: this can be used for any purpose by an MTM. --------------------------------------------------------------------- TMsvId iRelatedId Related folder ID. --------------------------------------------------------------------- TMsvId iServiceId Service ID. --------------------------------------------------------------------- TInt32 iSize Size 短信大小 --------------------------------------------------------------------- TUid iType Entry type --------------------------------------------------------------------- TInt32 iWdpPortNumber Port number --------------------------------------------------------------------- TInt32 iBioType BIO message type ---------------------------------------- 通过使用上述变量就可以取得sms中的所有信息,我只对经常使用的几个做了介绍,剩下的当大家使用到时可以详细研究一下。上面的一段例程很简单、也很清楚,使用起来也会比较方便,接下来使用上面的方法我们可以同样实现delete操作:
TMsvSelectionOrdering sort; sort.SetShowInvisibleEntries(ETrue); CMsvEntry* entry = CMsvEntry::NewL(*iSession,KMsvDraftEntryId,sort); CleanupStack::PushL(entry);
CMsvEntrySelection* entries = entry->ChildrenL(); CleanupStack::PushL(entries); TInt i = entries->Count(); for(TInt ncount=0;ncount<i;ncount++) entry->DeleteL(entries->At(ncount)); // information to the user iEikonEnv->InfoMsg(_L("DeleteAll Done!")); CleanupStack::PopAndDestroy(2);
如果你已经理解了上面的读取sms信息的操作,这个全部删除也就不难理解了。所不同的只是调用了一个DeleteL()函数,这个函数是在类CMsvEntry中定义的,它可以删除固定index位置的sms。详情可以查看相关sdk help
有了上面的了解,不难看出sms的操作其实和我们上一讲所说的vCard有类似之处,下面我们来看看如何将sms的内容导出到文件。 这里会用到类CBaseMtm,看下面例程:
iSmsMtm->SwitchCurrentEntryL(aEntryId); iSmsMtm->LoadMessageL(); // load the message
CRichText& body = iSmsMtm->Body(); //sms的内容存到CRichText控件对象中 TPtrC msg(body.Read(0)); WriteToFileL(msg);
iSmsMtm是CBaseMtm类型的指针变量,它当然需要初始化,如下方式: 1.iSession = CMsvSession::OpenAsyncL(*this); // 该函数的参数应该是从MMsvSessionObserver继承过来的任何类.....它会和 session library 间建立一个异步连接... //然后你可以在函数HandleSessionEventL中收到事件EMsvServerReady... //事件到达表明同服务器间的通话已建立... 接着去得到 Mtm Registry,并返回 SMS mtm... 2.iMtmReg = CClientMtmRegistry::NewL(*iSession); 3.iMtmSms = static_cast<CSmsClientMtm *> (iMtmReg->NewMtmL(KUidMsgTypeSMS));
下面是WriteToFileL()函数的具体实现:
void WriteToFileL(const TPtrC &aMsg) { //设置存储路径以及文件 _LIT(KDirName,"//system//apps//MyApp//Data"); _LIT(KFileName,"//system//apps//MyApp//Data//MsgBody.txt"); //连接文件服务器并生成相应文件夹 RFs fileSession; fileSession.Connect(); fileSession.MkDirAll(KDirName);
RFileWriteStream writer; writer.PushL(); User::LeaveIfError(writer.Replace(fileSession, KFileName, EFileWrite)); //写入文件并确认 writer << aMsg; writer.CommitL();
CleanupStack::PopAndDestroy(); fileSession.Close(); } //以下头文件会使用到 #include <smsclnt.h> #include <smut.h>
上面的步骤清晰明了,无需多说,大家要注意一下CBaseMtm这个类的用法,因为在接下来,我们看到的新建sms同样会重点使用到这个类,而且使用的次数会更多。
新建sms的步骤较为复杂,我们列出一些主要步骤:
TMsvEntry newEntry; newEntry.iMtm newEntry.iType newEntry.iServiceId newEntry.iDate.HomeTime();//一般设置为当前时间 newEntry.SetInPreparation(ETrue);//设置为true
设置好上面的参数之后,接下来就可以使用CBaseMtm类来完成新建操作了
CBaseMtm* iMtmSms; ... iMtmSms->SwitchCurrentEntryL(KMsvGlobalInBoxIndexEntryId);//设置为收信箱 iMtmSms->Entry().CreateL(newEntry);
long smsId = newEntry.Id();//得到新sms的id iMtmSms->SwitchCurrentEntryL(smsId); //设置sms的详细内容 _LIT(KSMSBody,"Hello World!"); CRichText& body = iMtmSms->Body(); body.Reset(); body.InsertL(0,KSMSBody); newEntry.iDescription.Set(KSMSBody); //设置sms的收信或发信人手机号码 iMtmSms->AddAddresseeL(_L("13500000000")); newEntry.iDetails.Set(_L("13500000000")); iMtmSms->Entry().ChangeL(newEntry); //别忘了保存 iMtmSms->SaveMessageL();
如此一来,你就可以新建一条sms了,当然有了新建sms的经验,实现修改sms的信息也就不困难,主要步骤可分为三步: 1. 给定一些需要修改sms的信息,比如id、index、所在位置或其他 2. 通过搜索找到满足条件的sms,并暂存这些结果 3. 利用搜索结果进行sms信息修改,最后确认变化即可 这里对sms的修改就不做详细的分析,大家可以自己尝试一下!
发送SMS也许我们大多数人都操作过,简单说来就是编辑一段文本,然后选择一个或多个目标号码,点击发送一切ok。其实在程序中实现的步骤也是如此,只不过需要我们了解更多的知识。 老方法,我们先来了解一些必须的类: CSmsSettings 设置sms服务的属性类 CSmsHeader sms头信息,主要有关消息的各种参数,当然与上面的CSmsSettings密切相关
其他有关sms的类在上一节我们都大致介绍了,这里不重复说明,接下来我们会用一些具体的源码加以分析。
首先,我们需要新建一个sms而且得到接受方的号码,这两步可以参照上一节的内容,里边详细介绍了如何新建一条sms。 然后就是要设定发送前的一些参数信息,并选择做一些相应的操作。
程序代码: //iMtm是在新建sms阶段设定 TMsvEntry msvEntry = iMtm->Entry().Entry(); // 得到sms内容 CRichText& mtmBody = iMtm->Body(); mtmBody.Reset(); mtmBody.InsertL(0, KGDSMSTag); //插入我们的短信标示 //重新设定TMsvEntry msvEntry.iDetails.Set(iRecipient->Des()); // set recipient info in details msvEntry.SetInPreparation(EFalse); // set inPreparation to false msvEntry.SetSendingState(KMsvSendStateWaiting); // set the sending state (immediately) msvEntry.iDate.HomeTime(); // set time to Home Time // 使用CSmsClientMtm类处理sms CSmsClientMtm* smsMtm = STATIC_CAST(CSmsClientMtm*, iMtm); smsMtm->RestoreServiceAndSettingsL(); // CSmsHeader封装sms消息的参数,像服务中心号码和发送设定 CSmsHeader& header = smsMtm->SmsHeader(); //CSmsSettings类用来详细设定sms Header CSmsSettings* sendOptions = CSmsSettings::NewL(); CleanupStack::PushL(sendOptions); sendOptions->CopyL(smsMtm->ServiceSettings()); sendOptions->SetDelivery(ESmsDeliveryImmediately);//设定立即发送 header.SetSmsSettingsL(*sendOptions); //检查服务中心号码有效性 if (header.Message().ServiceCenterAddress().Length() == 0) { // 如果没有设定,则查找默认中心号码 CSmsSettings* serviceSettings = &(smsMtm->ServiceSettings()); // 中心号码列表为空 if (!serviceSettings->NumSCAddresses()) { // 错误消息 iEikonEnv->InfoWinL(_L("No service center number"),_L("cannot send this one.")); } else { // 设定为默认服务中心号码 CSmsNumber* sc = 0; sc = &(serviceSettings->SCAddress(serviceSettings->DefaultSC())); header.Message().SetServiceCenterAddressL(sc->Address()); } } CleanupStack::PopAndDestroy();
... ...
CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection; CleanupStack::PushL(selection); selection->AppendL(movedId); // 添加我们要发送的sms,movedId在省略部分有定义,是TMsvId型变量 // 调用的这个函数是用于发送的,具体的代码后面介绍 SetScheduledSendingStateL(selection); CleanupStack::PopAndDestroy(); // selection return ETrue; // 到这里sms已被发送
SetScheduledSendingStateL函数的代码如下:
程序代码: void ...::SetScheduledSendingStateL(CMsvEntrySelection* aSelection) { CBaseMtm* smsMtm = iMtm; // 添加entry到任务列表 TBuf8<1> dummyParams; CCommandAbsorbingControl::NewLC(); CMsvOperationWait* waiter = CMsvOperationWait::NewLC(); waiter->Start(); // 这个函数是关键 CMsvOperation* op= smsMtm->InvokeAsyncFunctionL( ESmsMtmCommandScheduleCopy, *aSelection, dummyParams, waiter->iStatus); CleanupStack::PushL(op); CActiveScheduler::Start(); //开始时间表中任务 CleanupStack::PopAndDestroy(3); // waiter, op, CCommandAbsorbingControl }
需要我们注意的是:在发送sms的过程中大部分的操作都是用于设定发送sms时的参数,所以东西比较琐碎;如果您想自己实现这部分工作,给您的建议就是尽量采用一个比较通用的方法,无需设定一些让人捉摸不定的信息。在发送sms中起主要作用的还是CBaseMtm类,这个类以及从它继承的类负责sms的具体发送,所以整个过程的结束点一定是使用这些类的函数来实现发送的动作,犹如上述的InvokeAsyncFunctionL函数。