Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Cloud Messaging register AUTHENTICATION_FAILED

I want to try Google Cloud Messaging (GCM) service, and I am faced with a problem at the beginning.

I get an error AUTHENTICATION_FAILED while trying to register a device to GCM. I searched and all I found were variations of the incorrect password. My password is correct and I am using just one account.

There are two ways to implement GCM client on Android:

  1. GCM library with additional jar, now deprecated.
  2. Google Play Services API

I started with the second of course and got this issue.

I thought the problem is in my phone, but then decided to try the first way, which worked! However, it is deprecated and requires an additional jar, which doesn't seem like the right way.

In an attempt to understand the reasons for the error, I decompiled Google Play Services jar and compared it with GCM library.

It turns out they both have a similar method, something like:

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);
}

The difference in one row:

In GCM library it is com.google.android.gsf, where gsf is Google Services Framework (I guess), and it works!

In Google Play Services API jar it is com.google.android.gms, And it does not work (AUTHENTICATION_FAILED error).

Then in GCM library I replaced "gsf" to "gms" and run. And I got the same AUTHENTICATION_FAILED error! If I enter another package, then it is not working.

What do I need to do to make it work? Should I set up something in the phone? Or is it a bug in Google Play Services? Have someone encountered such a problem?

Thanks in advance!

like image 206
user2862139 Avatar asked Oct 09 '13 10:10

user2862139


1 Answers

I ran into the same problem, and it doesn't seem like google is in any hurry to fix it.

I didn't want to add the deprecated client helper gcm.jar to my app, so I coded a minimal solution that works on my Android 2.3.6 Nexus One phone that fails registration as in the question above

            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();
            }

The AUTHENTICATION_FAILED triggers the IOException in the code above

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;
    }
}

I added the above code to my app. They are simplified methods from the Client Helper gcm.jar (so you don't need to add the jar to your app)

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);
}

This code is in the intent service, and has a few lines to store the ID received from GCM. As you can see only about 20 extra lines of code compared to a basic implementation, and no additional dependencies! You only need to update your AndroidManifest.xml to make sure you can receive the REGISTRATION intent.

    <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>

I hope this helps until google gets their act together!

like image 98
spirographer Avatar answered Oct 24 '22 06:10

spirographer