16

我正在尝试对是否可以接收 C2DM 消息进行最佳猜测。

我创建了一个应用程序,它依赖于在物理上无法访问时将信息推送到手机。我知道 C2DM 不能保证传递,但我至少想知道何时可以传递消息;如果不是,我们会退回到我们自己的推送服务(并且实际上可以判断我们何时连接)。

我注意到即使没有登录的谷歌帐户,Android 上的 C2DM 仍会发出身份验证令牌;在这种情况下,消息似乎仍然被传递,即使它声明它们不应该传递。如果 GTalk 未连接(防火墙或其他原因),则在请求身份验证令牌时根本不会返回任何响应。当手机处于飞行模式时,身份验证令牌会返回给应用程序。这意味着它不像检查互联网是否可用那么简单。我找不到检查 GTalk 是否已登录的可靠方法。

同样,我不需要保证消息的传递,但我至少想知道传递是否可能。有没有人有有趣的解决方案?

4

8 回答 8

11

去看这个视频,这是一个关于 C2DM、如何使用它以及它是如何工作的 Google I/O 演讲。AFAIK,您不知道它是否已连接。可能大多数时候他们甚至都不知道(直到他们必须传递消息并失败)。

但是,强烈建议(在视频中也是如此)您不要通过 C2DM 发送重要数据(因为消息可能会丢失)。该服务应仅用作“网络搔痒”(占用空间尽可能小)。您的应用程序应该被这个痒痒唤醒,它应该开始获取它自己需要的信息。

现在,如果您以这种方式实现它,那么实现轮询机制应该很容易。由于您已经将“tickle”与实际信息检索分开,如果没有tickle,您可以每隔一段时间触发一次检索。

您可以检查 C2DM 是否已连接,例如 ping:

  1. 通过 C2DM 向手机发送消息
  2. 应用程序接收(或不接收)消息并将“pong”发送回您的服务器
  3. 服务器在将设备标记为“离线”之前等待“pong”一段预定的时间(我会说 1-2 分钟)。

编辑:依靠 GTalk 是不可行的。GTalk 依赖于 C2DM 就像您的应用程序一样,它没有任何“额外”。此外,并非所有设备上都存在 GTalk。我不确定 GTalk 应用程序如何确定它是否离线(不幸的是,它不是开源的),但我猜它只是尝试 ping 服务器并失败。

于 2011-10-31T16:46:47.070 回答
7

不,那是不可能的。因为您的设备经过了一次身份验证并生成注册 ID 并发送到第三方服务器(如您所知)。一旦设备注册,您的工作就结束了。所以请等待您收到或没有收到的消息(否保证作为 C2DM 使用 UDP 协议传递消息)。

替代解决方案

虽然它不可能像我上面提到的那样直接从谷歌方面检查,但是如果你有任何紧急检查手机连接的情况,那么你可以采取这样的方法

步骤 1):创建一个 Web 服务来检查连接

第 2 步):从应用程序调用此 Web 服务,该应用程序将命令服务器发送推送通知以进行检查。

第 3 步):现在从服务器端,服务器将立即发送特定设备的推送通知(从它获取命令)

第 4 步):现在,如果您收到推送通知,这意味着您仍然连接到 C2DM。

这不会花费太多时间。但是只有在检查连接紧急并且用户使用时才遵循它

于 2011-11-01T12:43:24.540 回答
1

这可能有点天真,因为我不是活跃的 C2DM 用户,但不可能阅读

/proc/net/netstat

并查看是否有任何活动的 TCP 连接。如果没有,那么 C2DM 就不可能工作。您还可以通过形成您希望找到的 C2DM 白名单(或者可能在特殊的 C2DM 端口上过滤?)来使这种技术更加通用

于 2011-11-03T20:05:54.330 回答
0

如果设备无法访问,即使您的后备推送消息系统也无法工作。C2DM 不保证它会传递您的消息,但未传递的事件非常罕见。任何其他服务也是如此。您可能拥有的最佳解决方法是轮询您的服务器以检查您是否有任何尚未传递的新消息。我假设您的应用程序非常重要,因此不要错过 500 条或可能是 1000 条中的一条消息。在这种情况下,您可以实现推送和拉取的混合。

于 2011-10-29T16:45:32.280 回答
0

我在 C2Dm 方面做了一些工作,我创建了自己的推送 3rd 方服务器。我已经实现了一些基于 C2DM http 响应代码的逻辑,以了解是否发送了推送消息。这是我使用的一些代码:

int responseCode = conn.getResponseCode();

    if (responseCode == HttpServletResponse.SC_UNAUTHORIZED || responseCode == HttpServletResponse.SC_FORBIDDEN) {

        LOGGER.warn("Unauthorized - need token");

        return false;
    }

在这里,我几乎可以肯定推送消息是从 c2dm 服务器发送的,因为我在响应中有一个 id:

if (responseParts[0].equals("id")) {
        LOGGER.info("Successfully sent data message to device: " + responseLine);

        return true;
    }

我已经使用其他方法从 Google 获取其他结果代码,如果您愿意,我可以发布它们。希望对您有所帮助。

于 2011-10-31T16:34:10.207 回答
0

我认为没有任何方法可以在 ADVANCE 中确定推送尝试是否有可能起作用,但我可以想到一种相当简单的方法来验证收据(但不排队等待将来通过 C2DM 交付)——只需完成消息环形。

请记住,C2DM 的主要好处是它允许在手机处于睡眠状态并且名义上处于离线状态时发出通知。一旦您的应用程序收到通知,就没有什么可以阻止您此时唤醒电话、启动网络并发送确认信息。我认为您甚至不必请求“保持手机唤醒”权限,因为我相信仅注册 C2DM 通知并接收通知的行为就足以唤醒手机并允许应用程序继续正常运行(至少,足够长的时间来启动网络并发送确认)。

当你在做这件事时,你应该跟踪在你认为它们是一个失败的原因之后很久才发生的确认。如果您看到多个,您可能需要更改重新发送策略。

唯一可能失败的现实边缘情况是,如果您的用户在启用语音/短信的同时向后弯腰禁用数据(我很确定 C2DM 使用电话轮询传入时发送的 4 个字节的响应数据报最初为 RIM 预留的电话和短信,后来重新用于 Apple 和 Google)。

于 2011-10-31T17:12:01.870 回答
0

尝试关闭所有网络连接并重新连接。如果您将获得一个注册 ID,那么您就可以接收消息。

于 2011-11-03T14:43:25.300 回答
0

与用于传递触发器的长期运行的 C2DM 连接相关的内容:

  • 在 WLAN 上,它每 15 分钟发送一次心跳。
  • 在移动网络上,超时时间为 28 分钟。

28 分钟可能会太长,具体取决于您的移动运营商使用的硬件、车库中的 2g/3g 中继器等。

您可以通过打开 Google Talk 服务监控应用程序来获取有关连接的大量信息:http: //www.honeytechblog.com/monitor-google-talk-service-android/

拨号:## 8255 ##

还有一个按钮可以立即发送心跳并重置超时。

如果您想确保(在客户端)可以在给定时间收到 c2dm 消息,最好的办法是重新发送心跳。这可以通过编程方式完成——不过只能在有根设备上完成。我可能会在某个时候向市场发布一个可以做到这一点的 apk。

于 2012-09-12T13:24:02.350 回答