13

我想尝试 Google Cloud Messaging (GCM) 服务,一开始我遇到了一个问题。

AUTHENTICATION_FAILED尝试将设备注册到 GCM 时出现错误。我进行了搜索,发现的只是错误密码的变体。我的密码是正确的,我只使用一个帐户。

在 Android 上实现 GCM 客户端有两种方式:

  1. 带有附加 jar 的 GCM 库,现已弃用。
  2. 谷歌播放服务 API

我当然从第二个开始并遇到了这个问题。

我以为问题出在我的手机上,但后来决定尝试第一种方法,它奏效了!但是,它已被弃用并且需要一个额外的 jar,这似乎不是正确的方法。

为了了解错误的原因,我反编译了 Google Play Services jar 并将其与 GCM 库进行了比较。

事实证明,它们都有类似的方法,例如:

void register(Context context, String senderIds) {
    Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
    intent.setPackage("com.google.android.gms"); // this one row are different
    setPackageNameExtra(context, intent);
    intent.putExtra("sender", senderIds);
    context.startService(intent);
}

一行的区别:

在 GCM 库中com.google.android.gsfgsfGoogle 服务框架在哪里(我猜),它可以工作!

在 Google Play Services API jar 中,它是com.google.android.gms,并且它不起作用(AUTHENTICATION_FAILED 错误)。

然后在 GCM 库中,我将“gsf”替换为“gms”并运行。我得到了同样的 AUTHENTICATION_FAILED 错误!如果我输入另一个包,则它不起作用。

我需要做什么才能使其工作?我应该在手机中设置一些东西吗?还是 Google Play 服务中的错误?有人遇到过这样的问题吗?

提前致谢!

4

3 回答 3

2

我遇到了同样的问题,谷歌似乎并不急于解决它。

我不想将已弃用的客户端帮助程序 gcm.jar 添加到我的应用程序中,因此我编写了一个适用于我的 Android 2.3.6 Nexus One 手机的最小解决方案,该手机注册失败,如上述问题

            try {
                gcm = GoogleCloudMessaging.getInstance(context);
                regID = gcm.register(SENDER_ID);
                storeRegistrationId(regID);
                msg = "Device registered, registration ID=" + regID;

                sendRegistrationIdToBackend();
            } catch (IOException ex) {
                msg = "Exception registering for GCM :" + ex.getMessage();
                // If there is an error, don't just keep trying to register.
                oldSchoolRegister();
            }

AUTHENTICATION_FAILED 触发了上面代码中的 IOException

private void oldSchoolRegister() {
    Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
    intent.setPackage("com.google.android.gsf");
    setRegCallbackIntent(context, intent);
    intent.putExtra("sender", SENDER_ID);
    context.startService(intent);
}

private static synchronized void setRegCallbackIntent(Context context, Intent intent) {
    regCallback = PendingIntent.getBroadcast(context, 0, new Intent(), 0);
    intent.putExtra("app", regCallback);
}

public static synchronized void cancelRegCallbackIntent() {
    if (regCallback != null) {
        regCallback.cancel();
        regCallback = null;
    }
}

我将上面的代码添加到我的应用程序中。它们是 Client Helper gcm.jar 中的简化方法(因此您无需将 jar 添加到您的应用程序中)

protected void onHandleIntent(Intent intent) {
    Bundle extras = intent.getExtras();

    if (extras != null && !extras.isEmpty()) {  // has effect of unparcelling Bundle
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        String messageType = gcm.getMessageType(intent);

        if (messageType != null) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                showMessage(extras.getString("message")); // call your code
                Logger.d(TAG, "Received message: " + message.alert + ": " + message.url);
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                Logger.e(TAG, "Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
                Logger.e(TAG, "Deleted messages on server: " + extras.toString());
            }
        } else {
            String regID = extras.getString("registration_id");
            if (regID != null && !regID.isEmpty()) {
                doRegistration(regID); // send to your server etc.
                GCMSetup.storeRegistrationId(regID);
                GCMSetup.cancelRegCallbackIntent();
            }
        }
    }
    // Release the wake lock provided by the WakefulBroadcastReceiver.
    GCMBroadcastReceiver.completeWakefulIntent(intent);
}

此代码位于意图服务中,并且有几行代码用于存储从 GCM 接收到的 ID。如您所见,与基本实现相比,只增加了大约 20 行代码,并且没有额外的依赖项!您只需要更新您的 AndroidManifest.xml 以确保您可以收到 REGISTRATION 意图。

    <receiver android:name="com.camiolog.android.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="com.camiolog.android"/>
        </intent-filter>
    </receiver>

我希望这会有所帮助,直到谷歌齐心协力!

于 2014-01-16T01:03:12.120 回答
1

这似乎是一个错误。以下是 Android 开发人员在android-gcm Google Group中对它的评价:

一些背景知识: Froyo 和 Gingerbread 注册是在 GoogleServicesFramework 中实现的,使用 Google 帐户进行注册。对于帐户状态不佳的人来说,这导致了很多身份验证错误。

从 ICS 开始,GCM 不依赖或不使用 Google 帐户 - 您可以在添加帐户之前使用它,也可以不使用任何帐户。

“播放服务”更新正在所有设备上实施新方案 - 但似乎有少数设备存在问题,我们正在调查 - 但数字远低于旧方案。

如果您想使用 GSF 中的代码,用于 Froyo 和 Gingerbread - 您需要使用之前的库,该库明确设置包名称。 GCM 中的新库正在使用新的注册码。

与谷歌的实际连接遵循相同的路径——我们正在逐渐(并且缓慢地)将设备转移到新的代码在播放服务中。

到目前为止,我有 2 个错误报告,我们有一些嫌疑人。我们知道,如果设备超过 9 个月未连接,它将处于此状态,并且需要恢复出厂设置。

我们有一些报告说恢复出厂设置没有解决问题 - 但我没有错误报告或信息来确认或追踪这一点。我发现恢复出厂设置无济于事的唯一情况是手机在初始签入时向服务器发送了错误信息——我们为此添加了额外的检查。

显然,恢复出厂设置可能会解决问题,但他们仍在调查中。

于 2013-10-09T20:30:08.347 回答
1

所以看起来避免这个问题的解决方案是回退到旧的不推荐使用的 GCM 客户端库,以防 AUTHENTICATION_FAILED 错误发生在 FROYO 和 GINGERBREAD 上。

这是我如何升级新的 Gcm 客户端以回退以使用旧客户端的简单代码片段:

@Override
protected void onPostExecute(Integer resultCode) {

    if(resultCode == EXCEPTION_THROWED) {

        //Android 2.2 gmc bug http://stackoverflow.com/questions/19269607/google-cloud-messaging-register-authentication-failed

        //fall back to old deprecated GCM client library

        GCMRegistrar.checkDevice(StartActivity.this);
        GCMRegistrar.checkManifest(StartActivity.this);
        final String registrationId = GCMRegistrar.getRegistrationId(StartActivity.this);
        if (registrationId.equals("")) {
            GCMRegistrar.register(StartActivity.this, SENDER_ID);
        }

        //Toast.makeText(context, "Orders and menus won't be sync with other devices since GoogleCloudMessaging is not working correctly on this device. Please notify the developer.", Toast.LENGTH_LONG).show();

    }

}

您可以在此处找到已弃用的旧 GCM 客户端助手:http: //developer.android.com/google/gcm/helper.html

您可以在计算机上的以下路径中找到 GCM 客户端的代码:ANDROID_SDK_ROOT/extras/google/gcm-client(假设您已经使用 Android SDK 管理器下载了此额外代码)。

我将旧的 gcm 客户端放在一个名为 com.google.android.gcm.deprecated 的新包中,以试图记住自己不要将它用于其他东西。

于 2013-10-29T12:51:28.147 回答