A free Firebase project (console.firebase.google.com)
A real Android phone with a SIM
How it fits together
1Enter +country number
2verifyPhoneNumber
3SMS code
4signInWithCredential
5HomeActivity
Build it step by step
1. Create a Firebase project
In the Firebase console, add an Android app with your package name (com.example.phoneauth to copy the code unchanged) and download google-services.json into the app folder.
2. Add your app's fingerprints
Phone sign-in checks that requests come from your real app. In Android Studio's terminal run ./gradlew signingReport, then copy the SHA-1 and SHA-256 into the Firebase app settings.
3. Turn on phone sign-in
In Authentication → Sign-in method, enable Phone. To test without real SMS, add a test number and code there (for example +1 650-555-1234 with code 123456).
4. Add Firebase to the app
In app/build.gradle.kts, add the plugin and dependencies:
plugins {id("com.google.gms.google-services") version "4.5.0" apply false}
Then press Sync Now.
5. Send the code
Ask for the number with the country code (+91...). PhoneAuthProvider.verifyPhoneNumber sends the SMS. Its callbacks tell you what happened:
onCodeSent: save the verification ID and show the code box.
onVerificationCompleted: Android read the SMS for you; sign in straight away.
onVerificationFailed: show a message.
6. Check the code
Combine the verification ID with the typed code using PhoneAuthProvider.getCredential, then call signInWithCredential.
7. Resend
Keep the ForceResendingToken from onCodeSent and pass it when the user taps Send again.
8. Remember the user
On launch, if getCurrentUser() isn't null, go straight to Home. Log out calls signOut().
9. Run it
Run on a real phone with a SIM, or use your test number.
If something goes wrong
"This app is not authorized": add the SHA-1 and SHA-256 fingerprints, then download google-services.json again.
No SMS arrives: check the number includes + and the country code, and that Phone sign-in is enabled.
Testing on an emulator: use a test phone number from step 3.
What's improved over the video
Both steps sit on one clear screen, it handles automatic SMS reading and resending, errors appear under the right field, and returning users skip straight to Home.
Files affected
Check what to add and what to replace before copying code.
Sends the SMS code, verifies it, and signs in. Skips straight to Home if already signed in.
MainActivity.java
packagecom.example.phoneauth;importandroid.content.Intent;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.Button;importandroid.widget.ProgressBar;importandroid.widget.TextView;importandroidx.annotation.NonNull;importandroidx.appcompat.app.AppCompatActivity;importcom.google.android.material.textfield.TextInputEditText;importcom.google.android.material.textfield.TextInputLayout;importcom.google.firebase.FirebaseException;importcom.google.firebase.auth.FirebaseAuth;importcom.google.firebase.auth.PhoneAuthCredential;importcom.google.firebase.auth.PhoneAuthOptions;importcom.google.firebase.auth.PhoneAuthProvider;importjava.util.concurrent.TimeUnit;/**
* Step 1: enter a phone number and send a code. Step 2: enter the 6-digit code.
* Firebase sends the SMS and checks the code; often it reads the SMS automatically.
*/publicclassMainActivityextendsAppCompatActivity{privatefinalFirebaseAuth auth =FirebaseAuth.getInstance();privateString verificationId;privatePhoneAuthProvider.ForceResendingToken resendToken;TextInputLayout phoneLayout, codeLayout;TextInputEditText phone, code;Button sendButton, verifyButton;TextView resend, stepTitle;ProgressBar progress;@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);// Already signed in? Go straight to Home.if(auth.getCurrentUser()!=null){openHome();return;}Screens.setUp(this,R.layout.activity_main);
phoneLayout =findViewById(R.id.phoneLayout);
codeLayout =findViewById(R.id.codeLayout);
phone =findViewById(R.id.phone);
code =findViewById(R.id.code);
sendButton =findViewById(R.id.buttonSend);
verifyButton =findViewById(R.id.buttonVerify);
resend =findViewById(R.id.textResend);
stepTitle =findViewById(R.id.textStep);
progress =findViewById(R.id.progress);
sendButton.setOnClickListener(v ->sendCode(null));
resend.setOnClickListener(v ->sendCode(resendToken));
verifyButton.setOnClickListener(v ->{String typed =String.valueOf(code.getText()).trim();if(typed.length()!=6|| verificationId ==null){
codeLayout.setError(getString(R.string.error_code));return;}signIn(PhoneAuthProvider.getCredential(verificationId, typed));});}privatevoidsendCode(PhoneAuthProvider.ForceResendingToken token){String number =String.valueOf(phone.getText()).replace(" ","");// Firebase needs the full international number, starting with + and the country code.if(!number.matches("\\+\\d{8,15}")){
phoneLayout.setError(getString(R.string.error_phone));return;}
phoneLayout.setError(null);setBusy(true);PhoneAuthOptions.Builder options =PhoneAuthOptions.newBuilder(auth).setPhoneNumber(number).setTimeout(60L,TimeUnit.SECONDS).setActivity(this).setCallbacks(callbacks);if(token !=null) options.setForceResendingToken(token);PhoneAuthProvider.verifyPhoneNumber(options.build());}privatefinalPhoneAuthProvider.OnVerificationStateChangedCallbacks callbacks =newPhoneAuthProvider.OnVerificationStateChangedCallbacks(){@OverridepublicvoidonVerificationCompleted(@NonNullPhoneAuthCredential credential){// Android read the SMS for us (or the number was verified instantly).signIn(credential);}@OverridepublicvoidonVerificationFailed(@NonNullFirebaseException e){setBusy(false);
phoneLayout.setError(getString(R.string.error_send));}@OverridepublicvoidonCodeSent(@NonNullString id,@NonNullPhoneAuthProvider.ForceResendingToken token){setBusy(false);
verificationId = id;
resendToken = token;showCodeStep();}};privatevoidsignIn(PhoneAuthCredential credential){setBusy(true);
auth.signInWithCredential(credential).addOnCompleteListener(this, task ->{setBusy(false);if(task.isSuccessful())openHome();else codeLayout.setError(getString(R.string.error_code));});}privatevoidshowCodeStep(){
stepTitle.setText(R.string.step_code);
phoneLayout.setEnabled(false);
sendButton.setVisibility(View.GONE);
codeLayout.setVisibility(View.VISIBLE);
verifyButton.setVisibility(View.VISIBLE);
resend.setVisibility(View.VISIBLE);
code.requestFocus();}privatevoidsetBusy(boolean busy){
progress.setVisibility(busy ?View.VISIBLE:View.GONE);
sendButton.setEnabled(!busy);
verifyButton.setEnabled(!busy);}privatevoidopenHome(){startActivity(newIntent(this,HomeActivity.class));finish();}}