OTP (токен) должен автоматически считываться из сообщения

Я работаю над приложением для Android, в котором сервер отправляет OTP, и пользователю необходимо ввести этот OTP в приложении, чтобы зарегистрироваться для моего приложения. Я хочу, чтобы мое приложение могло автоматически читать OTP, отправленный сервером. Как я могу этого добиться? Любая помощь или руководство в этом отношении будут высоко оценены.


person user1903022    schedule 16.06.2015    source источник
comment
Вы можете читать текстовые сообщения, написав широковещательный приемник. Но выше уровня API 19 вам нужно сделать смс-приложение по умолчанию для чтения сообщений. Так что я не думаю, что это возможно. Или, может быть, это возможно: проверьте эту ссылку stackoverflow.com/questions/19856338/   -  person capt.swag    schedule 16.06.2015
comment
Но именно так это делается в WhatsApp. Они отправляют токен/OTP/сообщение аутентификации, и OTP из этого сообщения считывается автоматически.   -  person user1903022    schedule 16.06.2015
comment
Итак, возможно, я нашел ссылку, которая позволяет читать входящие смс-сообщения с помощью BroadcastReceiver. Попробуйте эту ссылку и посмотрите, будет ли она полезна androidexample.com/   -  person capt.swag    schedule 16.06.2015
comment
Спасибо, но этот пример покажет мне только предупреждающее сообщение, отображая содержимое sms, тогда как мне нужно автоматически прочитать токен, отправленный сервером из sms.   -  person user1903022    schedule 16.06.2015
comment
Кажется, вы можете получить тело смс-сообщения. Таким образом, было бы легко разобрать токен из смс. Я не знаю вашу реализацию, но она должна работать.   -  person capt.swag    schedule 16.06.2015
comment
Да, я могу получить тело смс. Не могли бы вы привести пример того, как разобрать токен из sms и сделать так, чтобы он автоматически вводился в EditBox, который там есть, для ввода токена.   -  person user1903022    schedule 16.06.2015
comment
Это просто общение между BroadcastReceiver и Activity. В сети будет много примеров.   -  person capt.swag    schedule 16.06.2015
comment
Хорошо, спасибо за помощь.   -  person user1903022    schedule 16.06.2015


Ответы (9)


Я рекомендую вам не использовать какие-либо сторонние библиотеки для автоматической загрузки OTP из почтового ящика SMS. Это можно сделать легко, если у вас есть базовые знания о Broadcast Receiver и о том, как он работает. Просто попробуйте следующий подход:

Шаг 1) Создайте единый интерфейс, например SmsListner

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

Шаг 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;
}
}

Шаг 3) Добавьте прослушиватель, т. е. широковещательный приемник, в файл манифеста Android

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

и добавить разрешение

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

Последний шаг 4) Действие, при котором вы собираетесь автоматически получать 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();           
             }
    });
   }
}

Файл макета для 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>

Скриншоты действия по проверке OTP, когда вы получаете OTP, как только получаете сообщения введите здесь описание изображения

person brijexecon    schedule 16.05.2017
comment
Нужны ли нам какие-либо разрешения во время выполнения для этого? - person Akshay kumar; 05.04.2018
comment
Да, вам нужно запросить разрешение на выполнение, если вы ориентируетесь на Android 6 и выше. До Android 6 разрешение предоставлялось автоматически. Вы можете обратиться к stackoverflow.com/a/40558918/7727011. - person brijexecon; 08.05.2018
comment
Что такое пдус? @brijexecon - person Ravi Vaniya; 07.06.2018
comment
Не вдаваясь в подробности, просто его флаг, который вы используете при получении сообщений. Как вы можете видеть, он возвращает массив объектов, что означает, что если вы получаете sms с большим телом, вы будете получать части сообщения в каждом индексе. - person brijexecon; 11.06.2018
comment
Сейчас это решение устарело. Вы должны использовать SMS Retriever API. Подробные инструкции можно найти здесь: developers.google.com/identity/sms-retriever/overview. - person Tsiogas P.; 22.11.2018

Вы можете попробовать использовать простую библиотеку, например

После установки через gradle и добавления разрешений инициируйте SmsVerifyCatcher в методе, подобном действию onCreate:

    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
    }
});

Кроме того, переопределите методы жизненного цикла активности:

  @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;
}
person smy    schedule 15.09.2016
comment
вероятно, лучшее решение, и легкое тоже. - person TharakaNirmana; 14.03.2017
comment
Лучшее решение. Большое спасибо - person Christopher M.; 13.02.2018
comment
что такое parseCode здесь - person ; 22.05.2018
comment
@angelina Здесь вы получаете полный текст сообщения в onSmsCatch. Поэтому вам нужно проанализировать текст сообщения, чтобы получить OTP. - person Rupam Das; 14.06.2018
comment
Но сейчас это не работает, потому что Google отключил использование READ SMS и ReCIVE SMS. Это не работает на моей стороне' - person Rahul Kushwaha; 06.02.2019
comment
требуется РАЗРЕШЕНИЕ СМС Без разрешения смс это не работает - person Hitesh Kushwah; 19.02.2019
comment
Это решение теперь устарело Google. Вы должны использовать SMS Retriever API. Это требует некоторых изменений как на мобильной стороне, так и на стороне сервера. Подробные инструкции можно найти здесь: developer.google.com/identity/sms-retriever/overview. - person shaktisinghmoyal; 21.11.2019

Поскольку Google ограничил использование разрешения READ_SMS, здесь есть решение без разрешения READ_SMS.

API ретривера SMS

Основная функция заключается в том, чтобы избежать использования критического разрешения 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
    }
});

Код широковещательного приемника

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;
            }
        }
    }
}

Последний шаг. Зарегистрируйте этот приемник в своем манифесте

<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>

Ваше SMS должно быть таким, как показано ниже.

<#> Your OTP code is: 6789
QWsa8754qw2 

Здесь 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"
person Shabbir Dhangot    schedule 02.02.2019
comment
Код не работает, если SMS приходит с идентификатора отправителя, он работает нормально, если он приходит с мобильного номера. Есть идеи, что может быть не так? - person Neo; 07.08.2019
comment
Это не проблема. SMS Retriver проверяет только приведенный выше шаблон и проверяет, соответствует ли хэш вашему приложению или нет. Если вы проверите хэш среды разработки, он будет другим. К вашему сведению: я пробовал и идентификатор отправителя, и мобильный телефон. Я предполагаю, что идентификатор отправителя похож на TM-ABCDEF. Это работает для меня. - person Shabbir Dhangot; 08.08.2019
comment
Обновление библиотеки решило мою проблему, спасибо за ответ @Shabbir :) - person Neo; 10.08.2019
comment
как извлечь код, я не понял, можете ли вы объяснить больше - person MustafaShaikh; 04.11.2019
comment
@MustafaShaikh для извлечения кода вам нужно применить некоторую логику, чтобы найти код в сообщении. Этот API извлечет SMS и передаст его вам. Что я сделал. Я разделил смс пробелом и проверил 7-ю позицию в разделенной строке. Поскольку мое сообщение предопределено, оно всегда будет на 7-й позиции. - person Shabbir Dhangot; 04.11.2019
comment
Есть ли способ скрыть хеш-ключ в теле сообщения? - person George Thomas; 02.01.2020
comment
Не нужно. Нет смысла скрывать это. Никакое другое приложение не может прочитать ваше OTP-сообщение как хэш, созданный из ваших сертификатов подписи. Так что не беспокойтесь об этом. - person Shabbir Dhangot; 02.01.2020
comment
Не работает после выпуска apk в плеймаркете. Тот же apk, работающий до релиза. - person Kalu Khan Luhar; 12.02.2020
comment
Hashkey отличается для производства, поскольку ваш производственный jks отличается. Вам нужно сгенерировать свой хэш с помощью производственных jks и использовать его для добавления в сообщение. - person Shabbir Dhangot; 12.02.2020
comment
Привет @Shabbir, я протестировал рабочий APK, он работал нормально, но после выпуска приложения в магазине игр он не получает данные SMS. Я использую этот file также генерирует хеш для производства. Текст SMS не включает ‹#›. Может это проблема? - person Kalu Khan Luhar; 12.02.2020
comment
Попробуйте добавить # перед началом сообщения. В моем случае я добавляю # и все работает нормально. - person Shabbir Dhangot; 13.02.2020
comment
@ShabbirDhangot привет. как мы можем создать суровый код. это создается вручную или для этого тоже нужно писать какой-то код? - person vijju; 09.04.2021
comment
@vijju не нужно писать код. Вам нужно сгенерировать его, выполнив шаги по ссылке. developers.google.com/identity/sms-retriever/verify - person Shabbir Dhangot; 09.04.2021

Я реализовал что-то из того такого. Но вот что я сделал, когда приходит сообщение: я получаю только шестизначный код, связываю его с намерением и отправляю в действие или фрагмент, который в нем нуждается, и проверяю код. В примере показано, как уже получить смс. Посмотрите на приведенный ниже код, чтобы проиллюстрировать, как отправлять сообщения с помощью LocalBrodcastManager. Если ваше сообщение содержит больше текста, например приветствия, стандартизируйте его, чтобы вам было удобнее. Например, «Ваш код подтверждения: 84HG73», вы можете создать шаблон regex, подобный этому ([0-9]){2}([A-Z]){2}([0-9]){2}, что означает два целых числа, две [заглавные] буквы и два целых числа. Удачи!

После удаления всей ненужной информации из сообщения

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

И Фрагмент/Действие, получающее его

@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);
}

И код, предназначенный для обработки собранной вами полезной нагрузки

 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
        }
    }
};

Это немного помогает. Я сделал это лучше, используя обратные вызовы.

person Tonespy    schedule 10.08.2015
comment
разве вы не должны переопределять onPause() вместо onDestroy()? - person galdin; 06.03.2016
comment
Это зависит от того, как вы хотите его использовать. Если Fragment или Activity всегда активны, оставьте их в onPause, но в моем случае, когда мне это нужно только один раз, я могу поместить их в onPause или onDestroy, так как оба будут вызываться в любом случае - person Tonespy; 06.03.2016
comment
Извините, я был недостаточно ясен. Вызов onDestroy() не гарантируется. Следует использовать onStop() или onPause() в зависимости от контекста. Верно? - person galdin; 06.03.2016

Извините за поздний ответ, но все же решил опубликовать свой ответ, если он поможет. Он работает для 6-значного одноразового пароля.

    @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}";

Для прослушивателя SMS можно следовать классу ниже

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;
    }
person Raghav Sharma    schedule 17.02.2017

С помощью SMS Retriever API можно прочитать OTP, не объявляя android.permission.READ_SMS.

  1. Запустите поиск SMS
    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. Получать сообщения через рассылку
    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. Отправьте одноразовый код из проверочного сообщения на свой сервер

Убедитесь, что формат вашего SMS соответствует указанному ниже:

<#> Your ExampleApp code is: 123ABC78
fBzOyyp9h6L
  1. Быть не длиннее 140 байт
  2. Начните с префикса ‹#>
  3. Завершите 11-символьной хэш-строкой, которая идентифицирует ваше приложение.

    Вы можете вычислить хэш приложения с помощью следующего кода:

    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;
        }
    }       
    

Требуемый Gradle:

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

Ссылки:
https://developers.google.com/identity/sms-retriever/overview
https://developers.google.com/identity/sms-retriever/request
https://developers.google.com/identity/sms-retriever/verify

person Dhaval Patel    schedule 26.12.2018

Да, теперь это возможно и в браузерах. Chrome выпускает эту функцию в версии 84 и выше. С помощью WEBOTP API мы можем обнаруживать OTP в Интернете для мобильных устройств.

Вот интегрированный код Web-OTP с приложениями Angular PWA: https://github.com/Rohit3230/webOtpAutoReadByAngular

Перейдите к рабочему URL-адресу углового приложения PWA. https://rohit3230.github.io/webOtpAutoReadByAngular/

person Rohit Kumar    schedule 23.12.2020

Я знаю, что уже поздно, но чтобы это было проще для других, вот решение, которое я написал ранее. Воспользуйтесь ссылкой на эту библиотеку. Вам не придется ни с чем возиться. После добавления зависимости просто используйте этот метод.

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()

            }
        })

Вам нужно будет передать контекст, строку поиска вашего сообщения, например

Вы ожидаете OTP в своем сообщении. Пропустите OTP и Time Out for Как долго вы хотите слушать OTP и все. Вы получите свое сообщение в простом формате в OnRecieved CallBack.

person Intsab Haider    schedule 17.05.2021
comment
Это не работает, проверено как с числовым, так и с сопоставлением строк - person Mubashir Murtaza; 31.05.2021
comment
Можете ли вы поделиться кодом? или ошибка, с которой вы столкнулись? Вы добавили разрешения на стороне клиента? - person Intsab Haider; 31.05.2021
comment
я получаю сообщение от firebase, даже собственная функция firebase не читает мое сообщение, поэтому мне нужно выполнить работу, теперь я использую другую библиотеку и ее работу - person Mubashir Murtaza; 01.06.2021

person    schedule
comment
Хотя этот фрагмент кода может решить вопрос, включение объяснения помогает улучшить качество вашего ответа. Помните, что вы отвечаете на вопрос для будущих читателей, и эти люди могут не знать причин вашего предложения кода. - person Stefan Crain; 23.04.2018