android - 在 Firebase Auth 中合并 facebook 和 google 用户
问题描述
在我的应用程序中,我最近添加了通过邮件、Facebook 和谷歌登录。
我可以通过每种方法登录,但不能使用同一个帐户。
我可以切换提供商:Facebook-> Google on Firebase 但不能更改 Google -> Facebook 我必须补充一点,我不会为不同的提供商做单独的帐户,以合并它们。有人可以帮我解决这个链接凭证吗?
package com.company.altasnotas.fragments.login_and_register;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
import com.company.altasnotas.MainActivity;
import com.company.altasnotas.R;
import com.company.altasnotas.fragments.home.HomeFragment;
import com.company.altasnotas.viewmodels.LoginFragmentViewModel;
import java.util.Map;
import java.util.Objects;
import com.facebook.AccessToken;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.login.LoginResult;
import com.facebook.login.widget.LoginButton;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInApi;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.internal.GoogleApiManager;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.GoogleAuthProvider;
import com.google.firebase.ktx.Firebase;
import static android.content.ContentValues.TAG;
public class LoginFragment extends Fragment {
private static final int RC_SIGN_IN = 120;
GoogleSignInClient mGoogleSignInClient;
CallbackManager callbackManager;
LoginFragmentViewModel model;
LoginButton facebookLoginButton;
FirebaseAuth mAuth;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_login, container, false);
mAuth = FirebaseAuth.getInstance();
model = new ViewModelProvider(requireActivity()).get(LoginFragmentViewModel.class);
EditText email_editext = view.findViewById(R.id.login_email_edittext);
EditText password_editext = view.findViewById(R.id.login_password_edittext);
view.findViewById(R.id.login_w_mail_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
model.login((MainActivity) requireActivity(),email_editext.getText().toString().toLowerCase().trim(),password_editext.getText().toString().toLowerCase().trim());
}
});
view.findViewById(R.id.jump_to_register_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requireActivity().getSupportFragmentManager().beginTransaction().addToBackStack(null).replace(R.id.main_fragment_container, new RegisterFragment()).commit();
}
});
// Initialize Facebook Login button
FacebookSdk.sdkInitialize(getContext());
callbackManager = CallbackManager.Factory.create();
facebookLoginButton = view.findViewById(R.id.fb_new_login_button);
facebookLoginButton.setReadPermissions("email", "public_profile");
facebookLoginButton.setFragment(this);
// Callback registration
facebookLoginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
AccessToken token = loginResult.getAccessToken();
Log.d("Dziala ", "Token: "+ token.getUserId());
handleFacebookAccessToken(loginResult.getAccessToken());
}
@Override
public void onCancel() {
Log.d("Facebook","Login Canceled");
}
@Override
public void onError(FacebookException exception) {
Log.d("Facebook","Login error: "+exception.toString());
}
});
ImageButton fb_btn = view.findViewById(R.id.login_fb_btn);
fb_btn.setOnClickListener(v -> facebookLoginButton.performClick());
//Google Auth
ImageButton google_btn = view.findViewById(R.id.login_google_btn);
// Configure Google Sign In
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(getContext(), gso);
google_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signIn();
}
});
return view;
}
@Override
public void onStart() {
super.onStart();
FirebaseUser user = mAuth.getCurrentUser();
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.updateUI(user);
}
private void handleFacebookAccessToken(AccessToken token) {
MainActivity mainActivity = (MainActivity) getActivity();
mAuth = FirebaseAuth.getInstance();
String TAG="Facebook";
Log.d(TAG, "handleFacebookAccessToken:" + token);
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
if(mAuth.getCurrentUser()!=null){
mAuth.getCurrentUser().linkWithCredential(credential).addOnCompleteListener(mainActivity, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
Toast.makeText(mainActivity, "Link Facebook success",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(mainActivity, "Link Facebook fail",Toast.LENGTH_SHORT).show();
}
}
});
}else {
mAuth.signInWithCredential(credential).addOnCompleteListener(mainActivity, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
FirebaseUser user = mAuth.getCurrentUser();
mainActivity.updateUI(user);
int count = mainActivity.getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < count; i++) {
mainActivity.getSupportFragmentManager().popBackStack();
}
Toast.makeText(mainActivity, "Sign Facebook success", Toast.LENGTH_SHORT).show();
BottomNavigationView bottomNavigationView = mainActivity.findViewById(R.id.main_nav_bottom);
bottomNavigationView.setSelectedItemId(R.id.nav_home_item);
mainActivity.getSupportFragmentManager().beginTransaction().replace(R.id.main_fragment_container, new HomeFragment()).commit();
} else {
Toast.makeText(mainActivity, "Sign Facebook fail", Toast.LENGTH_SHORT).show();
mainActivity.updateUI(null);
}
}
});
}
}
private void signIn() {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
callbackManager.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
if(task.isSuccessful()){
try {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = task.getResult(ApiException.class);
Log.d(TAG, "firebaseAuthWithGoogle:" + account.getId());
firebaseAuthWithGoogle(account.getIdToken());
} catch (ApiException e) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e);
}
}else{
Log.w(TAG, task.getException().toString());
}
}
}
private void firebaseAuthWithGoogle(String idToken) {
MainActivity mainActivity = (MainActivity) getActivity();
AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null);
if(mAuth.getCurrentUser()!=null){
mAuth.getCurrentUser().linkWithCredential(credential).addOnCompleteListener(mainActivity, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
Toast.makeText(mainActivity,"Link google succeded!",Toast.LENGTH_SHORT).show();
FirebaseUser user = mAuth.getCurrentUser();
mainActivity.updateUI(user);
BottomNavigationView bottomNavigationView = mainActivity.findViewById(R.id.main_nav_bottom);
bottomNavigationView.setSelectedItemId(R.id.nav_home_item);
int count = mainActivity.getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < count; i++) {
mainActivity.getSupportFragmentManager().popBackStack();
}
mainActivity.getSupportFragmentManager().beginTransaction().replace(R.id.main_fragment_container, new HomeFragment()).commit();
}else{
Toast.makeText(mainActivity,"Link google failed!",Toast.LENGTH_SHORT).show();
}
}
});
}else {
mAuth.signInWithCredential(credential).addOnCompleteListener(mainActivity, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
Toast.makeText(mainActivity.getApplicationContext(), "Sign Google success", Toast.LENGTH_SHORT).show();
FirebaseUser user = mAuth.getCurrentUser();
mainActivity.updateUI(user);
BottomNavigationView bottomNavigationView = mainActivity.findViewById(R.id.main_nav_bottom);
//We shouldnt could go back so if i were transfering to another activity
// I should add finish(); at the end of code after starting another activity
bottomNavigationView.setSelectedItemId(R.id.nav_home_item);
int count = mainActivity.getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < count; i++) {
mainActivity.getSupportFragmentManager().popBackStack();
}
mainActivity.getSupportFragmentManager().beginTransaction().replace(R.id.main_fragment_container, new HomeFragment()).commit();
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.getException());
Toast.makeText(mainActivity.getApplicationContext(), "Sign Google failed", Toast.LENGTH_SHORT).show();
mainActivity.updateUI(null);
}
}
});
}
}
}
另外我想补充一点,我尝试了一种使用 GoogleApiClient 的方法,但它告诉我,无论我选择什么 ID,它总是被程序使用
解决方案
对于任何有同样问题的人:
这里的问题是 Google 切换了不应该发生的提供商。这是一个长期存在的错误,他们没有修复它。他们称之为功能哈哈。
这就是为什么我花了两天时间来解决这个问题。谢谢谷歌
推荐阅读
- vue.js - 向 npm / webpack 添加文件系统包依赖项
- c++ - pybind11实现一个cpp中间件概念(基础篇)
- gorilla - 我应该如何用 gorilla/mux 解决这个导入问题?
- javascript - 如何等到 iFrame 在 Google Chrome 中使用 AppleScript/JavaScript 加载?
- c# - 将 2 个排序的整数列表合并为一个,按升序排列。我的方法太乱了
- cucumber - 在 CucumberJs 和 Cypress 中是否可以使上下文独立并允许具有相同描述的步骤?
- javascript - 无法使用 Laravel (blade.php) 加载具有较长链接的样式
- visual-studio-2019 - 具有 ID #### 的进程未在 Visual Studio 2019 中运行
- .net-core - Bot Framework Composer开发的多语言bot中如何触发对应的QnAMaker
- spring-boot - 将数据从 Spring Boot 控制器传递到 Boostrap 模态