导航

忆龙2009:Brew FAQ-常见问答(2)

Posted on 2010-01-17 09:54  忆龙2009  阅读(783)  评论(0编辑  收藏  举报

(1)使用 ITAPI_MakeVoiceCall 进行语音呼叫后,为什么在我对“Return to Application(返回应用程序)”提示响应“No(否)”时我的应用程序似乎要重新启 动?
请确保参数 clsReturn(调用结束后要启动的应用程序) 在 ITAPI_MakeVoiceCall 的调用中为 0(零)。如果您将 clsReturn 指定为您的应用程序的 ClassID, 则 BREW 将尝试创建另一个应用程序的实例,而不是 恢复您的应用程序。
(2)终止数据呼叫后立即进行语音呼叫时应遵守哪些指导原则?
释放最后一个套接字之后,终止 PPP 连接之前,BREW 要等待网络延迟时间(默认为 30 秒钟)过期。实际断开 PPP 连接需用大约 3 秒钟时间。因此释放最后一个套接字和调用 ITAPI_MakeVoiceCall() 之间必须经过(延迟时间 + 3 秒钟)的时间。在释放最后一个套接字和进行语音呼叫之间应该使用一个(延迟时间+ 3 秒钟)的计时器。

例如:
ReleaseNetAndSocket(pMe);
//以下 LINGER_TIME 的单位为秒
ISHELL_SetTimer(pMe->a.m_pIShell, (LINGER_TIME +3) * 1000,
Timer_CB, (void *)pMe);

在计时器回调代码中,可以使用 ITAPI_MakeVoiceCall() 进行语音呼叫。

有关 ITAPI_MakeVoiceCall() 的详细信息,请参阅下面的 FAQ:

使用 ITAPI_MakeVoiceCall 进行一个语音呼叫后,为什么在我对 “Return to Application(返回应用程序)”提示响应“No(否)”时,我的应用程序似乎被重新启动? FAQ。

(3)使用 ITAPI_MakeVoiceCall 进行一个语音呼叫时,对 Privacy Alert(隐私警告)响应 No(否)会使应用程序挂起。有什么解决办法? 

注意:在 BREW SDK 版本 2.0 中,此 3 秒延迟已内置到 BREW 中。 应用程序无需在它的计时器中实现另外的三秒钟。

(4)在数据呼叫之后立即进行语音呼叫时, 为什么我看到的是 Privacy Alert(隐私警告)而不是“Return to Application(返回应用程序)”?
请参阅“终止数据呼叫之后立即进行语音呼叫时应遵守哪些 指导原则?”FAQ。

(5)如何获取正在运行我的应用程序的 设备电话号码?
应用程序可以调用 ITAPI_GetStatus() 来获取程序所运行 设备的电话号码。电话号码将位于 TAPIStatus.szMobileID 中。

例如:
TAPIStatus tapiStat;
if (ITAPI_GetStatus(pMe->p_tapi, &tapiStat) == EBADPARM) {
DisplayOutput((IApplet*)pMe, 6, "TAPI Status fetch failed");
}
DisplayOutput((IApplet*)pMe, 4, "Mobile ID:");
DisplayOutput((IApplet*)pMe, 5, tapiStat.szMobileID);

(6)BREW 何时会提供 HTTP 支持?
HTTP 支持在 BREW SDK 版本 1.1 中通过 AEEWeb 接口提供。对于 SDK 的早期版本,请使用 ISocket 接口连接到服务器的 HTTP 端口并发送 HTTP“get”和“post”请求。

(7)GetHostByName() 为什么在我的电话上不起作用?
要使 INETMGR_GetHostByName() 正确工作,电话的域名服务器 (DNS) 设置必须正确配置。这通常由服务提供商负责。在这种情况下,应将电话退回销售点或授权维修中心,以便正确配置其 DNS 设置。

目前,北美客户可以将电话寄至 QUALCOMM 进行 DNS 配置。这是临时性的解决办法,等到服务提供商安排好后,将由服务提供商处理客户电话的 DNS 配置事宜。有关将电话寄至何处进行 DNS 配置的信息,请参阅本 FAQ。

(8)使用 GetHostByName() 时为什么在 dnsresult.addrs 中获得 0.0.0.0 值?
这可能是由于 GetHostByName() 回调函数中错误处理的不正确实施引起的。NetSocket 示例的 GetHostByName() 回调函数中的错误处理实施不正确。请使用以下示例实施:
if(pMe->dnsresult.nResult > 0 && pMe->dnsresult.nResult
<= AEEDNSMAXADDRS) {
// DNS 查找 成功
// 处理 dnsresult.addrs
for(i = 0; i < pMe->dnsresult.nResult; i++) {
SPRINTF(szMsg,"Addr=:%x",pMe->dnsresult.addrs[i]);
DisplayOutput(pMe,i+4,szMsg);
}
} else {
// DNS 失败 - 错误代码为 dnsresult.nResult
SPRINTF(szMsg, "DNS:error %d", pMe->dnsresult.nResult);
DisplayOutput(pMe, 2, szMsg);
}

(9)由于 BREW 中没有 TCP/IP 刷新命令,如何能够确认命令立即发出?
无法确定何时发出 TCP/IP 命令;BREW 不提供此功能。

(10)BREW 支持的最大数据包大小是什么?
最大数据包大小由 OEM 确定,对于各生产商的电话各不相同。BREW 不对此限制进行控制。

(11)传输大文件时,是否必须在发送前将文件分割成数据包,或者 BREW 是否会代我执行此操作?
您只应发送能够发送的内容,ISOCKET_Write() 将告诉您实际上已经发送了多少数据。如果有数据尚未发送,只需用您对 ISOCKET_Write() 的上次调用显示的量来抵消您的数据指针即可。

例如:
void CommonWriteCB (void *pUser) {
char *psz = NULL;
int cbWrite;
... ... ...
SampleApp * pMe = (SampleApp*)pUser;
// pszData 是要写入的数据
psz = pszData;
cbWrite = STRLEN (pszData);

// 循环直至已写入所有字节。
while (cbWrite > 0) {
rv = ISOCKET_Write(pMe->m_pISocket, (byte *)psz,
(uint16)cbWrite);

if (rv == AEE_NET_WOULDBLOCK) {
// 无法成功写入字节。注册
// 回调,稍后再试。
ISOCKET_Writeable(pMe->m_pISocket,
CommonWriteCB, (void *)pMe);
return;
} else if (rv == AEE_NET_ERROR) {
// 写入错误。
ReleaseNetAndSocket(pMe);
return;
}

// 如果只写入了一部分,则循环并写入剩余部分
cbWrite -= rv;
psz += rv;
}
... ... ...
}

(12)同时可以打开多少个套接字?
此限制因 OEM 而异,将依据运行您的小程序的设备而不同 - 它不由 BREW 设置。

是否在主线程环境下调用网络回调?如果是这样,在当前环境下如何保持数据完整性?
在调用程序将控制权返回 AEE 事件循环之后的某个时间点,所有网络回调发生在同一线程上下文中。如果您的应用程序正在忙于执行某项操作,则会将回调排队,然后一旦您的应用程序将控制权返回 AEE 事件循环将进行调用,从而确保数据完整性。

(13)从套接字读取时,电话读取一次能够读取的所有内容,而模拟器一点一点读取大数据包。为什么?
这是电话的局限性。

您的程序应该调用 ISOCKET_Readable(),以便在可以从流中读取更多数据时得到通知。每当数据可用时将调用 ISOCKET_Readable() 注册的回调例程 - 通常可以在此时调用 ISOCKET_Read()。只要您的程序期望获得更多数据,就继续调用 ISOCKET_Readable()。

rv = ISOCKET_Read(piSock, (byte *)szBuf, sizeof(szBuf));
if (rv == AEE_NET_WOULDBLOCK) {
// WOULDBLOCK => 此时无其它可用数据
// 注册回调,稍后读取数据。
ISOCKET_Readable(piSock, CommonReadCB, (void*)pMe);
return;
}
else if (rv == AEE_NET_ERROR) {
// 从套接字读取时出错
ReleaseNetAndSocket (pMe);
}
else if (rv > 0) {
// 数据的 rv 字节已从套接字读入
// szBuf

// 读取剩余数据
ISOCKET_Readable(piSock, CommonReadCB, (void*)pMe);
}
else { // rv == 0
// 没有其它数据要接收。
// 对方已断开连接。
ReleaseNetAndSocket (pMe);
}

(14)如何检查我的套接字和 PPP 连接的状态?
您可以使用 INETMGR_NetStatus() 检查 PPP 连接的状态(激活、未激活、正在打开或正在关闭)。
NetState netState = NET_INVALID_STATE;
AEENetStats netStats;
netState = INETMGR_NetStatus (pINetMgr, &netStats);

您可以使用 INETMGR_OnEvent() 监控 PPP 连接和套接字连接的状态。请参阅 AEENet.h 中的 NetMgrEvent 枚举以获取包括所有网络和套接字事件的列表。
// 注册接收网络和套接字事件
INETMGR_OnEvent(piNet, (PFNNETMGREVENT)CheckNetStatus,
(void*)pMe, TRUE);

//接收到网络/套接字事件时调用回调
static void CheckNetStatus(void* cxt,
NetMgrEvent evt, uint32 dwData) {
SampleApp *pMe = (SampleApp*)cxt;

if(evt == NE_PPP) {
// 网络事件。 dwData = NetState 枚举值
// 请参阅《BREW API 参考资料》文档中的 NetState 数据结构
}
if(evt == NE_SO_CLOSING || evt == NE_SO_CLOSED) {
// 套接字事件 - 正在关闭或已关闭。
// DwData 是指向套接字的指针
}
... ...
return;
}

(15)是否可以在两个电话间传输数据?
我们发现电话间的对等连接是不可靠的,当两个电话在同一子网上时会失败。因此,最好使用代理服务器,使用服务器作为媒介在电话间传输数据。
(16)启用 BREW 的设备是否可以用作服务器?
除了明显的内存和性能限制外,在电话上运行 BREW 应用程序时无法监听套接字连接。这些因素使得在 BREW 上实施服务器十分困难。

(17)是否有方法可以确定套接字已经连接?
有两种方法可以确定套接字是否已经连接。最容易的方法是检查 ISOCKET_Connect() 的返回值。套接字已经连接时,ISOCKET_Connect() 将返回 EISCONN。

同样,也可以通过使用 INETMGR_OnEvent() 注册套接字状态改变事件 NE_SO_CLOSING 和 NE_SO_CLOSED 来监控套接字连接状态。通过使用此方法,您的应用程序可以避免试图连接已经连接的套接字。

要了解有关网络和套接字事件(包括 NE_SO_CLOSING 和 NE_SO_CLOSED)的详细信息,请参阅以下包含文件:AEENet.h。

例如:
// 注册接收网络和套接字事件
INETMGR_OnEvent(piNet, (PFNNETMGREVENT)CheckNetStatus,
(void*)pMe, TRUE);

//接收到网络/套接字事件时调用回调
static void CheckNetStatus(void* cxt, NetMgrEvent evt,
uint32 dwData)
{
SampleApp *pMe = (SampleApp*)cxt;

if(evt == NE_SO_CLOSING || evt == NE_SO_CLOSED) {
// 标记设置为 false,说明套接字已断开
pMe->m_SocketConnected = FALSE;
ReleaseNetAndSocket(pMe);
}
if(evt == NE_SO_CONNECTED) {
// 标记设置为 true,指示套接字已连接
pMe->m_SocketConnected = TRUE;
}
return;
}

(18)为什么 ISOCKET_Release() 在应该返回 0 值时却返回 1?
应用程序调用 ISOCKET_Release() 时,ISocket 对象的内部状态更改为“正在关闭”,BREW 开始等待异步“已关闭”事件。由于回调中收到已关闭事件,ISocket 对象的引用计数递增,防止它在内部状态改变为“已关闭”前释放。

(19)我试图创建 Net Manager 的实例 (AEECLSID_Net) 时为什么 ISHELL_CreateInstance 返回 ECLASSNOTSUPPORT?
    这可能是因为您的小程序对 MIF 文件的权限而引起的。请在 MIF 编辑器中打开 MIF 文件,检查复选框中的网络权限,然后保存。

(20)我是否可以获得监听 TCP 套接字?
不可以。我们建议使用 UDP,具体地说是 ISOCKET_Bind 和 ISOCKET_RecvFrom。

(21)BREW 是否支持编块套接字?
不支持。BREW 使用异步套接字。您可以使用 ISOCKET_Readable 或 ISOCKET_Writeable 以便在安全读写时得到通知。
(22)不在蜂窝电话覆盖范围时如何处理?
电话不在覆盖范围时,数据呼叫会中断。发生这种情况时,BREW 会清除正在使用的基本 OEM 套接字。应用程序使用的 ISocket 继续存在,应用程序将在试图使用它们时获得相应的错误响应。

对于同步 (TCP/IP) 数据通信,有两种方法可以处理可能错误的套接字:

1. 检查从所有套接字操作中返回的值

从套接字中读取或写入会导致返回 AEE_NET_ERROR。在您的代码中,您应该检查套接字连接、读写的返回值并采取相应措施。

在下面的代码片段中,相应操作是显示主菜单:
// 连接回调
static void SampleApp_ConnectCB(void *cxt, int err) {
SampleApp *pMe = (SampleAppApp*)cxt;

if (err) {
// 连接失败
SampleApp_CleanUp(pMe);
//清除 net manager 和
// 套接字
ShowMainMenu(pMe);
return;
}
... ... ... ...
}

// 正在写入
iRet = ISOCKET_Write(pMe->m_piSock, (byte*)Request,
(uint16)STRLEN(Request));
if (iRet == AEE_NET_ERROR) {
// 写入错误
SampleApp_CleanUp(pMe);
//清除 net Manager 和套接字
ShowMainMenu(pMe);
return;
}

// 正在读取
iRet = ISOCKET_Read(pMe->m_piSock, (byte*)buf,
sizeof(buf));
if (iRet == AEE_NET_ERROR) {
// 读取错误
SampleApp_CleanUp(pMe);
//清除 net manager 和套接字
ShowMainMenu(pMe);
return;
}

2. 注册网络/套接字状态中的更改

处理数据呼叫正在进行时电话不在覆盖范围情况的另一种方法是使用 INETMGR_OnEvent() 注册网络和套接字事件,并在接收到网络/套接字状态更改通知时采取相应措施。在下例中,设置了一个标记,表明套接字错误。使用前要检查套接字状态。

有关网络和套接字事件的详细信息,请参阅 aeenet.h 包含文件中的 NetMgrEvent 和 NetState 枚举。

例如:
// 注册接收网络和套接字事件
INETMGR_OnEvent(piNet, (PFNNETMGREVENT)CheckNetStatus,
(void*)pMe, TRUE);

//接收到网络/套接字事件时调用回调
static void CheckNetStatus(void* cxt, NetMgrEvent evt,
uint32, dwData) {
SampleApp *pMe = (SampleApp*)cxt;

if(evt == NE_PPP) {
if(dwData == NET_PPP_CLOSING || dwData ==
NET_PPP_CLOSED) {
// 标记设置为 false,说明套接字已坏
pMe->m_SocketState = FALSE;

// 清除网络和套接字
ReleaseNetAndSocket(pMe);
}
}
if(evt == NE_SO_CLOSING || evt == NE_SO_CLOSED) {
pMe->m_SocketState = FALSE;
ReleaseNetAndSocket(pMe);
}

if(evt == NE_SO_CONNECTED) {
pMe->m_SocketState = TRUE;
}
return;
}

// 使用套接字之前检查它的状态
static void RoadWarriorApp_ReadCB(void *cxt) {
int rc;
SampleApp *pMe = (SampleApp *)cxt;
if(pMe->m_SocketState == FALSE) { //socket is bad
ReleaseNetAndSocket(pMe);
ShowMainMenu(pMe);
return;
}

rc = ISOCKET_Read(piSock, (byte*)buf, sizeof(buf));
... ... ...
... ... ...
}

使用 INETMGR_InEvent() 注册网络和套接字事件时,必须在终止应用程序前使用 INETMGR_OnEvent() (bRegister = FALSE) 取消注册。

请注意:电话超出覆盖范围后,套接字无法使用。必须在下次要求时释放您的 Isocket 并重新实例化。INetMgr 在用于下次网络操作前不必释放和重新实例化,

不过这样做也无妨。

要处理异步 (UDP) 数据通信可能错误的套接字,请注册网络/套接字状态的变化(如上文第 2 条所述)。

(23)通过关闭打开的套接字终止数据呼叫时,为什么电话仍显示数据呼叫正在进行?
关闭最后一次连接的套接字后,BREW 会在终止 PPP 连接前等待一定的延迟时间。因此,出现了延迟的呼叫正在进行显示。

默认延迟时间为 30 秒。要更改延迟时间,请使用 INETMGR_SetLinger()。

服务中断时(尽管试图连接)或服务器不响应时为什么我的连接回调不超时?
这是由于 BREW 版本 1.0.1 SDK 中的缺陷引起的 - 在以下情况下不调用连接回调:
试图连接时服务中断。
服务器不响应

作为暂时解决办法,您应该使用与回调相关的计时器。如果 30 秒内不发生连接回调,则应该引起连接超时。

例如:
// 初始化 pMe->connectCBInvoked = FALSE;
// 调用 ISOCKET_Connect() 之前将计时器设置为 30 秒钟
ISHELL_SetTimer(pMe->a.m_pIShell, 30000, ConnectTimeout_CB, (void *)pMe);
ISOCKET_Connect(pMe->m_pISocket, nodeINAddr, AEE_htons(USAGE_TEST_PORT),
SampleApp_ConnectCB, pMe);

// 设置说明已调用连接 CB 的标记
void SampleApp_ConnectCB(void *cxt, int err) {
SampleApp *pMe = (SampleApp*)cxt;

// 设置说明已调用连接 CB 的标记
pMe->connectCbInvoked = TRUE;
if (err) {
DisplayOutput((IApplet*)pMe, 3, "Connect failed!");
return;
}
DisplayOutput((IApplet*)pMe, 3, "Connected!");
}

// 计时器过期时,检查是否已调用连接 CB
static void ConnectTimeout_CB(void* cxt) {
SampleApp *pMe = (SampleApp *)cxt;

if(pMe->connectCbInvoked == FALSE) {
// 在 30 秒内未调用回调 - 取消连接回调
ISOCKET_Cancel(pMe->m_pISocket, 0, 0);
DisplayOutput((IApplet*) pMe, 3, "Connection timed out");
}
else {
// 已调用回调。将标记设置为默认值 FALSE
pMe->connectCbInvoked = FALSE;
}
}

(24)使用 ISHELL_CreateInstance 进行初始化时为什么我的 INetMgr 对象为 NULL?其它对象(如 IDisplay 或 IGraphics)已经正确初始化。
请参阅我试图创建 Net Manager 的实例 (AEECLSID_Net) 时为什么 ISHELL_CreateInstance 返回 ECLASSNOTSUPPORT?(技术 FAQ 7o)。
(25)调用 INETMGR_GetHostByName() 执行 DNS 查找时应该采取哪些预防措施?
必须在所有退出途径中使用 CALLBACK_Cancel() 确保您的应用程序取消未完成的 DNS 回调(如果有)。这包括中止应用程序和停止应用程序的情况(都通过结束键和清除键)。

例如,如果您使用了以下代码来查找 DNS 地址:
CALLBACK_Init(&pMe->cbkLookup, GetHostByNameCB, pMe);
INETMGR_GetHostByName(pINetMgr,&pMe->dnsresult, hostName,
&pMe->cbkLookup);

您应该使用以下代码在所有退出途径中取消回调:
// 检查是否可以取消回调。如果 NULL
// 已发生,无法取消。
if(pMe->cbkLookup.pfnCancel != NULL) {
CALLBACK_Cancel(&pMe->cbkLookup);
}

回调取消代码应该并入中止事件处理程序代码 (EVT_APP_SUSPEND)、应用程序的 FreeAppData 函数(在应用程序停止时,即接收 EVT_APP_STOP 事件时调用)和清除键按键事件处理程序代码 (EVT_KEY 和按键代码 AVK_CLR) 中。有关详细信息,请阅读下文:中止和恢复应用程序及下面的 FAQ:使用电话的“End(结束)”键关闭小程序和使用“Clear(清除)”键关闭小程序有何区别?。

请注意:如果您的应用程序没有正确地取消其未完成的 DNS 回调,则不会通过 TRUE BREW 测试。可能表示您的应用程序未取消未完成的 DNS 回调的某些故障现象如下:
电话在启动应用程序时失效
电话在启动应用程序时显示“Please Re-insert Battery(请重新插入电池)”错误

两者都表示以前余兴的应用程序未取消其未完成的 DNS 回调。

(26)对于我可以设置的应用程序网络延迟时间的值有限制吗?
提供 INETMGR_SetLinger() 函数以使开发者灵活设计他们的应用程序。但是,建议不要变更 OEM 选定的默认延迟时间(通常为 30 秒钟),除非您的应用程序有非改不可的理由。变更任一上目录中的默认延迟时间都可能导致您的应用程序无法通过 TRUE BREW 测试,或导致运营商拒收您的应用程序。

(27)BREW 支持哪些图像格式?
BREW 支持颜色深度达到运行设备上提供的值的任何 BMP 文件。BREW 目前尚不支持 GIF 和 JPEG 图像。目前,您需要将 GIF 和 JPEG 图像转换为 BMP 图像。

BREW SDK 版本 1.1 将支持 PNG 格式和 BREW Compressed Image (BCI) 格式。

在 1.1 之前的 SDK 版本中,模拟器只能模拟 1 位、4 位和 8 位颜色深度的 BMP。在版本 1.1 中,模拟器仅可以显示 2 位颜色深度的 BMP。

(28)彩色和单色电话上的透明色是什么?
紫色是彩色色被的透明色。白色是单色和 4 级灰度设备上的透明色。

(29)如何将光标移动到文本输入的末尾?
可以连续对字符串调用 ITEXTCTL_HandleEvent() 方法 n 次(其中,n 是字符串的长度)以将光标移动到字符串的末尾。

例如:
while(len) {
ITEXTCTL_HandleEvent(pMe->m_pIText, EVT_KEY,
AVK_RIGHT, dwParam);
len--;
}

请注意:当前,这在 Kyocera 3035 上不工作,除非将 dwParam 设置为 10(相对于 AVK_RIGHT)。Kyocera 正在试图解决此问题,以便无需对 dwParam 进行明确设置。设置 dwParam = 10 对 Sharp Z-800 手持设备没有不良影响。

BREW SDK 版本 1.2 将增加一个新的 API - ITEXTCTL_SetCursorPos(),用来设置文本控件的光标位置。

(30)如何创建有水平和垂直滚动条的文本控件?
如果文本大于文本控件,则会显示一个垂直或水平滚动条,使您可以使用方向键在文本中定位。

(31)使用 IDISPLAY_BitBlt() 绘制位图时为什么会收到内存错误,如“memheap.c 0696”?
请确保释放 CONVERTBMP 分配的内存。检查 CONVERTBMP 的最后一个布尔型参数。如果为 True,则重新分配已完成,必须使用 SYSFREE 来释放内存。

例如:
pBmp = CONVERTBMP (pDataBytes, &imageInfo, &bVal);
IDISPLAY_BitBlt (pIDisplay, xDest, yDest, cxDest,
cyDest, pBmp, xSrc, ySrc, dwRopCode);
IDISPLAY_Update (pIDisplay);
if(bVal) //只有完成 realloc 后才能释放
SYSFREE (pBmp);

请参阅 API 参考文档中的 CONVERTBMP 助手函数说明。若需示例代码,可以参阅 IDisplay 用法示例。

(32)如何不让标题区域在 Istatic 上显示?
SDK 版本 1.0 目前无法对标题区域进行限制。BREW 版本 1.1 中已增加此功能。