问题
I want to use Firebase phone number authentication. My code is this:
LoginActivity.kt
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.tasks.Task
import com.google.firebase.FirebaseException
import com.google.firebase.auth.AuthResult
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.PhoneAuthCredential
import com.google.firebase.auth.PhoneAuthProvider
import kotlinx.android.synthetic.main.login_activity.*
import java.util.concurrent.TimeUnit
class LoginActivity : AppCompatActivity() {
lateinit var mCallbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
lateinit var mAuth: FirebaseAuth
var verificationId = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.login_activity)
mAuth = FirebaseAuth.getInstance()
veriBtn.setOnClickListener {
if (phnNoTxt.text.toString()!=""){
progress.visibility = View.VISIBLE
verify ()}
else toast("Enter verification number")
}
authBtn.setOnClickListener {
if ((verifiTxt.text.toString()!="")&&(phnNoTxt.text.toString()!="")){
progress.visibility = View.VISIBLE
authenticate()}
else toast("Enter phone number and its verification number")
}
}
private fun verificationCallbacks () {
mCallbacks = object: PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
progress.visibility = View.INVISIBLE
signIn(credential)
Log.d("abc","1")
}
override fun onVerificationFailed(p0: FirebaseException) {
progress.visibility=View.GONE
Log.d("abc","2")}
override fun onCodeSent(verfication: String, p1: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(verfication, p1)
verificationId = verfication
progress.visibility = View.INVISIBLE
Log.d("abc","3")
}
}
}
private fun verify () {
verificationCallbacks()
val phnNo ="+"+ phnNoTxt.text.toString()
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phnNo,
60,
TimeUnit.SECONDS,
this,
mCallbacks
)
}
private fun signIn (credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener {
task: Task<AuthResult> ->
if (task.isSuccessful) {
toast("Sign in Successfully :)")
}
}
}
private fun authenticate () {
val verifiNo = verifiTxt.text.toString()
val credential: PhoneAuthCredential = PhoneAuthProvider.getCredential(verificationId, verifiNo)
signIn(credential)
}
private fun toast (msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show()
}
}
login_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
xmlns:android="http://schemas.android.com/apk/res/android">
<EditText
android:id="@+id/phnNoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:hint="Phone Number"
android:inputType="number"
android:textAlignment="center"
android:textSize="24sp"
android:gravity="center_horizontal" />
<EditText
android:id="@+id/verifiTxt"
android:text=""
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:textAlignment="center"
android:inputType="number"
android:layout_below="@+id/phnNoTxt"
android:hint="Verification Code"
android:gravity="center_horizontal"
android:layout_alignParentLeft="true" />
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
<Button
android:id="@+id/veriBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/verifiTxt"
android:layout_centerHorizontal="true"
android:layout_gravity="center"
android:text="Verify" />
<Button
android:id="@+id/authBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/veriBtn"
android:layout_centerHorizontal="true"
android:layout_gravity="center"
android:text="Authenticate" />
</LinearLayout>
</ScrollView>
When I enter my phone number for first time, Firebase sends me SMS, in fact in verificationCallbacks ()
, the third one will run (onCodeSent
). After that when I enter again my phone number, in verificationCallbacks ()
, the first one will run (onVerificationCompleted
). It's rational. But it is strange for me that after I deleted SMS verification code from my phone and deleted my phone number from Firebase, although I expected Firebase to send me SMS and (onCodeSent
) run, but again (onVerificationCompleted
) ran. When I test in another phone, it worked as I like. Every time I entered my phone number (in another phone not the phone my simcard is in it), Firebase sent me SMS with code and it authenticated my phone number if the code was correct. I want Firebase to send me SMS everytime I enter my phone number, either I try it in the phone my simcard is in it or in another phone. Is it possible? How should I change my code?
回答1:
There seems no way to do that without an SMS. Even in firebase docs it's mentioned it will be done through SMS by sending a code. And how would you verify code without SMS? The phone number is not a property of your android device. It's somewhere with your operator. Even if you manage to get a phone number in a string and create your own way to verify the phone number it won't be safe and can be misused by reverser-engineering.
This is mentioned in the docs.
onCodeAutoRetrievalTimeOut(String verificationId) Optional. This method is called after the timeout duration specified to verifyPhoneNumber has passed without onVerificationCompleted triggering first. On devices without SIM cards, this method is called immediately because SMS auto-retrieval isn't possible.
Now coming back to the topic, this is possible but during testing. You can whitelist the numbers and the OTP or code via SMS won't be sent. However there are some conditions for it. https://firebase.google.com/docs/auth/android/phone-auth#test-with-whitelisted-phone-numbers
Secondly, you seem to have an issue where you delete the phone number but firebase still ran onVerificationCmoplete
. Try deleting the user from the Authentication tab and refreshing it. And if your code keeps trace of the phone number or user data afiiliated with that number, make sure you clean that as well.
来源:https://stackoverflow.com/questions/61038436/authenticating-phone-number-without-sending-sms-in-firebase-for-android