Reputation: 444
I am trying to create an application where a user can do registration with a username and password, and then enters a phone number, receives an OTP code, and completes the registration form. But there is a problem. If you do this, Firebase creates two different users. How can I combine (join) them so that it appears as a single account?
Activity with entering a phone number:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_signup2)
init()
var phoneNumber: String
mBackBtn.setOnClickListener {
}
mNextBtn.setOnClickListener {
phoneNumber = "+" + mCountyCode!!.selectedCountryCode + mPhoneNumberEd.text.toString()
Toast.makeText(this, phoneNumber, Toast.LENGTH_LONG).show()
sendVerificationCode(phoneNumber)
}
}
private fun sendVerificationCode(phone: String) {
var phoneShadow = phone
Log.d("MyTag", phoneShadow)
val options = PhoneAuthOptions.newBuilder()
.setPhoneNumber(phoneShadow)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(callbacks)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private fun init() {
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
Log.d(TAG, "onVerificationCompleted:$credential")
val intent = Intent(applicationContext, Signup3::class.java)
startActivity(intent)
}
override fun onVerificationFailed(e: FirebaseException) {
Log.d(TAG, "onVerificationFailed", e)
Toast.makeText(applicationContext, "Failed", Toast.LENGTH_LONG).show()
}
override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) {
Log.d("MyTag","onCodeSent:$verificationId")
var storedVerificationId: String = verificationId
var resendToken: PhoneAuthProvider.ForceResendingToken = token
val intent = Intent(applicationContext, Signup3::class.java)
intent.putExtra("storedVerificationId", storedVerificationId)
startActivity(intent)
}
}
mNextBtn = findViewById(R.id.signup2_next_btn)
mBackBtn = findViewById(R.id.signup2_back_btn)
mPhoneNumberEd = findViewById(R.id.signup2_phone_number_ed)
mCountyCode = findViewById(R.id.signup2_county_code)
mAuth = FirebaseAuth.getInstance()
}
Activity with entering the code that the phone receives:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_signup3)
init()
var storedVerificationId = intent.getStringExtra("storedVerificationId").toString()
mConfirmBtn.setOnClickListener {
var code = mPinView.text.toString().trim()
if (code.isEmpty()) {
Toast.makeText(this, "Ты ввёл?", Toast.LENGTH_LONG).show()
} else {
var credential : PhoneAuthCredential = PhoneAuthProvider.getCredential(storedVerificationId!!, code)
signInWithPhoneAuthCredential(credential)
}
}
}
private fun init() {
mConfirmBtn = findViewById(R.id.signup3_confirm_btn)
mPinView = findViewById(R.id.signup3_pin_view)
mAuth = FirebaseAuth.getInstance()
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) {
if (it.isSuccessful) {
var intent = Intent(this, PhoneConfirmedSignup::class.java)
startActivity(intent)
finish()
} else {
if (it.exception is FirebaseAuthInvalidCredentialsException) {
Toast.makeText(this, "Invalid OTP", Toast.LENGTH_SHORT).show()
}
}
}
}
Upvotes: 2
Views: 1300
Reputation: 337
What worked for me was updatePhoneNumber()
, instead of using,
linkWithCredential()
val auth = FirebaseAuth.getInstance() auth.currentUser!!.linkWithCredential(credential).addOnCompleteListener(this){ }
you can use
updatePhoneNumber()
val auth = FirebaseAuth.getInstance() auth.currentUser?.updatePhoneNumber(credential).addOnCompleteListener(this){ }
As it is phone number that you want to merge with Email and password.
Upvotes: 0
Reputation: 138824
If you do this, the Firebase creates two different users.
That's the expected behavior since you are using two separate types of authentication.
How can I combine them so that it appears as a single account?
If you want to have only one, then you should link both of them together into a single account. According to the official documentation regarding account linking, first, you need to get the existing credentials:
val authCredential = EmailAuthProvider.getCredential(email, password)
For Java users:
AuthCredential authCredential = EmailAuthProvider.getCredential(email, password);
And then simply use the FirebaseUser#linkWithCredential(AuthCredential credential) method like in the following lines of code:
val auth = FirebaseAuth.getInstance()
auth.currentUser!!.linkWithCredential(credential).addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
Log.d(TAG, "linkWithCredential:success")
val user = task.result!!.user
updateUI(user)
} else {
Log.w(TAG, "linkWithCredential:failure", task.exception)
Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show()
updateUI(null)
}
}
And for Java users:
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.getCurrentUser().linkWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "linkWithCredential:success");
FirebaseUser user = task.getResult().getUser();
updateUI(user);
} else {
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.", Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});
Upvotes: 3