0

我正在编写一个使用 GCM 消息的游戏。当一名玩家进入回合移动到服务器时,服务器将向他们的对手发送 GCM 消息,让该客户端知道有额外的回合数据可用。这应该很简单。我尽可能地遵循示例 GCM 客户端代码。

我有两台设备进行测试: 带有 Ice Cream Sandwich 版本 4.0.4 的 Motorola Xoom 带有 Gingerbread 版本 2.3.5 的 Motorola X2

两台设备都有一个 Goggle 帐户设置(实际上是同一个帐户)。我可以从 Play Store 下载应用程序。当我收到新的 Google Talk 消息或 Gmail 消息时,我都会收到通知消息。他们都在我面前使用相同的 Wi-Fi 网络,所以我可以确认没有防火墙问题。我在两者上都安装了相同的游戏应用程序。我已经能够在两台设备上获得 GCM 注册 ID 号。除了 Android 操作系统版本之外,这两款设备几乎完全相同。但是,Xoom 将接收 GCM 消息而 X2 不会,或者至少这些消息没有被广播到我在 X2 上的应用程序。

这是我的清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="myGame.app.main" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="myGame.app.main.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="myGame.app.main.permission.C2D_MESSAGE" />

<application android:icon="@drawable/icon" android:name="myGameApp" android:label="@string/app_name" android:description="@string/description" android:theme="@style/GlobalTheme" android:killAfterRestore="false" android:allowTaskReparenting="false" android:persistent="false">

    ... Other Activities ...

    <receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="myGame.app.main" />
        </intent-filter>
    </receiver>
    <service android:name=".GCMIntentService" android:enabled="true" />
    </application>
</manifest>

这是我的 GCMIntentService 的代码:

package myGame.app.main;

import com.google.android.gcm.GCMBaseIntentService;
import com.google.android.gcm.GCMRegistrar;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import java.util.logging.Logger;

public class GCMIntentService extends GCMBaseIntentService
{
    private static PowerManager.WakeLock sWakeLock;
    private static final Object LOCK = GCMIntentService.class;
    private static final String GCM_SENDER_ID = "... My Sender ID...";
    private static final String GCM_INTENT_FILTER = "myGame.app.main.GCM_MESSAGE";
    private static final String MESSAGE_TYPE = "Type";
    private static final String MESSAGE_CONTENT = "Body";
    private static Logger log = Logger.getLogger(GCMIntentService.class.getName());

    public GCMIntentService()
    {
        super(GCM_SENDER_ID);
    }

    static void runIntentInService(Context context,Intent intent)
    {
        synchronized(LOCK)
        {
            if (sWakeLock == null)
            {
                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
                sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"sc_wakelock");
            }
        }
        sWakeLock.acquire();
        intent.setClassName(context,GCMIntentService.class.getName());
        context.startService(intent);
    }

    @Override protected void onRegistered(Context context,String registrationId)
    {
        log.warning("From GCMIntentService: Device successfully registered as "+registrationId);
        ... Other Code ...
    }

    @Override protected void onUnregistered(Context context,String registrationId)
    {
        log.warning("From GCMIntentService: Device successfully unregistered");
        ... Other Code ...
    }

    @Override protected void onMessage(Context context,Intent messageIntent)
    {
        log.warning("From GCMIntentService: Game update notice received");
        ... Other Code ...
    }

    @Override protected void onDeletedMessages(Context context,int total)
    {
        log.warning("From GCMIntentService: Server deleted "+Integer.toString(total)+" pending messages");
    }

    @Override public void onError(Context context,String errorId)
    {
        log.warning("From GCMIntentService: Error "+errorId);
        ... Other Code ...
    }

    @Override protected boolean onRecoverableError(Context context,String errorId)
    {
        log.warning("From GCMIntentService: Recoverable error "+errorId);
        return(super.onRecoverableError(context,errorId));
    }
}

我什至用自己的 getGCMIntentServiceClassName() 函数创建了自己的 GCMBroadcastReceiver 类,并在那里放置了一条日志消息。在我尝试过的每个变体中,当应用程序在 Xoom 上运行时,我都会看到正确的 LogCat 消息,但我在 X2 上根本看不到任何 GCM 消息的证据。就好像 GCMBroadcastReceiver 和/或 GCMIntentService 根本不起作用,但我没有看到任何类型的错误消息。

谁能帮我这个?

4

1 回答 1

0

我为 GCM 消息编译了示例代码。我所做的唯一更改是使用我在游戏应用程序中使用的相同 API 密钥和发件人 ID。此应用程序可在两台设备上运行,因此我可以再次确认没有网络问题,并且我可以确认 X2 实际上可以接收 GCM 消息。

坏消息是 X2 仍然没有收到我的游戏的 GCM 消息。经过更多研究后,我发现当服务器尝试向 X2 发送 GCM 消息(仅适用于我的游戏应用程序)时,服务器会收到 ERROR_NOT_REGISTERED 结果。发送到 Xoom 时不会出现此类错误。我已确认服务器已成功接收注册 ID 号。我知道这很难说,但注册 ID 不会在传输过程中被破坏。

我尝试了一些关于如何从 GCM 服务器取消注册设备的不同已发布建议,但似乎没有一个有效。我总是再次收到相同的注册 ID。所以我完全卸载了我的游戏,然后在 X2 上重新安装了它。这迫使它获得一个新的注册 ID 号,从而解决了这个问题。我的游戏现在在两台设备上都能正常运行。我必须假设在我调试时,注册 ID 在游戏和 GCM 服务器之间以某种方式混淆了。

我只能希望这不会成为一个常规问题,因为除了卸载应用程序之外似乎没有成功的修复。

于 2012-07-26T21:09:32.963 回答