46

I am working on an Android App, in which the server sends an OTP and the user needs to enter this OTP in the App, to SignUp for my App. What I want is, that my App should be able to automatically read the OTP sent by the server. How can I achieve this? Any help or guidance in this regard would be highly appreciated.

aminography
  • 18,195
  • 11
  • 51
  • 57
user1903022
  • 995
  • 1
  • 10
  • 19
  • You could read text messages by writing a broadcast receiver. But above API level 19, you need to make a default sms app to read messages. So I don't think it's possible. Or maybe it's possible: check this link http://stackoverflow.com/questions/19856338/using-new-telephony-content-provider-to-read-sms – capt.swag Jun 16 '15 at 08:20
  • But that's how its done in WhatsApp. They send the token/OTP/authentication message and the OTP from that message is read automatically. – user1903022 Jun 16 '15 at 08:22
  • So, then it's possible, I've found a link which allows to read incoming sms messages using BroadcastReceiver. Try this link and see if it's helpful http://androidexample.com/Incomming_SMS_Broadcast_Receiver_-_Android_Example/index.php?view=article_discription&aid=62&aaid=87 – capt.swag Jun 16 '15 at 08:23
  • Thanks, but, this example would only show me an alert message by displaying the contents of the sms, whereas what I need is to automatically read the token sent by the server from the sms. – user1903022 Jun 16 '15 at 08:27
  • It seems like you can get the body of sms message. So it would be easy to parse the token from the sms. I don't know your implementation, but it should work. – capt.swag Jun 16 '15 at 08:36
  • Yes, I can get the body of the sms. Could you please give me an example of how to parse the token from the sms and make it automatically entered in the EditBox which is there, for the token to be entered. – user1903022 Jun 16 '15 at 08:39
  • It's just communicating between BroadcastReceiver and Activity. There will be plenty of examples online. – capt.swag Jun 16 '15 at 08:44
  • Okay, thank you for the help. – user1903022 Jun 16 '15 at 08:46

9 Answers9

34

I will recommend you not to use any third party libraries for auto fetch OTP from SMS Inbox. This can be done easily if you have basic understanding of Broadcast Receiver and how it works. Just Try following approach :

Step 1) Create single interface i.e SmsListner

package com.wnrcorp.reba;
public interface SmsListener{
public void messageReceived(String messageText);}

Step 2) Create single Broadcast Receiver i.e SmsReceiver

package com.wnrcorp.reba;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
public class SmsReceiver extends BroadcastReceiver {
private static SmsListener mListener;
Boolean b;
String abcd,xyz;
@Override
public void onReceive(Context context, Intent intent) {
Bundle data  = intent.getExtras();
Object[] pdus = (Object[]) data.get("pdus");
    for(int i=0;i<pdus.length;i++){
        SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
        String sender = smsMessage.getDisplayOriginatingAddress();
       // b=sender.endsWith("WNRCRP");  //Just to fetch otp sent from WNRCRP
        String messageBody = smsMessage.getMessageBody();
       abcd=messageBody.replaceAll("[^0-9]","");   // here abcd contains otp 
        which is in number format
        //Pass on the text to our listener.
        if(b==true) {
            mListener.messageReceived(abcd);  // attach value to interface 
  object
        }
        else
        {
        }
    }
}
public static void bindListener(SmsListener listener) {
    mListener = listener;
}
}

Step 3) Add Listener i.e broadcast receiver in android manifest file

<receiver android:name=".SmsReceiver">    
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
        </intent-filter>
</receiver>

and add permission

<uses-permission android:name="android.permission.RECEIVE_SMS"/>

Final Step 4) The activity where you going to auto fetch otp when it is received in inbox. In my case I'm fetching otp and setting on edittext field.

public class OtpVerificationActivity extends AppCompatActivity {
EditText ed;
TextView tv;
String otp_generated,contactNo,id1;
GlobalData gd = new GlobalData();
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_otp_verification);
    ed=(EditText)findViewById(R.id.otp);
    tv=(TextView) findViewById(R.id.verify_otp); 
    /*This is important because this will be called every time you receive 
     any sms */            
 SmsReceiver.bindListener(new SmsListener() {
        @Override
        public void messageReceived(String messageText) {
            ed.setText(messageText);     
        }
    });
    tv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try
            {
                InputMethodManager imm=
  (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);                    
  imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
            }
            catch(Exception e)
            {}           
            if (ed.getText().toString().equals(otp_generated))
            {
                Toast.makeText(OtpVerificationActivity.this, "OTP Verified 
       Successfully !", Toast.LENGTH_SHORT).show();           
             }
    });
   }
}

Layout File for OtpVerificationActivity

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_otp_verification"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.wnrcorp.reba.OtpVerificationActivity">
<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/firstcard"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    card_view:cardCornerRadius="10dp"
    >
   <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="@android:color/white">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="OTP Confirmation"
            android:textSize="18sp"
            android:textStyle="bold"
            android:id="@+id/dialogTitle"
            android:layout_margin="5dp"
            android:layout_gravity="center"
            />
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/otp"
            android:layout_margin="5dp"
            android:hint="OTP Here"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Verify"
            android:textSize="18sp"
            android:id="@+id/verify_otp"
            android:gravity="center"
            android:padding="10dp"
            android:layout_gravity="center"
            android:visibility="visible"
            android:layout_margin="5dp"
            android:background="@color/colorPrimary"
            android:textColor="#ffffff"
            />
        </LinearLayout>
        </android.support.v7.widget.CardView>
        </RelativeLayout>

Screenshots for OTP Verification Activity where you fetch OTP as soons as messages received enter image description here

Aabauser
  • 513
  • 1
  • 4
  • 17
brijexecon
  • 509
  • 4
  • 11
  • Do we need any run time permissions for this? – Akshay kumar Apr 05 '18 at 14:58
  • Yes you need to ask for runtime permission if you targeting android 6 and above. Until Android 6, permission were granted automatically. You can refer https://stackoverflow.com/a/40558918/7727011 – brijexecon May 08 '18 at 05:54
  • What is "pdus" ? @brijexecon – Ravi Vaniya Jun 07 '18 at 06:26
  • Without going into more detail, simply its flag that you use while receiving the messages. As u can see it returns array of Objects that means if u receiving sms having large body then you will receive parts of message in each index. – brijexecon Jun 11 '18 at 17:35
  • 5
    This solution is now deprecated. You should use the SMS Retriever API. You can find detailed instructions here: https://developers.google.com/identity/sms-retriever/overview – Tsiogas P. Nov 22 '18 at 08:43
26

You can try using a simple library like

After installing via gradle and adding permissions initiate SmsVerifyCatcher in method like onCreate activity:

    smsVerifyCatcher = new SmsVerifyCatcher(this, new OnSmsCatchListener<String>() {
    @Override
    public void onSmsCatch(String message) {
        String code = parseCode(message);//Parse verification code
        etCode.setText(code);//set code in edit text
        //then you can send verification code to server
    }
});

Also, override activity lifecicle methods:

  @Override
protected void onStart() {
    super.onStart();
    smsVerifyCatcher.onStart();
}

@Override
protected void onStop() {
    super.onStop();
    smsVerifyCatcher.onStop();
}

/**
 * need for Android 6 real time permissions
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    smsVerifyCatcher.onRequestPermissionsResult(requestCode, permissions, grantResults);
}


public String parseCode(String message) {
    Pattern p = Pattern.compile("\\b\\d{4}\\b");
    Matcher m = p.matcher(message);
    String code = "";
    while (m.find()) {
        code = m.group(0);
    }
    return code;
}
Agilanbu
  • 2,308
  • 1
  • 26
  • 29
smy
  • 269
  • 3
  • 4
13

As Google has restricted use of READ_SMS permission here is solution without READ_SMS permission.

SMS Retriever API

Basic function is to avoid using Android critical permission READ_SMS and accomplish task using this method. Blow are steps you needed.

Post Sending OTP to user's number, check SMS Retriever API able to get message or not

SmsRetrieverClient client = SmsRetriever.getClient(SignupSetResetPasswordActivity.this);
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
    @Override
    public void onSuccess(Void aVoid) {
        // Android will provide message once receive. Start your broadcast receiver.
        IntentFilter filter = new IntentFilter();
        filter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);
        registerReceiver(new SmsReceiver(), filter);
    }
});
task.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        // Failed to start retriever, inspect Exception for more details
    }
});

Broadcast Receiver Code

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;

import com.google.android.gms.auth.api.phone.SmsRetriever;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;

public class SmsReceiver extends BroadcastReceiver {

    @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 otp;
                    String msgs = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);

                    // Extract one-time code from the message and complete verification
                    break;
                case CommonStatusCodes.TIMEOUT:
                    // Waiting for SMS timed out (5 minutes)
                    // Handle the error ...
                    break;
            }
        }
    }
}

Final Step. Register this receiver into your Manifest

<receiver android:name=".service.SmsReceiver" android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
    </intent-filter>
</receiver>

Your SMS must as below.

<#> Your OTP code is: 6789
QWsa8754qw2 

Here QWsa8754qw2 is your own application 11 character hash code. Follow this link

  • Be no longer than 140 bytes
  • Begin with the prefix <#>
  • End with an 11-character hash string that identifies your app

To import com.google.android.gms.auth.api.phone.SmsRetriever, Dont forget to add this line to your app build.gradle:

implementation "com.google.android.gms:play-services-auth-api-phone:16.0.0"
Dika
  • 1,727
  • 4
  • 26
  • 42
Shabbir Dhangot
  • 8,089
  • 9
  • 55
  • 75
  • The code is not working if SMS coming from a sender id, it's working fine if it is coming from a mobile number. Any idea what may be wrong? – Neo Aug 07 '19 at 14:25
  • 1
    This is not an issue. SMS Retriver Only checks above pattern and checks hash is matching with your application or not. If you check in dev environment hash will be different. FYI : I have tried both sender id and mobile. I am assuming sender id is something like TM-ABCDEF. Its working for me. – Shabbir Dhangot Aug 08 '19 at 05:45
  • 2
    Updating library fixed my problem, thanks for your reply @Shabbir :) – Neo Aug 10 '19 at 10:14
  • how to extract code i didn't understand can u explan more – MustafaShaikh Nov 04 '19 at 11:16
  • 1
    @MustafaShaikh to extract code you need to apply some logic to find code in the message. This API will retrive SMS and give it to you. What I did. I splitted sms with space and checked 7th position on splitted string. As my message is predefined I will always have it at 7th position. – Shabbir Dhangot Nov 04 '19 at 11:44
  • Is there any way to hide the hash key in the message body? – George Thomas Jan 02 '20 at 04:47
  • Not needed. There is no advantage of hiding it. No other application can read your OTP message as hash created from your signing certificates. So don't worry about it. – Shabbir Dhangot Jan 02 '20 at 04:57
  • Not working after release apk on playstore. The same apk working before release. – Kalu Khan Luhar Feb 12 '20 at 01:42
  • Hashkey is different for production as your production jks is different. You need to generate your hash with production jks and use that for appending in message. – Shabbir Dhangot Feb 12 '20 at 03:41
  • Hi @Shabbir, I have tested with production APK it was working fine, but after release app on the play store this is not fetching SMS data. I am using this [file](https://github.com/chintandesai49/SMSRetrieverAPIDemo/blob/master/app/src/main/java/com/example/chintan/smsretrieverapidemo/AppSignatureHelper.java) generate hash for production as well. The SMS text does not include . Can this an issue? – Kalu Khan Luhar Feb 12 '20 at 15:16
  • Try with appending # before message starts. In my case I am adding # and its working fine. – Shabbir Dhangot Feb 13 '20 at 05:03
  • @ShabbirDhangot hii. how can we create the harsh code . is it create manually or for that also we need to write any code? – vijju Apr 09 '21 at 05:09
  • @vijju no need to write any code. You need to generate it by following steps in link. https://developers.google.com/identity/sms-retriever/verify – Shabbir Dhangot Apr 09 '21 at 06:56
5

I implemented something of that such. But, here is what I did when the message comes in, I retrieve only the six digit code, bundle it in an intent and send it to the activity or fragment needing it and verifies the code. The example shows you the way to get the sms already. Look at the code below for illustration on how to send using LocalBrodcastManager and if your message contains more texts E.g Greetings, standardize it to help you better. E.g "Your verification code is: 84HG73" you can create a regex pattern like this ([0-9]){2}([A-Z]){2}([0-9]){2} which means two ints, two [capital] letters and two ints. Good Luck!

After discarding all un needed info from the message

 Intent intent = new Intent("AddedItem");
 intent.putExtra("items", code);
 LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent); 

And the Fragment/Activity receiving it

@Override
public void onResume() {
    LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("AddedItem"));
    super.onResume();
}

@Override
public void onPause() {
    super.onDestroy();
    LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
}

And the code meant to handle the payload you collected

 private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction()) {
            final String message = intent.getStringExtra("message");
            //Do whatever you want with the code here
        }
    }
};

Does that help a little bit. I did it better by using Callbacks

Tonespy
  • 2,707
  • 7
  • 21
  • 46
  • shouldn't you be overriding `onPause()` instead of `onDestroy()`? – galdin Mar 05 '16 at 21:17
  • It depends on how you want to use it. If the `Fragment` or `Activity` is always active, then leave it in `onPause` but in my case whereby I need it just once, I can drop it in `onPause` or `onDestroy` since both would be called anyway – Tonespy Mar 06 '16 at 05:32
  • 1
    I'm sorry I wasn't clear enough. The call to onDestroy() is [not guaranteed](http://developer.android.com/reference/android/app/Activity.html#onDestroy%28%29). Should be using onStop() or onPause() depending on context. Right? – galdin Mar 06 '16 at 05:44
3

Sorry for late reply but still felt like posting my answer if it helps.It works for 6 digits OTP.

    @Override
    public void onOTPReceived(String messageBody)
    {
        Pattern pattern = Pattern.compile(SMSReceiver.OTP_REGEX);
        Matcher matcher = pattern.matcher(messageBody);
        String otp = HkpConstants.EMPTY;
        while (matcher.find())
        {
            otp = matcher.group();
        }
        checkAndSetOTP(otp);
    }
Adding constants here

public static final String OTP_REGEX = "[0-9]{1,6}";

For SMS listener one can follow the below class

public class SMSReceiver extends BroadcastReceiver
{
    public static final String SMS_BUNDLE = "pdus";
    public static final String OTP_REGEX = "[0-9]{1,6}";
    private static final String FORMAT = "format";

    private OnOTPSMSReceivedListener otpSMSListener;

    public SMSReceiver(OnOTPSMSReceivedListener listener)
    {
        otpSMSListener = listener;
    }

    @Override
    public void onReceive(Context context, Intent intent)
    {
        Bundle intentExtras = intent.getExtras();
        if (intentExtras != null)
        {
            Object[] sms_bundle = (Object[]) intentExtras.get(SMS_BUNDLE);
            String format = intent.getStringExtra(FORMAT);
            if (sms_bundle != null)
            {
                otpSMSListener.onOTPSMSReceived(format, sms_bundle);
            }
            else {
                // do nothing
            }
        }
    }

    @FunctionalInterface
    public interface OnOTPSMSReceivedListener
    {
        void onOTPSMSReceived(@Nullable String format, Object... smsBundle);
    }
}

    @Override
    public void onOTPSMSReceived(@Nullable String format, Object... smsBundle)
    {
        for (Object aSmsBundle : smsBundle)
        {
            SmsMessage smsMessage = getIncomingMessage(format, aSmsBundle);
            String sender = smsMessage.getDisplayOriginatingAddress();
            if (sender.toLowerCase().contains(ONEMG))
            {
                getIncomingMessage(smsMessage.getMessageBody());
            } else
            {
                // do nothing
            }
        }
    }

    private SmsMessage getIncomingMessage(@Nullable String format, Object aObject)
    {
        SmsMessage currentSMS;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && format != null)
        {
            currentSMS = SmsMessage.createFromPdu((byte[]) aObject, format);
        } else
        {
            currentSMS = SmsMessage.createFromPdu((byte[]) aObject);
        }

        return currentSMS;
    }
Raghav Sharma
  • 734
  • 9
  • 17
2

With the SMS Retriever API, one can Read OTP without declaring android.permission.READ_SMS.

  1. Start the SMS retriever
    private fun startSMSRetriever() {
        // Get an instance of SmsRetrieverClient, used to start listening for a matching SMS message.
        val client = SmsRetriever.getClient(this /* context */);

        // Starts SmsRetriever, which waits for ONE matching SMS message until timeout
        // (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
        // action SmsRetriever#SMS_RETRIEVED_ACTION.
        val task: Task<Void> = client.startSmsRetriever();

        // Listen for success/failure of the start Task. If in a background thread, this
        // can be made blocking using Tasks.await(task, [timeout]);
        task.addOnSuccessListener {
            Log.d("SmsRetriever", "SmsRetriever Start Success")
        }

        task.addOnFailureListener {
            Log.d("SmsRetriever", "SmsRetriever Start Failed")
        }
    }
  1. Receive messages via Broadcast
    public class MySMSBroadcastReceiver : BroadcastReceiver() {

        override fun onReceive(context: Context?, intent: Intent?) {
            if (SmsRetriever.SMS_RETRIEVED_ACTION == intent?.action && intent.extras!=null) {
                val extras = intent.extras
                val status = extras.get(SmsRetriever.EXTRA_STATUS) as Status

                when (status.statusCode) {
                    CommonStatusCodes.SUCCESS -> {
                        // Get SMS message contents
                        val message = extras.get(SmsRetriever.EXTRA_SMS_MESSAGE) as String
                        Log.e("Message", message);
                        // Extract one-time code from the message and complete verification
                        // by sending the code back to your server.
                    }
                    CommonStatusCodes.TIMEOUT -> {
                        // Waiting for SMS timed out (5 minutes)
                        // Handle the error ...
                    }
                }
            }
        }

    }   


    /**Don't forgot to define BroadcastReceiver in AndroidManifest.xml.*/       
    <receiver android:name=".MySMSBroadcastReceiver" android:exported="true">
        <intent-filter>
            <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
        </intent-filter>
    </receiver>
  1. Send the one-time code from the verification message to your server

Make sure your SMS format is exactly as below:

<#> Your ExampleApp code is: 123ABC78
fBzOyyp9h6L
  1. Be no longer than 140 bytes
  2. Begin with the prefix <#>
  3. End with an 11-character hash string that identifies your app

    You can compute app hash with following code:

    import android.content.Context
    import android.content.ContextWrapper
    import android.content.pm.PackageManager
    import android.util.Base64
    import android.util.Log
    import java.nio.charset.StandardCharsets
    import java.security.MessageDigest
    import java.security.NoSuchAlgorithmException
    import java.util.*
    
    /**
     * This is a helper class to generate your message hash to be included in your SMS message.
     *
     * Without the correct hash, your app won't recieve the message callback. This only needs to be
     * generated once per app and stored. Then you can remove this helper class from your code.
     *
     * For More Detail: https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string
     *
     */
    public class AppSignatureHelper(private val context: Context) : ContextWrapper(context) {
    
        companion object {
            val TAG = AppSignatureHelper::class.java.simpleName;
    
            private const val HASH_TYPE = "SHA-256";
            const val NUM_HASHED_BYTES = 9;
            const val NUM_BASE64_CHAR = 11;
        }
    
        /**
         * Get all the app signatures for the current package
         * @return
         */
        public fun getAppSignatures(): ArrayList<String> {
            val appCodes = ArrayList<String>();
    
            try {
                // Get all package signatures for the current package
                val signatures = packageManager.getPackageInfo(
                    packageName,
                    PackageManager.GET_SIGNATURES
                ).signatures;
    
                // For each signature create a compatible hash
                for (signature in signatures) {
                    val hash = hash(packageName, signature.toCharsString());
                    if (hash != null) {
                        appCodes.add(String.format("%s", hash));
                    }
                }
            } catch (e: PackageManager.NameNotFoundException) {
                Log.e(TAG, "Unable to find package to obtain hash.", e);
            }
            return appCodes;
        }
    
        private fun hash(packageName: String, signature: String): String? {
            val appInfo = "$packageName $signature";
            try {
                val messageDigest = MessageDigest.getInstance(HASH_TYPE);
                messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8));
                var hashSignature = messageDigest.digest();
    
                // truncated into NUM_HASHED_BYTES
                hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
                // encode into Base64
                var base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING or Base64.NO_WRAP);
                base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR);
    
                Log.e(TAG, String.format("pkg: %s -- hash: %s", packageName, base64Hash));
                return base64Hash;
            } catch (e: NoSuchAlgorithmException) {
                Log.e(TAG, "hash:NoSuchAlgorithm", e);
            }
            return null;
        }
    }       
    

Required Gradle :

implementation "com.google.android.gms:play-services-auth-api-phone:16.0.0"

References:
https://developers.google.com/identity/sms-retriever/overview
https://developers.google.com/identity/sms-retriever/request
https://developers.google.com/identity/sms-retriever/verify

Dhaval Patel
  • 9,209
  • 4
  • 42
  • 44
0

Yes, this is possible now in browsers also. Chrome release this feature in version 84 and above. With the help of WEBOTP API, we can detect OTP on the web for mobile devices.

Here is a Web-OTP integrated code with Angular PWA Apps: https://github.com/Rohit3230/webOtpAutoReadByAngular

Go for live working URL for angular PWA app. https://rohit3230.github.io/webOtpAutoReadByAngular/

0

I know it's late but to keep this simple for others, here is the solution I have written previously. Use this Library Link. You will not have to mess with anything. After adding dependency simply use this method.

OtpFetcher.getInstance().verifyOtpByMatchingString(this, "OTP", 21000, object : OtpListener {
            override fun onReceived(messageItem: MessageItem) {
                Toast.makeText(this@MainActivity, "" + messageItem, Toast.LENGTH_SHORT).show()
            }

            override fun onTimeOut() {
                Toast.makeText(this@MainActivity, "TimeOut", Toast.LENGTH_SHORT).show()

            }
        })

You will have to pass Context, Search String of your message for Example

You are expecting OTP in your message Pass "OTP" and Time Out for How long you want to listen OTP and That's It. You will get your message in simple format in OnRecieved CallBack.

Intsab Haider
  • 3,161
  • 3
  • 17
  • 29
-2
**activity_main.xml**

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mukundwn.broadcastreceiver.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>



**MainActivity.java**
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private BroadcastReceiver broadcastReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        broadcastReceiver =new MyBroadcastReceiver();
    }

@Override
    protected void onStart()
{
    super.onStart();
    IntentFilter intentFilter=new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
    registerReceiver(broadcastReceiver,intentFilter);
}
@Override
    protected void onStop()
{
    super.onStop();
    unregisterReceiver(broadcastReceiver);
}

}


**MyBroadcastReceiver.java**

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

/**
 * Created by mukundwn on 12/02/18.
 */

public class MyBroadcastReceiver extends BroadcastReceiver {


    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"hello received an sms",Toast.LENGTH_SHORT).show();
    }
}


**Manifest.xml**

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mukundwn.broadcastreceiver">

    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
    <uses-permission android:name="android.permission.READ_SMS"></uses-permission>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".MyBroadcastReceiver">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVE"></action>
        </intent-filter>
        </receiver>
    </application>

</manifest>
  • While this code snippet may solve the question, [including an explanation](https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) helps to improve the quality of your response. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Stefan Crain Apr 23 '18 at 15:24