问题
Background
Hello, I'm new with Firebase for Android and I'm trying to implement the Facebook and Google auth/login for the first time. I followed these two tutorials for the corresponding authentication:
- http:// firebase.google.com/docs/auth/android/google-signin
- http:// firebase.google.com/docs/auth/android/facebook-login
Separately, the FacebookSignInActivity
and GoogleSignInActivity
are working as they should.
Problem
The problem is that I'm trying to use the Google and Facebook auth in the same activity, but it won't work. Like so:
What I did
I tried to keep the FacebookSignInActivity
separate from the GoogleSignInActivity
by letting them extend a MainActivity
and set the layout in there.
But I think I'm supposed to merge the two into one. So I tried that but I'm getting a weird nullpointer exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.firebase.auth.FirebaseAuth.addAuthStateListener(com.google.firebase.auth.FirebaseAuth$AuthStateListener)' on a null object reference
I don't know why the object is null in the onCreate
because I've copied the same code from the other two activities which are working:
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");
}
// [START_EXCLUDE]
updateUI(user);
// [END_EXCLUDE]
}
};
I'm not even sure if I'm even supposed to merge the two into one activity. I've also checked these links:
- https://firebase.google.com/docs/auth/android/account-linking
- How to Link Multiple Auth Providers to an Firebase Account?
But it looks like that is something else from what I'm trying to do. If someone could help point me in the right direction, it would be gladly appreciated.
回答1:
You can try this code:
public class LoginActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener {
private static final String TAG = "SignInActivity";
private static final int RC_SIGN_IN = 9001;
private GoogleApiClient mGoogleApiClient;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private CallbackManager mCallbackManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Facebook Login
FacebookSdk.sdkInitialize(getApplicationContext());
mCallbackManager = CallbackManager.Factory.create();
LoginButton mFacebookSignInButton = (LoginButton) findViewById(R.id.facebook_button);
mFacebookSignInButton.setReadPermissions("email", "public_profile", "user_birthday", "user_friends");
mFacebookSignInButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
Log.d(TAG, "facebook:onSuccess:" + loginResult);
firebaseAuthWithFacebook(loginResult.getAccessToken());
}
@Override
public void onCancel() {
Log.d(TAG, "facebook:onCancel");
}
@Override
public void onError(FacebookException error) {
Log.d(TAG, "facebook:onError", error);
}
});
// Google Sign-In
// Assign fields
Button mGoogleSignInButton = (Button) findViewById(R.id.google_button);
// Set click listeners
mGoogleSignInButton.setOnClickListener(this);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
// 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 onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
@Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
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(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
} else {
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
}
}
});
}
private void firebaseAuthWithFacebook(AccessToken token) {
Log.d(TAG, "handleFacebookAccessToken:" + token);
final 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(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
} else {
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
}
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.google_button:
signIn();
break;
default:
return;
}
}
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mCallbackManager.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = result.getSignInAccount();
firebaseAuthWithGoogle(account);
} else {
// Google Sign In failed
Log.e(TAG, "Google Sign In failed.");
}
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
Log.d(TAG, "onConnectionFailed:" + connectionResult);
Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
}
}
Please let me know if you have any questions.
回答2:
Maybe anyone still looking for solution:
In Activity( yourLoginActivity.class)
*Create a constant int to represents the requestCode for ActivityForResult
// You can change to any Value just be unique
private static final int RC_SIGN_IN = 1001;
–> declare GoogleApiClient, FirebaseAuth, AuthStateListener and the CallbackManager
private static final String TAG = "LoginActivity";
private static final int RC_SIGN_IN = 1001;
private GoogleApiClient mGoogleApiClient;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private CallbackManager mCallbackManager;
–> Initialize the variables declared above:
mCallbackManager = CallbackManager.Factory.create(); 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");
}
} };
–> Get reference to SingInButton and LoginButton:
LoginButton facebookLoginButton = findViewById(R.id.login_facebook_button);
SignInButton mGoogleSignInButton = findViewById(R.id.sign_in_button);
–> Handle the SingInButton and LoginButton:
facebookLoginButton.setReadPermissions("email", "public_profile", "user_birthday");
facebookLoginButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
firebaseAuthWithFacebook(loginResult.getAccessToken());
}
@Override
public void onCancel() {
Toast.makeText(LoginActivity.this, "Succes", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(FacebookException error) {
Toast.makeText(LoginActivity.this, "Succes", Toast.LENGTH_SHORT).show();
}
});
mGoogleSignInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
signIn();
}
});
–> Manage the GoogleSingInOptions and GoogleApiClient
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
–> Handle the Facebook Login
private void authWithFacebook(AccessToken token) {
Log.d(TAG, "handleFacebookAccessToken:" + token);
final AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
if (mAuth.getCurrentUser() != null) {
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
Toast.makeText(LoginActivity.this, "Logged IN", Toast.LENGTH_LONG).show();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
Log.e(TAG, "onFailure: " + e.getMessage());
mAuth.signInWithCredential(credential).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
Toast.makeText(LoginActivity.this, "Logged IN", Toast.LENGTH_LONG).show();
}
});
}
});
} else {
mAuth.signInWithCredential(credential);
}
}
–> Handle the Google Login:
pprivate void authWithGoogle(final GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGooogle:" + acct.getId());
final AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
if (mAuth.getCurrentUser() != null) {
mAuth.getCurrentUser().linkWithCredential(credential).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
Toast.makeText(LoginActivity.this, "Logged IN", Toast.LENGTH_LONG).show();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
Log.e(TAG, "onFailure: " + e.getMessage());
mAuth.signInWithCredential(credential).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
Toast.makeText(LoginActivity.this, "Logged IN", Toast.LENGTH_LONG).show();
}
});
}
});
}else{
mAuth.signInWithCredential(credential);
}
}
–> Override the onConnectionFailed():
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
Log.d(TAG, "onConnectionFailed:" + connectionResult);
Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
}
–> Singing in and calling the onActivityForResult()
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
–> Implement GoogleApiClient.OnConnectionFailedListener
LoginActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener{
....
}
Be sure you have ENABLED FACEBOOK SDK Login FROM FIREBASE CONSOLE AND SET UP CORRECTLY!
回答3:
Somebody wanting to do this in Kotlin in a Fragment
class LoginFragment(): Fragment() , GoogleApiClient.OnConnectionFailedListener {
override fun onConnectionFailed(p0: ConnectionResult) {
Toast.makeText(activity, "Google Play Services error.", Toast.LENGTH_SHORT).show();
}
private val TAG = "SignInActivity"
private val RC_SIGN_IN = 9001
private var mGoogleApiClient: GoogleApiClient? = null
private var mAuth: FirebaseAuth? = null
private var mAuthListener: FirebaseAuth.AuthStateListener? = null
private var mCallbackManager: CallbackManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.likes_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
FacebookSdk.sdkInitialize(activity);
mCallbackManager = CallbackManager.Factory.create()
google_container.setOnClickListener {
signIn()
}
// Facebook Button (LoginButton) from xml
login_button.setReadPermissions("email", "public_profile")
login_button.fragment = this
login_button.run {
registerCallback(mCallbackManager, object: FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult?) {
Log.e(TAG, "Succesfull Facebook Sign In")
firebaseAuthWithFacebook(result?.accessToken!!)
}
override fun onCancel() {
Log.e(TAG, "Cancelled Facebook Sign In")
}
override fun onError(error: FacebookException?) {
Log.e(TAG, "Facebook sign in error : " + error.toString())
}
})
}
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()
mGoogleApiClient = GoogleApiClient.Builder(activity!!.applicationContext)
.enableAutoManage(this.activity!! /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build()
mAuth = FirebaseAuth.getInstance()
mAuthListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
val user = firebaseAuth.currentUser
if (user != null) {
// User is signed in
Log.e(TAG, "onAuthStateChanged:signed_in:" + user.uid)
} else {
// User is signed out
Log.e(TAG, "onAuthStateChanged:signed_out")
}
}
}
fun signIn() {
val signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient)
startActivityForResult(signInIntent, RC_SIGN_IN);
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
mCallbackManager!!.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
if (result.isSuccess) {
// Google Sign In was successful, authenticate with Firebase
val account = result.signInAccount
firebaseAuthWithGoogle(account!!)
} else {
// Google Sign In failed
Log.e(TAG, "Google Sign In failed.");
}
}
}
private fun firebaseAuthWithGoogle(token : GoogleSignInAccount) {
Log.e(TAG, "handleGoogleAccessToken:" + token);
val credential = GoogleAuthProvider.getCredential(token.idToken,null)
mAuth!!.signInWithCredential(credential)
.addOnCompleteListener(activity as MainActivity, object : OnCompleteListener<AuthResult> {
override fun onComplete(task: Task<AuthResult>) {
Log.e(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
if(!task.isSuccessful){
Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(activity, "Success", Toast.LENGTH_SHORT).show();
}
}
})
}
private fun firebaseAuthWithFacebook(token : AccessToken) {
Log.e(TAG, "handleFacebookAccessToken:" + token);
val credential = FacebookAuthProvider.getCredential(token.token)
mAuth!!.signInWithCredential(credential)
.addOnCompleteListener(activity as MainActivity, object : OnCompleteListener<AuthResult> {
override fun onComplete(task: Task<AuthResult>) {
Log.e(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());
if(!task.isSuccessful){
Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(activity, "Success", Toast.LENGTH_SHORT).show();
}
}
})
}
}
来源:https://stackoverflow.com/questions/39778301/combining-facebook-and-google-auth-for-firebase-android