Search code examples
androidsmsone-time-password

Cannot get OTP when use Sms Retriever


I'm trying to use Google's SMS Retriever API for Automatic SMS Verification. I have followed the directions here but my app is not receiving any SMS messages. I've tried many ways but it's still not working and I really don't understand why.

Here is what I've done. First I create class MySMSBroadcastReceiver:

public class MySMSBroadcastReceiver extends BroadcastReceiver {

    public OTPReceiveListener otpReceiveListener;
    public void initOtpReceiveListener(OTPReceiveListener otpReceiveListener) {
        this.otpReceiveListener = otpReceiveListener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
            Bundle extras = intent.getExtras();
            Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

            switch(status.getStatusCode()) {
                case CommonStatusCodes.SUCCESS:
                    // Get SMS message contents
                    String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
                    otpReceiveListener.onOTPReceived(message);
                    break;
                case CommonStatusCodes.TIMEOUT:
                    otpReceiveListener.onOTPTimeOut();
                    break;
            }
        }
    }

    public interface OTPReceiveListener {

        void onOTPReceived(String otp);
        void onOTPTimeOut();
    }

}

For class OTPActivity, I remove unrelated code:

public class OTPActivity extends BaseActivity implements IDelegateResponse<OTPResponse>, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, MySMSBroadcastReceiver.OTPReceiveListener {

    @BindView(R.id.edtSmsOtp)
    EditText edtSmsOtp;

    private final String TAG = "OTPActivity";
    private MySMSBroadcastReceiver mySMSBroadcastReceiver;

    @Override
    public int getLayoutID() {
        return R.layout.activity_otp;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setUpOTPSms();
    }

    private void setUpOTPSms() {
        AppSignatureHelper appSignatureHelper = new AppSignatureHelper(OTPActivity.this);
        Utils.showLog(TAG, "getAppSignatures:" + appSignatureHelper.getAppSignatures());

        mySMSBroadcastReceiver = new MySMSBroadcastReceiver();
        mySMSBroadcastReceiver.initOtpReceiveListener(this);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);
        intentFilter.setPriority(2147483647);
        registerReceiver(mySMSBroadcastReceiver, intentFilter);

        startSMSListener();
   }

    private void startSMSListener() {
        SmsRetrieverClient client = SmsRetriever.getClient(OTPActivity.this);
        Task<Void> task = client.startSmsRetriever();
        task.addOnSuccessListener(aVoid -> {
            //Toast.makeText(OTPActivity.this, "SMS Retriever starts", Toast.LENGTH_LONG).show();
            Utils.showLog(TAG, "SMS Retriever starts");
        });
        task.addOnFailureListener(e -> Toast.makeText(OTPActivity.this, "Error", Toast.LENGTH_LONG).show());
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {

    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }

    @Override
    public void onOTPReceived(String otp) {
        if (mySMSBroadcastReceiver != null) {
            unregisterReceiver(mySMSBroadcastReceiver);
        }

        Utils.showLog("OTP Received", "OTP: " + otp);
    }

    @Override
    public void onOTPTimeOut() {
        Utils.showLog("OTP Received", "onOTPTimeOut");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mySMSBroadcastReceiver != null) {
            unregisterReceiver(mySMSBroadcastReceiver);
        }
    }
}

Solution

  • You don't need to add any Permission in Manifest for OPT to work. Follow the given code (is in Kotlin, easy to implement and it's working).

    class MainActivity : AppCompatActivity() {
    
    private val smsBroadcastReceiver by lazy { SMSBroadcastReceiver() }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
        val client = SmsRetriever.getClient(this)
        val retriever = client.startSmsRetriever()
        retriever.addOnSuccessListener {
    
            Toast.makeText(this@MainActivity,"Listener started", Toast.LENGTH_SHORT).show()
    
            val otpListener = object : SMSBroadcastReceiver.OTPListener {
                override fun onOTPReceived(otp: String) {
                    customCodeInput.setText(otp)
                    Toast.makeText(this@MainActivity, otp , Toast.LENGTH_LONG).show()
                }
    
                override fun onOTPTimeOut() {
                    Toast.makeText(this@MainActivity,"TimeOut", Toast.LENGTH_SHORT).show()
                }
            }
            smsBroadcastReceiver.injectOTPListener(otpListener)
            registerReceiver(smsBroadcastReceiver,
                    IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION))
        }
        retriever.addOnFailureListener {
            Toast.makeText(this@MainActivity,"Problem to start listener", Toast.LENGTH_SHORT).show()
        }
    
    }
    
    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(smsBroadcastReceiver)
    }}
    

    SMSBroadcastReceiver is as follows :

    class SMSBroadcastReceiver: BroadcastReceiver() {
    
    private var otpReceiver: OTPListener? = null
    
    fun injectOTPListener(receiver: OTPListener?) {
        this.otpReceiver = receiver
    }
    
    override fun onReceive(context: Context, intent: Intent) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
            val extras = intent.extras
            val status = extras.get(SmsRetriever.EXTRA_STATUS) as Status
    
            when (status.statusCode) {
    
                CommonStatusCodes.SUCCESS -> {
    
                    val message = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
    
                    val pattern = Pattern.compile("\\d{6}")
                    val matcher = pattern.matcher(message)
    
                    if (matcher.find()) {
                        otpReceiver?.onOTPReceived(matcher.group(0))
                        return
                    }
                }
                CommonStatusCodes.TIMEOUT -> {
                    otpReceiver?.onOTPTimeOut()
                }
            }
        }
    }
    
    interface OTPListener {
    
    
        fun onOTPReceived(otp: String)
    
        fun onOTPTimeOut()
    }}
    

    PS : If you still face difficulties let me know.