最近一段时间一直在做三版Symbian上的http访问小程序实验,主要为了熟悉symbian的开发,同时想得到这样几个目的:1)实现真机通过CMWAP方式访问web;2)在手机访问web时,尽可能多的获取到手机相关的信息。对于初学者来说,有点无从下手。相信跟我一样的初学者在这个时候都会遇到这样几个问题:
1、开发环境的熟悉,签名文件的制作;
2、在模拟器上比较容易实现的网络连接,在真机上失败;
3、如何控制自动的选择网络接入点,而免去用户的选择;
4、在web端获取尽可能多的信息。
对于第一点,在前面的一篇文章中有所介绍,这里就先不提了。下面讲讲其他几点的完成过程,在这个过程中,我也是一边学习一边实验完成的。
通过大量的查阅资料,了解到,应用程序要在手机上实现网络连接需要具备几个条件:
1)mmp文件中的CAPABILITY描述,应加上NetworkServices选项,该能力是基本能力,不受签名级别的限制;
2)通过CMWAP或者CMNET方式接入网络。
一般来说,手机上有CMWAP和CMNET两种接入点,如果采用CMNET方式接入,可以简单的理解为PC上网,是能获取到一个C类地址的,那么就是说可以直接与Internet连接,但此种方式费用奇贵,一般不使用;如果通过CMWAP方式接入,就相当于局域网内的一台PC,要与Internet连接,就必须通过“网关”进行路由,而自身是没有外网地址的。这个“网关”就是中国移动的wap以及彩信代理服务器10.0.0.172,而这个“网关”只开放了80和9201端口(后者是起初的CSD方式接入的端口,现在很少用了)。这种方式接入,收取的费用现在基本上已经降到1分钱1K,包流量的话5元30M每月。
可见,如果不是钱多烧得慌,都会使用CMWAP来接入。这就要求应用程序能用代理方式连入Internet。
那么,第二点的问题的解决办法就是,在mmp文件中加入网络访问能力的描述,实现CMWAP代理访问。代理方式访问,解决代码如下:
// Parse string to URI (as defined in RFC2396) TUriParser8 uri; uri.Parse(aUri); TBuf8<20> aProxy8(_L8("10.0.0.172:80")); RStringF iPrxAddr = iSession.StringPool().OpenFStringL(aProxy8); CleanupClosePushL(iPrxAddr); THTTPHdrVal iPrxUsage(iSession.StringPool().StringF(HTTP::EUseProxy,RHTTPSession::GetTable())); iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF(HTTP::EProxyUsage,RHTTPSession::GetTable()), iPrxUsage); iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF(HTTP::EProxyAddress,RHTTPSession::GetTable()), iPrxAddr); CleanupStack:: PopAndDestroy(); // Get request method string for HTTP GET RStringF method = iSession.StringPool().StringF(HTTP::EGET, RHTTPSession::GetTable()); // Open transaction with previous method and parsed uri. This class will // receive transaction events in MHFRunL and MHFRunError. iTransaction = iSession.OpenTransactionL(uri, *this, method); // Set headers for request; user agent and accepted content type RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection(); SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent); SetHeaderL(hdr, HTTP::EAccept, KAccept); // Submit the transaction. After this the framework will give transaction // events via MHFRunL and MHFRunError. iTransaction.SubmitL();
这是在HttpClientExample例子的基础上修改的,实际上就是加上了aProxy,并在iSession.ConnectionInfo()中设置代理相关的属性即可。
第三点,例子中原来的做法是跟其他程序一样,调用API弹出一个接入点选择框,让用户选择之后,获取到选择的iapID,再使用这个iapID进行连接。如果能够在程序中自动的完成类似的操作,就可隐藏掉选择接入点的过程。以下是该函数:
TInt CClientEngine::GetIap(const TDesC8& aData) { CCommsDatabase* CommDb = CCommsDatabase::NewL(EDatabaseTypeIAP); CleanupStack::PushL(CommDb); TBuf<64> Name; TBuf<64> Name1; TBuf<64> Name2; TBuf<20> wap; wap.Copy(aData); wap.LowerCase(); TBool result = EFalse; TUint32 id = 0; TInt iapId = 0; CCommsDbTableView* tableIAP = CommDb->OpenTableLC(TPtrC(OUTGOING_GPRS)); // CCommsDbTableView* tableIAP = CommDb->OpenIAPTableViewMatchingBearerSetLC(ECommDbBearerCSD|ECommDbBearerGPRS,ECommDbConnectionDirectionOutgoing); if (tableIAP->GotoFirstRecord()==KErrNone) { do { tableIAP->ReadTextL(TPtrC(COMMDB_NAME),Name1); tableIAP->ReadTextL(TPtrC(GPRS_APN),Name); Name.LowerCase(); Name1.LowerCase(); if(Name.Find(wap) != KErrNotFound) { result = ETrue; break; } }while(tableIAP->GotoNextRecord()==KErrNone); } CleanupStack::PopAndDestroy(tableIAP); // CleanupStack::PopAndDestroy(CommDb); // if(result) { CCommsDatabase* CommDb1 = CCommsDatabase::NewL(EDatabaseTypeIAP); CleanupStack::PushL(CommDb1); CCommsDbTableView* tableIAP1 = CommDb1->OpenIAPTableViewMatchingBearerSetLC(ECommDbBearerGPRS,ECommDbConnectionDirectionOutgoing); tableIAP1->GotoFirstRecord(); do { tableIAP1->ReadTextL(TPtrC(COMMDB_NAME),Name2); Name2.LowerCase(); if(Name2.Find(Name1) != KErrNotFound) { TUint32 intVal=0; tableIAP1->ReadUintL(TPtrC(COMMDB_ID), intVal); iapId = intVal; break; } }while(tableIAP1->GotoNextRecord()==KErrNone); CleanupStack::PopAndDestroy(tableIAP1); // CleanupStack::PopAndDestroy(CommDb1); // } return iapId; }
在SetConnectionL函数中加入:
TUint32 iapID = GetIap(_L8("cmwap")); TCommDbConnPref connectPref; connectPref.SetIapId(iapID); // IAP ID for connection to be used connectPref.SetDialogPreference( ECommDbDialogPrefDoNotPrompt ); connectPref.SetDirection( ECommDbConnectionDirectionOutgoing ); User::LeaveIfError(iConnection.Start(connectPref));
记得把弹出选择框的代码注释掉。这样就实现了自动通过cmwap代理连接到Internet。
第四点,目前还在研究中,有了新的进展我会更新本篇博客的。