Вход в Facebook с Android с помощью Firebase BaaS

Я следую этому руководству Firebase по интеграции Facebook в мое приложение. Все выглядит хорошо, за исключением того факта, что у меня есть это исключение:

com.google.firebase.auth.FirebaseAuthUserCollisionException: уже существует учетная запись с тем же адресом электронной почты, но с другими учетными данными. Войдите в систему, используя провайдера, связанного с этим адресом электронной почты.

Достаточно справедливо, учитывая, что это именно то, что я пытаюсь сделать. Сначала я создал код для интеграции Gmail в свое приложение и вошел в систему, используя свою учетную запись электронной почты. Затем я попытался войти в систему через Facebook и получил сообщение об ошибке.

Пытаясь решить эту проблему, я нашел здесь это

FirebaseAuthUserCollisionException выбрасывается, если уже существует учетная запись с адресом электронной почты, подтвержденным учетными данными. Разрешите этот случай, вызвав fetchProvidersForEmail (String), а затем попросив пользователя войти в систему, используя один из них.

Наконец, проблема в том, что я не уверен, что правильно использую метод fetchProvidersForEmail, потому что моя задача не выполняется (проверьте последний блок кода).

Кто-нибудь может оказать поддержку? Спасибо,

* Приведенный ниже код в настоящее время поддерживает вход в Gmail и Facebook. Метод, о котором я говорю, последний, handleFacebookAccessToken.

public class SignInActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, View.OnClickListener {

/**
 * References
 * https://developers.google.com/identity/sign-in/android/sign-in#configure_google_sign-in_and_the_googleapiclient_object
 */

// Here a simple Sign-In button is used to initiate authentication. In this step you will
// implement the logic to Sign-In with Google then use that Google account to authenticate with
// Firebase.

private static final String TAG = "SignInActivity";
private static final int RC_SIGN_IN = 9001;
private GoogleApiClient mGoogleApiClient;
private FirebaseAuth mAuth;

private FirebaseAuth.AuthStateListener mAuthListener;

LoginButton facebookLogin;
CallbackManager cM;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    FacebookSdk.sdkInitialize(this.getApplicationContext());
    setContentView(R.layout.activity_sign_in);

    cM = CallbackManager.Factory.create();
    facebookLogin = (LoginButton) findViewById(R.id.sign_in_button_facebook);
    if (facebookLogin != null) {
        facebookLogin.setReadPermissions("public_profile", "email", "user_friends");
        facebookLogin.registerCallback(cM, new FacebookCallback<LoginResult>() {
            @Override
            public void onSuccess(LoginResult loginResult) {
                Log.d(TAG, "facebook:onSuccess:" + loginResult);
                handleFacebookAccessToken(loginResult.getAccessToken());
            }

            @Override
            public void onCancel() {
                Log.d(TAG, "facebook:onCancel");
                // ...
            }

            @Override
            public void onError(FacebookException error) {
                Log.d(TAG, "facebook:onError", error);
                // ...
            }
        });
    }

    // Configure Google Sign-In to request the user data required by the app. For example, to
    // configure Google Sign-In to request users' ID and basic profile information, create a
    // GoogleSignInOptions object with the DEFAULT_SIGN_IN parameter (ID and basic profile are
    // included in DEFAULT_SIGN_IN). To request users' email addresses as well, create the
    // GoogleSignInOptions object with the requestEmail option.
    GoogleSignInOptions mGoogleSignInOptions = new GoogleSignInOptions
            .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.default_web_client_id))
            .requestEmail()
            .build();

    // Create a GoogleApiClient object with access to the Google Sign-In API and the options
    // specified. Note: To use enableAutoManage, your activity must extend FragmentActivity or
    // AppCompatActivity (a subclass of FragmentActivity), both of which are part of the Android
    // Support Library. You can use GoogleApiClient in a Fragment; however, the fragment's
    // parent activity must be a FragmentActivity. If you can't extend FragmentActivity, you
    // must manually manage the GoogleApiClient connection lifecycle.
    mGoogleApiClient = new GoogleApiClient
            .Builder(this)
            .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
            .addApi(Auth.GOOGLE_SIGN_IN_API, mGoogleSignInOptions)
            .build();

    // Configure the sign in button.
    SignInButton mSignInButton = (SignInButton) findViewById(R.id.sign_in_button);
    if (mSignInButton != null) {
        mSignInButton.setSize(SignInButton.SIZE_STANDARD);
        mSignInButton.setOnClickListener(this);
    }

    // Initialize FirebaseAuth
    mAuth = FirebaseAuth.getInstance();

    mAuthListener = new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            FirebaseUser user = firebaseAuth.getCurrentUser();
            if (user != null) {
                // User is signed in
                Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
            } else {
                // User is signed out
                Log.d(TAG, "onAuthStateChanged:signed_out");
            }
            // ...
        }
    };
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.sign_in_button:
            signIn();
            break;
    }
}

@Override
public void onResume() {
    super.onResume();
    mAuth.addAuthStateListener(mAuthListener);
}

@Override
public void onPause() {
    super.onPause();
    if (mAuthListener != null) {
        mAuth.removeAuthStateListener(mAuthListener);
    }
}

// Handle sign-in button taps by creating a sign-in intent with the getSignInIntent method, and
// starting the intent with startActivityForResult. Starting the intent prompts the user to
// select a Google account to sign in with. If you requested scopes beyond profile, email, and
// openid, the user is also prompted to grant access to the requested resources.
private void signIn() {
    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
    startActivityForResult(signInIntent, RC_SIGN_IN);
}

// An unresolvable error has occurred and Google APIs (including Sign-In) will not be available.
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    Log.d(TAG, "onConnectionFailed:" + connectionResult);
    Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
}

// Handle the result of the Google Sign In in the activity's onActivityResult method, which
// retrieve the sign-in result with getSignInResultFromIntent.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    cM.onActivityResult(requestCode, resultCode, data);

    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
    if (requestCode == RC_SIGN_IN) {
        GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
        handleSignInResult(result);
    }
}

// After you retrieve the sign-in result, you can check if sign-in succeeded with the isSuccess
// method. If sign-in succeeded, you can call the getSignInAccount method to get a
// GoogleSignInAccount object that contains information about the signed-in user, such as the
// user's name. You can also get the user's email address with getEmail, the user's Google ID
// (for client-side use) with getId, and an ID token for the user with with getIdToken. If you
// need to pass the currently signed-in user to a backend server, send the ID token to your
// backend server and validate the token on the server.
public void handleSignInResult(GoogleSignInResult result) {
    if (result.isSuccess()) {
        GoogleSignInAccount account = result.getSignInAccount();

        // Google Sign In was successful, authenticate with Firebase.
        firebaseAuthWithGoogle(account);

    } else {
        // Google Sign In failed
        // TODO: 26/06/2016 Handle no internet connection
        Log.e(TAG, "Google Sign In failed.");
    }
}

// Add the required firebaseAuthWithGoogle method to authenticate with the signed in Google
// account.
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
    Log.d(TAG, "firebaseAuthWithGooogle:" + acct.getId());

    AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
    mAuth
            .signInWithCredential(credential)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

                    // If sign in fails, display a message to the user. If sign in succeeds
                    // the auth state listener will be notified and logic to handle the
                    // signed in user can be handled in the listener.

                    if (!task.isSuccessful()) {
                        Log.w(TAG, "signInWithCredential", task.getException());
                        Toast.makeText(SignInActivity.this, "Authentication failed.", Toast.LENGTH_SHORT).show();

                    } else {
                        startActivity(new Intent(SignInActivity.this, MainActivity.class));
                        finish();
                    }
                }
            });
}

private void handleFacebookAccessToken(AccessToken token) {
    Log.d(TAG, "handleFacebookAccessToken:" + token);

    // This commented block below is what is on the tutorial, but gives the exceptio explained.
    /*
    AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
    mAuth.signInWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
        @Override
        public void onComplete(@NonNull Task<AuthResult> task) {
            Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

            // If sign in fails, display a message to the user. If sign in succeeds
            // the auth state listener will be notified and logic to handle the
            // signed in user can be handled in the listener.
            if (!task.isSuccessful()) {
                Log.w(TAG, "signInWithCredential", task.getException());
                Toast.makeText(SignInActivity.this, "Authentication failed.", Toast.LENGTH_SHORT).show();
            }

            // ...
        }
    });
    */

    mAuth.fetchProvidersForEmail("[email protected]").addOnCompleteListener(this, new OnCompleteListener<ProviderQueryResult>() {
        @Override
        public void onComplete(@NonNull Task<ProviderQueryResult> task) {
            Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

            // If sign in fails, display a message to the user. If sign in succeeds
            // the auth state listener will be notified and logic to handle the
            // signed in user can be handled in the listener.
            if (!task.isSuccessful()) {
                Log.w(TAG, "signInWithCredential", task.getException());
                Toast.makeText(SignInActivity.this, "Authentication failed.", Toast.LENGTH_SHORT).show();
            } else {
                startActivity(new Intent(SignInActivity.this, MainActivity.class));
                finish();
            }
        }
    });
}

}


person Danilo Setton    schedule 02.07.2016    source источник


Ответы (1)


AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
        mFirebaseAuth.signInWithCredential(credential)
                .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

                        // If sign in fails, display a message to the user. If sign in succeeds
                        // the auth state listener will be notified and logic to handle the
                        // signed in user can be handled in the listener.

                        if (!task.isSuccessful()) {
                            Log.w(TAG, "signInWithCredential", task.getException());
                            Toast.makeText(SignInActivity.this, "Authentication failed.",
                                    Toast.LENGTH_SHORT).show();

                            //((FirebaseAuthException)task.getException()).getErrorCode();

                        }

                    }

                }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        if(e instanceof  FirebaseAuthUserCollisionException)
                        {
                            //Handle Auth Error Here
                            Toast.makeText(SignInActivity.this, e.toString(),
                                    Toast.LENGTH_SHORT).show();

                        }else if(e instanceof FirebaseAuthInvalidUserException)
                        {
                            //Handle Auth Error Here
                            Toast.makeText(SignInActivity.this, e.toString(),
                                    Toast.LENGTH_SHORT).show();

                        }
                    }
        });

Примечание: если мы можем получить код ошибки для этих исключений Auth, то это лучше, чем использовать проверку типа (instanceOf).

person Raghavendra B    schedule 03.07.2016