I am getting the error \"SERVICE_NOT_AVAILABLE\" on my GoogleCloudMessaging.register() call on a Android 2.2 device.
I am writing an app that uses GoogleCloudMessagi
So, there is another thing to watch out for that tripped me up.
I had it working fine in emulator + with test application, but then I had issues deploying it on actual devices.
Was consistently getting the SERVICE_NOT_AVAILABLE error, and resorted to an approach similar to the answer above:
IntentFilter filter = new IntentFilter("com.google.android.c2dm.intent.REGISTRATION");
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Got into onReceive for manual GCM retrieval. "
+ intent.getExtras());
String regId = intent.getStringExtra("registration_id");
if (regId != null && !regId.isEmpty()) {
theResult.add(regId);
} else {
theResult.add("");
}
lastDitchEffortComplete = true;
}
};
cont.registerReceiver(receiver, filter);
This sort-of worked. But it was taking an oddly long amount of time to receive this information, and in a wait-loop I had, it would ONLY ever retrieve it AFTER I'd given up and let things proceed.
This got me thinking that there might be another cause to the SERVICE_NOT_AVAILABLE msg.
This is the code I had to do the fetching/registration with GCM:
new AsyncTask<Void, Void, Void>() {
final long timeSleep = 1000;
@Override
protected Void doInBackground(Void... params) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(cont);
String registrationId = "";
int count = 0;
while (count < 1) {
try {
count++;
Log.i(TAG, "Starting GCM Registration Attempt #" + count);
registrationId = gcm.register(CLOUDAPPID);
rph.storeRegistrationId(registrationId);
return null;
} catch (IOException e) {
e.printStackTrace();
}
Log.w(TAG, "Registration failed. Retrying in " + timeSleep + " ms.");
try {
Thread.sleep(timeSleep);
} catch (InterruptedException e) {
}
}
return null;
}
}.execute().get();
The main thing to look for here is the last line.
.execute.get();
A "clever/cheating" way to block on asynchronous off-thread results.
It turns out, that IS what is causing the problem. As soon as I just had:
.execute();
Let it pass through, and made the algorithm/code work with reporting back and not needing the registration id right away, then it was fine. I didn't even need the manual broadcast receiver, it just worked like it should.
For the time being, until either Google fix this bug or someone provides a better solution I am using a hybrid solution where it will use Google Player Services for the first few times (with exponential backoff) but switch to GCMRegistrar afterwards.
I experienced the same problem. GCM works fine on my Tablet running Android 4.04, but always received a SERVICE_NOT_AVAILABLE on my smartphone running Android 2.3.
I found following workaround not using (so far as I know) any deprecated classes. Add the action "com.google.android.c2dm.intent.REGISTRATION" to the GCMBroadcastReceiver in your manifest. This will enable to receive the registration_id at your GCMBroadcastReceiver.
<receiver
android:name="YOUR_PACKAGE_NAME.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="YOUR_PACKAGE_NAME" />
</intent-filter>
</receiver>
After that your GCMBroadcastReceiver is able to receive the registration_id:
public void onReceive(Context context, Intent intent) {
String regId = intent.getExtras().getString("registration_id");
if(regId != null && !regId.equals("")) {
/* Do what ever you want with the regId eg. send it to your server */
}
}
Although I still get a SERVICE_NOT_AVAILABLE error, I can handle the registration_id in my GCMBroadcastReceiver and I am able to send messages to my smartphone. Quite weird, but it works for me.
This error also occurred to me, but it did because I was trying to register in the GCM through a firewall of my company. And in the documentation I found:
"Note: If your organization has a firewall that restricts the traffic to or from the Internet, you need to configure it to allow connectivity with GCM in order for your Android devices to receive messages. The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow your firewall to accept outgoing connections to all IP addresses contained in the IP blocks listed in Google's ASN of 15169."
Once I opened the ports or tried from another network, it worked.
If the marked answer is not working for you (as it was for me), check the person in front of your device, maybe shake it and then enable the internet connection. Worked for me ;-)
Without internet, you receive the same Exception and I spent the afternoon chasing complex problems with the service....
I had the same problem but it was happening on all devices. It took me forever to find my problem but I thought I would post it in case it matches someone else's case. Here is a simplified version of my problem:
public class Login extends Activity {
Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
context = getApplicationContext();
//Get GCM registration id
new GcmRegistrationAsyncTask().execute(context);
Set<Tuple> timeline = new HashSet<Tuple>();
try {
//Get data from Redis database
timeline = new RedisAsyncTask().execute(context).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
When I add the second AsyncTask with a return using get(), I would get the GCM 'SERVICE_NOT_AVAILABLE' every time even though I could still retrieve the registration id from the GcmBroadcastReceiver onReceive(). However, when I run:
public class Login extends Activity {
Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
context = getApplicationContext();
new GcmRegistrationAsyncTask().execute(context);
new RedisAsyncTask().execute(context);
}
}
the GCM would receive the registration id without issue.