应该从消息中自动读取OTP(令牌)

use*_*022 37 android one-time-password

我正在开发一个Android应用程序,其中服务器发送OTP并且用户需要在应用程序中输入此OTP,以登录我的应用程序.我想要的是,我的应用程序应该能够自动读取服务器发送的OTP.我怎样才能做到这一点?任何有关这方面的帮助或指导都将受到高度赞赏.

bri*_*con 28

我建议您不要使用任何第三方库从SMS收件箱中自动获取OTP.如果您对广播接收器及其工作原理有基本的了解,则可以轻松完成此操作.试试以下方法:

步骤1)创建单个接口,即SmsListner

package com.wnrcorp.reba;
public interface SmsListener{
public void messageReceived(String messageText);}
Run Code Online (Sandbox Code Playgroud)

步骤2)创建单个广播接收器即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;
}
}
Run Code Online (Sandbox Code Playgroud)

步骤3)在android清单文件中添加监听器即广播接收器

<receiver android:name=".SmsReceiver">    
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
        </intent-filter>
</receiver>
Run Code Online (Sandbox Code Playgroud)

并添加权限

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

最后的步骤4)在收件箱中收到otp时自动获取otp的活动.在我的情况下,我正在获取otp并设置edittext字段.

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();           
             }
    });
   }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

OTP验证活动的屏幕截图,您可以在其中获取OTP作为收到的消息 在此输入图像描述

  • 此解决方案现已弃用.您应该使用SMS Retriever API.您可以在此处找到详细说明:https://developers.google.com/identity/sms-retriever/overview (4认同)

小智 24

您可以尝试使用像这样的简单库

通过gradle安装并添加权限后,在onCreate activity等方法中启动SmsVerifyCatcher:

    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
    }
});
Run Code Online (Sandbox Code Playgroud)

另外,覆盖活动生命周期方法:

  @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;
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*got 6

由于Google限制了对READ_SMS权限的使用,因此,这里是没有READ_SMS权限的解决方案。

SMS检索器API

基本功能是避免使用Android关键权限READ_SMS并使用此方法完成任务。打击是您需要的步骤。

将发送OTP发送到用户号码,检查SMS Retriever API是否能够接收消息

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
    }
});
Run Code Online (Sandbox Code Playgroud)

广播接收器代码

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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一步。将此接收器注册到您的清单中

<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>
Run Code Online (Sandbox Code Playgroud)

您的短信必须如下。

<#> Your OTP code is: 6789
QWsa8754qw2 
Run Code Online (Sandbox Code Playgroud)

这里QWsa8754qw2是您自己的应用程序11个字符的哈希码。点击此链接

  • 不能超过140个字节
  • 以前缀<#>开头
  • 以11个字符的哈希字符串结尾,该字符串标识您的应用

要导入com.google.android.gms.auth.api.phone.SmsRetriever,请不要忘记将此行添加到您的应用程序build.gradle中:

implementation "com.google.android.gms:play-services-auth-api-phone:16.0.0"
Run Code Online (Sandbox Code Playgroud)

  • 更新库解决了我的问题,感谢您的回复@Shabbir :) (2认同)

Abu*_*eji 5

我实现了这样的东西。但是,这是我在消息传入时所做的,我只检索了六位代码,将其捆绑在一个意图中,并将其发送到需要它的活动或片段并验证代码。该示例向您展示了获取短信的方法。查看下面的代码以说明如何使用LocalBrodcastManager发送,如果您的消息包含更多文本(例如问候语),请将其标准化以更好地帮助您。例如“您的验证码是:84HG73”,您可以创建一个这样的正则表达式模式([0-9]){2}([A-Z]){2}([0-9]){2},这意味着两个整数、两个 [大写] 字母和两个整数。祝你好运!

从消息中丢弃所有不需要的信息后

 Intent intent = new Intent("AddedItem");
 intent.putExtra("items", code);
 LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent); 
Run Code Online (Sandbox Code Playgroud)

和接收它的片段/活动

@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);
}
Run Code Online (Sandbox Code Playgroud)

以及用于处理您收集的有效负载的代码

 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
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

这是否有点帮助。我通过使用回调做得更好