GCM SERVICE_NOT_AVAILABLE on Android 2.2

百般思念 提交于 2019-11-26 06:42:23

问题


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 GoogleCloudMessaging using the new Google Play Services. I implemented it using the guidelines provided on the Android website and my source contains a lot of error checking and handling code such as making sure the Google Play Services is installed, or updated. The GCM registration code also implements a exponential backoff as google as suggested one to implement to handle the SERVICE_NOT_AVAILABLE error.

I have tested my application on a wide array of devices including ICS, JB, Honey Comb and even 2.3.x devices. The GCM registration works and I am able to send messages to it via GCM. However on a 2.2 device I am continuously getting a SERVICE_NOT_AVAILABLE error on the GoogleCloudMessaging.register() call even with the exponential backoff in place.

The device that GCM is failing on is a Samsung SGH-I896 to be exact and the phone has 2 google accounts on it. I\'ve read that this error might be caused by a misconfigured time, but the time is set to be automatic. The phone is not moded and is running samsung stock ROM.

I have also tried rebooting the device as well as reinstalling Google Play Services without luck. Any help on this issue will be greatly appreciated.

EDIT: I tried to implement GCM using the old gcm.jar and GCMRegistrar and it ended up working on the device. However I hardly consider this a good solution to the problem as Google has stopped supporting this method afaik.

EDIT2: See the accepted answer.


回答1:


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.




回答2:


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.




回答3:


SERVICE_NOT_AVAILABLE may be caused by an old or missing GooglePlayServices. Use GooglePlayServicesUtil to check the version and if wrong redirect to market so user can manually install it - this will fix the SERVICE_NOT_AVAILABLE and also get all improvements and bug fixes ( and new bugs :-).

If you can't do this - there is no point in using register(), the method expects the matching play service to retrieve the result. It does generate the same broadcast, for backward compatibility. Using the REGISTER intent directly or the deprecated library will continue to work - I would suggest using the intent, GCMRegistrar is tied to the old implementation in GoogleServicesFramework (it has a call to intent.setPackage(GSF_PACKAGE)), so it can't benefit from any fixes.

Having the latest version of GCM - by using GooglePlayServicesUtil to deal with devices that didn't get the automatic install - can help not only for registration.




回答4:


After reading the post from marnanish, I tried the code below, and I have successfully got my Activity to receive a registration. Just add this:

<activity
    android:name=".MyActivity"
    ... />
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="your.package.here" />
    </intent-filter>
</activity>

in your AndroidManifest.xml




回答5:


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.




回答6:


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.




回答7:


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




回答8:


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.




回答9:


I know this is an old post, but I just had the same problem, while everything was setup correctly. The SERVICE_NOT_AVAILABLE error, kept popping up. After going to settings => apps => Google Play-servises, and clear the cache and remove the data, it worked.



来源:https://stackoverflow.com/questions/17618982/gcm-service-not-available-on-android-2-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!