Je travaille sur une application Android, sur laquelle le serveur envoie un OTP et l'utilisateur doit entrer ce OTP dans l'application pour s'inscrire pour mon application. Ce que je veux, c'est que mon application soit capable de lire automatiquement l'OTP envoyé par le serveur. Comment puis-je atteindre cet objectif? Toute aide ou orientation à cet égard serait hautement appréciée.
Je vous recommanderai de ne pas utiliser de bibliothèques tierces pour la récupération automatique d'OTP à partir de la boîte de réception SMS . Cela peut être fait facilement si vous avez une connaissance de base de Broadcast Receiver et de son fonctionnement . Essayez juste de suivre approche:
Étape 1) Créer une interface unique, à savoir SmsListner
package com.wnrcorp.reba;
public interface SmsListener{
public void messageReceived(String messageText);}
Étape 2) Créer un récepteur de radiodiffusion unique, à savoir 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;
}
}
Étape 3) Ajouter un auditeur i.e, le récepteur de radiodiffusion dans le fichier manifeste Android
<receiver Android:name=".SmsReceiver">
<intent-filter>
<action Android:name="Android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
et ajouter la permission
<uses-permission Android:name="Android.permission.RECEIVE_SMS"/>
Final Step 4) L'activité dans laquelle vous allez chercher automatiquement un otp quand il est reçu dans la boîte de réception. Dans mon cas, je vais chercher otp et mets le champ 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();
}
});
}
}
Fichier de mise en forme pour 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>
Captures d'écran de l'activité de vérification d'OTP où vous extrayez d'OTP sous la forme de messages Reçus
Vous pouvez essayer d’utiliser une simple bibliothèque like
Après l'installation via gradle et l'ajout d'autorisations, démarrez SmsVerifyCatcher selon une méthode similaire à l'activité 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
}
});
En outre, substituez les méthodes de cycle de vie d'activité:
@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;
}
Cela m'a aidé et a également travaillé pour moi:
http://androiddhina.blogspot.in/2015/06/reading-incoming-message-automatically-to-verify-OTP.html
Veuillez aussi n'oubliez pas de faire static
à votre EditText
à partir de votre Activity/Fragment
J'ai mis en œuvre quelque chose de ce genre. Mais voici ce que j'ai fait lorsque le message est arrivé: je récupère uniquement le code à six chiffres, le regroupe dans une intention et l'envoie à l'activité ou au fragment en ayant besoin et vérifie le code. L'exemple vous montre déjà comment obtenir le sms. Consultez le code ci-dessous pour savoir comment envoyer à l'aide de LocalBrodcastManager et si votre message contient plus de textes, par exemple, Salutations E.g, faites-en la normalisation pour mieux vous aider. E.g "Votre code de vérification est: 84HG73" vous pouvez créer un motif regex comme ce ([0-9]){2}([A-Z]){2}([0-9]){2}
qui signifie deux ints, deux [majuscules] et deux ints. Bonne chance!
Après avoir supprimé toutes les informations inutiles du message
Intent intent = new Intent("AddedItem");
intent.putExtra("items", code);
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
Et le fragment/activité qui le reçoit
@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);
}
Et le code destiné à gérer la charge utile que vous avez collectée
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
}
}
};
Est-ce que ça aide un peu? Je l'ai fait mieux en utilisant Callbacks
Désolé pour la réponse tardive mais toujours envie de poster ma réponse si cela aide. Il fonctionne pour 6 chiffres 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}";
Pour l'auditeur SMS, on peut suivre la classe ci-dessous
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;
}
Avec l’API SMS Retriever, il est possible de lire le protocole OTP sans déclarer Android.permission.READ_SMS
.
- Démarrer le SMS récupérateur
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")
}
}
- Recevoir des messages via diffusion
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>
- Envoyez le code à usage unique du message de vérification à votre serveur
Assurez-vous que votre format SMS est exactement comme ci-dessous:
<#> Your ExampleApp code is: 123ABC78
fBzOyyp9h6L
Terminez avec une chaîne de hachage de 11 caractères identifiant votre application.
Vous pouvez calculer le hachage de l'application avec le code suivant:
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;
}
}
Niveau requis:
implementation "com.google.Android.gms:play-services-auth-api-phone:16.0.0"
Références:
https://developers.google.com/identity/sms-retriever/overview
https://developers.google.com/identity/sms-retriever/request
https://developers.google.com/identity/sms-retriever/verify
Comme Google a restreint l'utilisation de l'autorisation READ_SMS, la solution est sans autorisation READ_SMS.
La fonction de base consiste à éviter d'utiliser la permission critique Android READ_SMS et à accomplir la tâche à l'aide de cette méthode. Coup sont les étapes dont vous aviez besoin.
Post Envoi d'OTP au numéro d'utilisateur, consultez SMS API Retriever capable de recevoir un message ou non
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
}
});
Code du récepteur de radiodiffusion
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;
}
}
}
}
Dernière étape. Enregistrez ce récepteur dans votre manifeste
<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>
Votre SMS doit être comme ci-dessous.
<#> Your OTP code is: 6789
QWsa8754qw2
QWsa8754qw2 représente ici votre propre code de hachage à 11 caractères. Suivez ceci link
Pour importer com.google.Android.gms.auth.api.phone.SmsRetriever
, n'oubliez pas d'ajouter cette ligne à votre application build.gradle:
implementation "com.google.Android.gms:play-services-auth-api-phone:16.0.0"