18

I am trying to implement SMS Retriever API for SMS verification. The official way mentioned in the documentation says to use GoogleApiClient along with HintRequest to retrieve the mobile number from the device

HintRequest hintRequest = new HintRequest.Builder()
            .setPhoneNumberIdentifierSupported(true)
            .build();

PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
            googleApiClient, hintRequest);
try {
    startIntentSenderForResult(intent.getIntentSender(),
                RESOLVE_HINT, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
    e.printStackTrace();
}

But the GoogleAPIClient is deprecated and replaced by GoogleApi interface, such as GoogleSignInClient. I tried to use GoogleSignInClient but getHintPickerIntent does not accept it. Is it safe to use the old API even after being deprecated or is there a way to use the latter with SMSRetriver API?

Christopher Bull
  • 2,489
  • 1
  • 23
  • 27
Dev Sharma
  • 634
  • 7
  • 26

2 Answers2

37

To remove the deprecated GoogleApiClient, replace your intent with the following:

// Kotlin
val intent = Credentials.getClient(this).getHintPickerIntent(hintRequest)
// Java
PendingIntent intent = Credentials.getClient(this).getHintPickerIntent(hintRequest);

Credentials is found in this package: com.google.android.gms.auth.api.credentials.Credentials.


Full working example which calls buttonClicked when a button is pressed:

// Kotlin

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.auth.api.credentials.Credential
import com.google.android.gms.auth.api.credentials.Credentials
import com.google.android.gms.auth.api.credentials.CredentialsApi
import com.google.android.gms.auth.api.credentials.HintRequest

class MyActivity : AppCompatActivity() {

    // ... onCreate Functions, etc

    // Arbitrary number to identify the request for crednetials
    private val iRequestCodePhoneNumber = 100

    // Button click listener
    fun buttonClicked(@Suppress("UNUSED_PARAMETER") view: View) {
        val hintRequest = HintRequest.Builder()
            .setPhoneNumberIdentifierSupported(true)
            .build()

        val intent = Credentials.getClient(this).getHintPickerIntent(hintRequest)

        startIntentSenderForResult(
            intent.intentSender,
            iRequestCodePhoneNumber, null, 0, 0, 0
        )
    }

    // Parse the result of the HintPicker (i.e., get the selected phone number)
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        // resultCode:
        //   Activity.RESULT_OK (-1) = number selected
        //   Activity.RESULT_CANCELED (0) = user touched outside the HintPicker (do nothing)
        //   CredentialsApi.ACTIVITY_RESULT_OTHER_ACCOUNT (1001) = "None of the above" (do nothing; treat as same use case as 'Cancelling')
        //   CredentialsApi.ACTIVITY_RESULT_NO_HINTS_AVAILABLE (1002) = no numbers found, probably no SIM card
        if (requestCode == iRequestCodePhoneNumber && resultCode == Activity.RESULT_OK) {
            val credential: Credential? = data?.getParcelableExtra(Credential.EXTRA_KEY)
            val phoneNumber = credential?.id

            // *** Do something with the phone number here ***

        } else if (
            requestCode == iRequestCodePhoneNumber &&
            resultCode == CredentialsApi.ACTIVITY_RESULT_NO_HINTS_AVAILABLE
        ) {
            // *** No phone numbers available ***
            Toast.makeText(this, "No phone numbers found", Toast.LENGTH_LONG).show()
        }
    }
}

This will generate a popup like this:

User selecting phone number available on their device

UPDATED :

The upper code is also deprecated as of now
Step 1 :

Getting GetPhoneNumberHintIntentRequest

val request: GetPhoneNumberHintIntentRequest = GetPhoneNumberHintIntentRequest.builder().build()

        Identity.getSignInClient(requireActivity())
            .getPhoneNumberHintIntent(request)
            .addOnSuccessListener {
                phoneNumberHintIntentResultLauncher.launch(
                    IntentSenderRequest.Builder(it.intentSender).build()
                )
            }
            .addOnFailureListener {
                Log.d(TAG, it.message)
            }
Step 2 :

Setting up ActivityResultLauncher IntentSenderRequest

private val phoneNumberHintIntentResultLauncher: ActivityResultLauncher<IntentSenderRequest> = registerForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()
    ) { result ->
        try {
            val phoneNumber = Identity.getSignInClient(requireActivity()).getPhoneNumberFromIntent(result.data)
            //Do more stuff with phoneNumber
        } catch (e: Exception) {
            Log.d(TAG, it.message)
        }
    }

Image Description : Mobile Number

For official google documentation : Click Here

Kishan Mevada
  • 662
  • 1
  • 6
  • 17
Christopher Bull
  • 2,489
  • 1
  • 23
  • 27
  • 11
    I sympathise with anyone stumbling on this answer, as the documentation for migrating away from the deprecated `GoogleApiClient`s is quite poor (no mappings provided for old/new classes or techniques). Hope this helps someone. – Christopher Bull Apr 23 '20 at 10:08
  • 1
    Thank you, Christopher! It works well. I totally agree with you regarding the documentation. – Dev Sharma Apr 25 '20 at 12:09
  • Thank you for sharing, wish I could do more up votes. – Dino Tw Sep 03 '20 at 21:45
  • Can anyone tell what should we pass in Function `buttonClicked(View view)` the view place, if I use it in java – Athos Tokbi Oct 12 '20 at 20:53
  • You should not be calling `buttonClicked(View view)` directly. In an XML layout files, select a Button (which is a subclass of `View`) and set it's onclick event listener to "buttonClicked". If you're doing it right, Android Studio should auto-suggest available methods. – Christopher Bull Oct 12 '20 at 21:27
  • Thank you for this answer, it was very annoying to see deprecated calls everywhere in my code. How consistent did this api work for you? I have 2 Samsung phones with SIM cards with different api levels (24 and 28) but it gives 1002 as a result code and content of intent differs in both of them. Is this reliable and am I doing something wrong or should I switch to something else? More info: https://stackoverflow.com/questions/66252392/android-hintpicker-results-in-1002-while-retrieving-phone-number – Prethia Feb 18 '21 at 07:27
  • Sorry, I don't know. Best of luck finding an answer. – Christopher Bull Feb 18 '21 at 08:02
  • 2
    For some reason, on a real device, the new code gives me `ApiException: 16: No phone number is found on this device` , while the old one works fine. And, on emulator, it's the opposite (old doesn't work, and new works fine). How come? I've reported this here: https://issuetracker.google.com/issues/266967506 – android developer Jan 30 '23 at 09:55
3

Use this function requestHint() when you want to request for phone number hint.

       GetPhoneNumberHintIntentRequest request = GetPhoneNumberHintIntentRequest.builder().build();
    Identity.getSignInClient(this)
            .getPhoneNumberHintIntent(request)
            .addOnSuccessListener(result -> {
                try {
                    IntentSender intentSender = result.getIntentSender();
                    hintResult.launch(new IntentSenderRequest.Builder(intentSender).build());
                } catch (Exception e) {
                    Log.i("Error launching", "error occurred in launching Activity result");
                }
            })
            .addOnFailureListener(e -> Log.i("Failure occurred", "Failure getting phone number"));

Here, we use this to handle the result (previously, we used onActivityResult() for this).

    ActivityResultLauncher<IntentSenderRequest> hintResult = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(),
        result -> {
            if(result!=null){
                try {
                    String phoneNum = Identity.getSignInClient(getApplicationContext()).getPhoneNumberFromIntent(result.getData());
                    // Do your work with phone number here
                } catch (ApiException e) {
                    e.printStackTrace();
                }
            }
        });