Вход в 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("i_put_here_my_email@gmail.com").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();
}
}
});
}
}
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)