108

I am trying to use Google Play Service in my Android app. As Google document says, we need to check if the Google API is available before using it. I have searched some way to check it. Here is what I got:

private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
    if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
        GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                PLAY_SERVICES_RESOLUTION_REQUEST).show();
    } else {
        Log.i(TAG, "This device is not supported.");
        finish();
    }
    return false;
}
return true;
}

But when I go to Google Api GooglePlayServicesUtil page, https://developers.google.com/android/reference/com/google/android/gms/common/GooglePlayServicesUtil

I find all functions are deprecated. For example, the method

GooglePlayServicesUtil.isGooglePlayServicesAvailable (deprecated)

And Google recommends to use:

GoogleApiAvailability.isGooglePlayServicesAvailable.

However, when I try to use GoogleApiAvailability.isGooglePlayServicesAvailable, I get the error message:

enter image description here

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
James
  • 5,119
  • 5
  • 25
  • 27
  • where do I find GoogleApiAvailability? I can't find it. – mcmillab Apr 26 '16 at 05:51
  • @mcmillab +1. I upgraded from 8.1.0 to 8.4.0 and `GooglePlayServicesUtil` is gone (which seem like a bad practice for a "minor" update) but I'm not seeing `GoogleApiAvailability` to use as a replacement. – spaaarky21 Jun 02 '16 at 15:30
  • When updating to Firebase checkout this: http://www.etivy.com/googleapiavailability-missed-with-firebase-messaging-9-4-0/ – Gelldur Nov 15 '16 at 16:18

6 Answers6

211

I have found the solution. In the GoogleApiAvailability, all methods are public method, while in GooglePlayServicesUtil all methods are static public function.

So to use GoogleApiAvailability, the right way is:

private boolean checkPlayServices() {
    GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
    int result = googleAPI.isGooglePlayServicesAvailable(this);
    if(result != ConnectionResult.SUCCESS) {
        if(googleAPI.isUserResolvableError(result)) {
            googleAPI.getErrorDialog(this, result,
                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
        }

        return false;
    }

    return true;
}
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
James
  • 5,119
  • 5
  • 25
  • 27
65

The class GooglePlayServicesUtil shouldn't be used anymore!

Here is how the class GoogleApiAvailability can be used instead - when for example GCM (or any other Google service) is needed:

public static final int REQUEST_GOOGLE_PLAY_SERVICES = 1972;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        startRegistrationService();
    }
}

private void startRegistrationService() {
    GoogleApiAvailability api = GoogleApiAvailability.getInstance();
    int code = api.isGooglePlayServicesAvailable(this);
    if (code == ConnectionResult.SUCCESS) {
        onActivityResult(REQUEST_GOOGLE_PLAY_SERVICES, Activity.RESULT_OK, null);
    } else if (api.isUserResolvableError(code) &&
        api.showErrorDialogFragment(this, code, REQUEST_GOOGLE_PLAY_SERVICES)) {
        // wait for onActivityResult call (see below)
    } else {
        Toast.makeText(this, api.getErrorString(code), Toast.LENGTH_LONG).show();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch(requestCode) {
        case REQUEST_GOOGLE_PLAY_SERVICES:
            if (resultCode == Activity.RESULT_OK) {
                Intent i = new Intent(this, RegistrationService.class); 
                startService(i); // OK, init GCM
            }
            break;

        default:
            super.onActivityResult(requestCode, resultCode, data);
    }
}

UPDATE:

REQUEST_GOOGLE_PLAY_SERVICES is an integer constant with arbitrary name and value, which can be referred to in the onActivityResult() method.

Also, calling this.onActivityResult() in the above code is okay (you also call super.onActivityResult() in the other place).

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
  • 2
    Can you point to the source that claims that "The class GooglePlayServicesUtil shouldn't be used anymore!". The Google Play Services API is so confusing. – Lachezar Nov 16 '15 at 00:06
  • 8
    All methods in [GooglePlayServicesUtil](https://developers.google.com/android/reference/com/google/android/gms/common/GooglePlayServicesUtil) marked as deprecated plus recommendation at the top of the javadoc to take the `GOOGLE_PLAY_SERVICES_PACKAGE` constant from [GoogleApiAvailability](https://developers.google.com/android/reference/com/google/android/gms/common/GoogleApiAvailability) class is Google's way to tell you: don't use the `GooglePlayServicesUtil` class anymore. – Alexander Farber Nov 16 '15 at 09:50
  • 3
    What if the device has an older version of Google Play services in which the `GoogleApiAvailability` class doesn't exist? If we reference the class statically, even inside a conditional expression, won't it crash the app? – Kevin Krumwiede Nov 20 '15 at 21:33
  • 6
    @Kevin Krumwiede, `GoogleApiAvailability` is part of the client library. So it's code is compiled into the app => Don't worry about that. – WindRider Jan 25 '16 at 10:59
  • 9
    You should not call onActivityResult(). It is meant to be called from outside, when another activity returns a result. – Yar Feb 09 '16 at 21:02
  • I do not have a link to Google doc stating that. That is obvious. You can call it just my opinion. – Yar Feb 09 '16 at 21:07
  • 1
    this has one error: `onActivityResult()` should not be called directly. – Chisko Aug 21 '16 at 19:54
  • @AlexanderFarber it's a system method intended to be used with Intents and startActivityForResult(), mr Senior – Chisko Aug 30 '16 at 03:17
  • Nothing stops you for writing a more adequate method instead of calling a wrong one either, but there you go. – Chisko Aug 31 '16 at 21:56
11

You will have to use GoogleApiAvailability instead:

GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance(); 
int errorCode = googleApiAvailability.isGooglePlayServicesAvailable(this);

this represents the context.

Satan Pandeya
  • 3,747
  • 4
  • 27
  • 53
Gaurav
  • 227
  • 3
  • 4
9

Check the device to make sure it has the Google Play Services APK. If it doesn't, display a dialog that allows users to download the APK from the Google Play Store or enable it in the device's system settings.

public static boolean checkPlayServices(Activity activity) {
    final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
    int resultCode = apiAvailability.isGooglePlayServicesAvailable(activity);
    if (resultCode != ConnectionResult.SUCCESS) {
        if (apiAvailability.isUserResolvableError(resultCode)) {
            apiAvailability.getErrorDialog(activity, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
                    .show();
        } else {
            Logger.logE(TAG, "This device is not supported.");
        }
        return false;
    }
    return true;
}
Anoop M Maddasseri
  • 10,213
  • 3
  • 52
  • 73
1

Just putting a .getInstance() in between the two methods would do the game.

Arpit Anand
  • 347
  • 2
  • 17
0

I have added this as fun in BaseActivity class to be used in all places

    fun checkGooglePlayServices(okAction : ()-> Unit , errorAction: (msg:String, isResolved:Boolean)-> Unit){
    val apiAvailability = GoogleApiAvailability.getInstance()
    val resultCode = apiAvailability.isGooglePlayServicesAvailable(this)
    if (resultCode != ConnectionResult.SUCCESS) {
        if (apiAvailability.isUserResolvableError(resultCode)) {
            apiAvailability.getErrorDialog(
                this,
                resultCode,
                PLAY_SERVICES_RESOLUTION_REQUEST
            ).show()
             // dialoe when click on ok should let user go to install/update play serices


            errorAction("dialog is shown" , true)

        } else {
          "checkGooglePlayServices  This device is not supported.".log(mTag)
            errorAction("This device is not supported",false)
        }
    }else{
        okAction()
    }
}

companion object {
    const val PLAY_SERVICES_RESOLUTION_REQUEST = 1425
}

use it like this

    (activity as? BaseActivity)?.checkGooglePlayServices({
        // ok so start map
        initializeMap()
    },
        { msg, isResolved ->
            if (!isResolved)
                context?.show(msg)

        }
    )

Or you can customize it as you want.

Mahmoud Mabrok
  • 1,362
  • 16
  • 24