26

I want to implement an gcm client into an existing android app. So, by following this tutorial I wrote following code:

public class RegisterForGCMAsyncTask extends AbstractSecureOperationTask {

...

@Override
protected Boolean doInBackground(String... params) {
    String token = authenticate();
    getRegId();
    if (TextUtils.isEmpty(registrationId)) {
        return false;
    }
    //
    try {
        URL url = convertToURLEscapingIllegalCharacters(String.format(Constants.REGISTER_URL,
                registrationId, userId, token));
        URLConnection connection = url.openConnection();
        InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
        JSONParser parser = new JSONParser();
        JSONObject rootObj = (JSONObject) parser.parse(streamReader);
        String status = rootObj.get("status").toString();
        if (status.equals("OK")) {
            return true;
        }
    } catch (ParseException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

private void getRegId() {
    try {
        if (gcm == null) {
            gcm = GoogleCloudMessaging.getInstance(context);
        }
        registrationId = gcm.register(PROJECT_ID);
    } catch (IOException e) {
        Log.e(LOG_TAG, e.getMessage(), e);
    }
}
}

AndroidMainfest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="de.xxxxxxxx.xxxxxxxx"
      android:versionCode="20140617"
      android:versionName="2.0.0">

<uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="19"/>

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>

<permission
        android:name="de.xxxxxxxx.xxxxxxxx.permission.MAPS_RECEIVE"
        android:protectionLevel="signature"/>
<uses-permission android:name="de.xxxxxxxx.xxxxxxxx.permission.MAPS_RECEIVE"/>

<permission
        android:name="de.xxxxxxxx.xxxxxxxx.permission.C2D_MESSAGE"
        android:protectionLevel="signature"/>
<uses-permission android:name="de.xxxxxxxx.xxxxxxxx.permission.C2D_MESSAGE"/>


<!-- Maps API needs OpenGL ES 2.0. -->
<uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">

    <activity
            android:name="de.retterapps.Handyalarm.views.activities.MainActivity"
            android:configChanges="orientation|screenLayout|screenSize|layoutDirection"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

    <receiver
            android:name=".helper.gcm.GcmBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
            <category android:name="de.xxxxxxxx.xxxxxxxx"/>
        </intent-filter>
    </receiver>
    <service android:name=".helper.gcm.GcmMessageHandler"/>

    <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>
    <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="xxxxxxxx"/>
</application>

Yesterday everything worked fine and I could retrieve the registration id. But now, there's always an IOException saying SERVICE_NOT_AVAILABLE.

I tested it on my Samsung Galaxy S5 and in the Genymotion Emulator (Android 4.1.2), but I am getting always the same results. Has anyone an idea how to solve the problem?

Edit

Here's the full stacktrace:

java.io.IOException: SERVICE_NOT_AVAILABLE
    at com.google.android.gms.gcm.GoogleCloudMessaging.register(Unknown Source)
    at de.retterapps.Handyalarm.helper.tasks.RegisterForGCMAsyncTask.getRegId(RegisterForGCMAsyncTask.java:72)
    at de.retterapps.Handyalarm.helper.tasks.RegisterForGCMAsyncTask.doInBackground(RegisterForGCMAsyncTask.java:43)
    at de.retterapps.Handyalarm.helper.tasks.RegisterForGCMAsyncTask.doInBackground(RegisterForGCMAsyncTask.java:24)
    at android.os.AsyncTask$2.call(AsyncTask.java:287)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
    at java.lang.Thread.run(Thread.java:856)
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
Robin
  • 709
  • 2
  • 8
  • 20

8 Answers8

36

Check the time of your device. Google cannot register your device with a wrong time

Nickolai Astashonok
  • 2,878
  • 3
  • 20
  • 23
  • 2
    The time seems to be correct. The curious thing ist, that it worked yesterday - but now, it is not working ;( Either on real device, nor on the genymotion emulator. – Robin Jun 17 '14 at 17:11
  • Do you mean on the test device or another one? On the test device, yes. – Robin Jun 17 '14 at 17:15
  • Yes, google play servis is up-to-date on both test devices (real device and emulator). I use google play service 4.4.52. – Robin Jun 17 '14 at 17:23
  • Hm, have you tried fully remove application, re-install it and test again? – Nickolai Astashonok Jun 17 '14 at 17:24
  • Yes, I already tried this. Well, the following discussions says "According to the Google GCM docs, SERVICE_NOT_AVAILABLE indicates the Google servers are busy at the moment and you should try again later". See more here: https://groups.google.com/forum/#!topic/android-gcm/Skhe3jG5DIg Can this be the problem? – Robin Jun 17 '14 at 17:28
  • Probably, but I think there is an issue on client-side, but I can't figure out what issue.. ( – Nickolai Astashonok Jun 17 '14 at 17:33
  • Okay, but I didn't changed anything since yesterday. The only thing I changed, is to reduce the minimum api level from 17 to 15 (but i tried it also with api level 17). – Robin Jun 17 '14 at 17:35
  • I've tried this demo - and it works: http://tausiq.wordpress.com/tag/gcm-client/ But I don't understand, why my solution doesn't work, it is nearly the same code ;-( – Robin Jun 19 '14 at 15:10
  • Yes of course. I've tried it with my sender id given by my client and created a new one - both of them are working well in the demo project, but not on my application ;( – Robin Jun 19 '14 at 19:20
  • Without internet you'll also get this exception. Given everything else is working. – Hussain Mansoor Jul 26 '16 at 09:23
15

When I encountered this issue what worked for me was to open the Google Play application.

It seems that it must be started at least once after the device restarts before any GCM registration attempt.

Tom Susel
  • 3,397
  • 1
  • 24
  • 25
6

This is a weird one. I solved it by moving the GCM code to the end of my onCreate() method.

My guess is the app Context was not fully created by the time I tried to register for CGM. It needs a valid Context.

  • i solved problem by adding 10 seconds delay(for complete app loading) and then make GCM request. – Enakhi Jan 21 '16 at 23:54
3

SERVICE_NOT_AVAILABLE might also mean, that the device is offline when executing a task:

com.google.android.gms.tasks.RuntimeExecutionException: java.io.IOException: java.util.concurrent.ExecutionException: java.io.IOException: SERVICE_NOT_AVAILABLE

at com.google.android.gms.tasks.zzw.getResult(com.google.android.gms:play-services-tasks@@17.2.1:3)

So this can be solved by not requesting eg. the FCM token, while the device is offline, for example:

@Override
public void onNetworkAvailable() {
    FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {
        Log.d(LOG_TAG, "FCM token: " + task.getResult());
    });
}
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
0

Yesterday I solved the problem on my own. I followed the demo-application and changed the AsyncTask in the registerInBackground()-Method to a plain java thread. Here's the code:

private void registerInBackground() {
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    Toast.makeText(context, getString(R.string.txt_gcm_registered), Toast.LENGTH_LONG).show();
                    break;
                case 1:
                    Toast.makeText(context, getString(R.string.error_register_gcm), Toast.LENGTH_LONG).show();
                    break;
            }
            super.handleMessage(msg);
        }

    };
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                if (gcm == null) {
                    gcm = GoogleCloudMessaging.getInstance(context);
                }
                regId = gcm.register(Constants.SENDER_ID);

                if (sendRegistrationIdToBackend(regId)) {
                    handler.sendEmptyMessage(0);
                } else {
                    handler.sendEmptyMessage(1);
                }

                storeRegistrationId(context, regId);
            } catch (IOException ex) {
                handler.sendEmptyMessage(1);
                Log.e(LOG_TAG, ex.getMessage(), ex);
            }
        }
    };
    new Thread(runnable).start();
}

Now, it is working, but I don't know why. Can anybody explain the reason? Thanks for your help!

Robin
  • 709
  • 2
  • 8
  • 20
0

If you are running your app in emulator, you must install Google Play Service.

I recently switched to GenyMotion Emulator from Google native emulator and encountered this error. Later I realized GenyMotion image does not come with Google Play Service. After installation, problem solved.

0

also make sure you have internet on your phone!

Ali80
  • 6,333
  • 2
  • 43
  • 33
0

NativeFirebaseError: [messaging/unknown] java.io.IOException: java.util.concurrent.ExecutionException: java.io.IOException: SERVICE_NOT_AVAILABLE

I know it sounds weird but this error comes up when there's internet connectivity issue on the testing device.

Aditya Singh
  • 135
  • 6