Grzegorz Adam Hankiewicz
Grzegorz Adam Hankiewicz

Reputation: 7661

How can I avoid Firebase entering an infinite loop due to bad Play services version?

I have a basic Firebase login situation with the following code:

    Log.d(TAG, "Entering black hole");
    try {
        FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password)
                .addOnCompleteListener(task -> {
                    Log.d(TAG, "Exiting black hole");
                    …
                }).addOnFailureListener(new OnFailureListener() {
            @Override public void onFailure(@NonNull Exception e) {
                Log.d(TAG, "Exiting black hole");
                …
            }
        });
    } catch (Exception e) {
        Log.e(TAG, "try/catch " + e);
    }

However, running this on an emulator with Android 7 generates the following logs:

D/FirebaseController: Entering black hole
W/GooglePlayServicesUtil: Google Play services out of date.  Requires 11925000 but found 11743470
D/EGL_emulation: eglMakeCurrent: 0x89b5a620: ver 2 0 (tinfo 0x89b5c680)
D/EGL_emulation: eglMakeCurrent: 0x89b5a620: ver 2 0 (tinfo 0x89b5c680)
W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
W/BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzal@415e769
W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
W/GooglePlayServicesUtil: Google Play services out of date.  Requires 12451000 but found 11743470
W/DynamiteModule: Local module descriptor class for com.google.firebase.auth not found.
W/GooglePlayServicesUtil: Google Play services out of date.  Requires 12451000 but found 11743470

Meaning, the FirebaseAuth code enters and never exists, leaving my app in an endless loop. I understand from the logs that the google play services is outdated, but how can I check this before running the .signInWithEmailAndPassword() method? The isGooglePlayServicesAvailable() method doesn't allow passing a version number, doesn't seem to return any either.

Upvotes: 0

Views: 535

Answers (1)

Jinson Paul
Jinson Paul

Reputation: 481

int v = getPackageManager().getPackageInfo(GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, 0 ).versionCode; 

this will return play service version , then simply check it program before .signInWithEmailAndPassword()

The problem is caused by a specific condition when you have 2 issues with Google Play Services (GPS). Because GPS is also disabled Google Play Store (GPT), will not run on the device.

If your Google Play Services is out of date, then calling showErrorDialogFragment using an error code of ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED, (error code 2), which works fine.

But if your GPS is both disabled AND out-of-date, then there is an issue with the way googleApiAvailability api works.If you call isGooglePlayServicesAvailable() it will return the first error it finds, but it's not necessarily the error you want to resolve first. The problem is knowing that you have another error you need to address first. isGooglePlayServicesAvailable() does not help in this regard.

In my case play services is both disabled, AND out of date. So, the approach is to first call showErrorDialogFragment and you'll get a response error code for SERVICE_VERSION_UPDATE_REQUIRED.

Android will attempt to resolve it by sending a pendingIntent to launch Google Play Store (GPT) to update GPS, but this will fail, as GPT depends on an ENABLED version of GPS. Because you're calling showErrorDialogFragment it will call onActivityResult after it fails to launch GPT.

The next step is codig the onActivityResult. I needed to test for isGooglePlayServicesAvailable() again. If you still get the same error code (SERVICE_VERSION_UPDATE_REQUIRED), then you need to call showErrorDialogFragment again in onActivityResult, but this time pass it a different error code, ConnectionResult.SERVICE_DISABLED (error code 3). This will take the user to the app manager to ENABLE google play services first. Then when returning to the app, you need to test for isGooglePlayServicesAvailable and it should then detect google services is still out of date. If you successfully update the app, onActivityResult should allow you to determine that isGooglePlayServicesAvailable is succcessful and you can continue. Note that you will may need to add a flag that so that you know to test again for google play services compatibility rather than continue executing a startup process.

(So, really what googleApiAvailability should do is return the disabled error first (ie ConnectionResult.SERVICE_DISABLED aka error code 3), so you can resolve that first before attempting to update GPS.)

Upvotes: 1

Related Questions