Android: escuche los mensajes SMS entrantes
Estoy intentando crear una aplicación para monitorear los mensajes SMS entrantes e iniciar un programa a través de SMS entrantes, también debería leer el contenido del SMS.
Flujo de trabajo:
- SMS enviado al dispositivo Android
- Aplicación autoejecutable
- Leer la información del SMS
public class SmsListener extends BroadcastReceiver{
private SharedPreferences preferences;
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Bundle bundle = intent.getExtras(); //---get the SMS message passed in---
SmsMessage[] msgs = null;
String msg_from;
if (bundle != null){
//---retrieve the SMS message received---
try{
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for(int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
msg_from = msgs[i].getOriginatingAddress();
String msgBody = msgs[i].getMessageBody();
}
}catch(Exception e){
// Log.d("Exception caught",e.getMessage());
}
}
}
}
}
Nota: En su archivo de manifiesto agregue BroadcastReceiver-
<receiver android:name=".listener.SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Agregue este permiso:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Tenga en cuenta que en algunos dispositivos su código no funcionará sin android:priority="1000" en el filtro de intención:
<receiver android:name=".listener.SmsListener">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Y aquí hay algunas optimizaciones:
public class SmsListener extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
for (SmsMessage smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
String messageBody = smsMessage.getMessageBody();
}
}
}
}
Nota :
El valor debe ser un número entero, como "100". Los números más altos tienen una mayor prioridad. El valor predeterminado es 0. El valor debe ser mayor que -1000 y menor que 1000.
Aquí hay un enlace.
@Mike M. y yo encontramos un problema con la respuesta aceptada (vea nuestros comentarios):
Básicamente, no tiene sentido pasar por el bucle for si no estamos concatenando el mensaje multiparte cada vez:
for (int i = 0; i < msgs.length; i++) {
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
msg_from = msgs[i].getOriginatingAddress();
String msgBody = msgs[i].getMessageBody();
}
Tenga en cuenta que simplemente configuramos msgBody
el valor de cadena de la parte respectiva del mensaje sin importar en qué índice estemos, lo que hace que todo el objetivo de recorrer las diferentes partes del mensaje SMS sea inútil, ya que simplemente se configurará en el mismo último valor del índice. En su lugar deberíamos usar +=
, o como señaló Mike StringBuilder
:
Considerándolo todo, así es como se ve mi código de recepción de SMS:
if (myBundle != null) {
Object[] pdus = (Object[]) myBundle.get("pdus"); // pdus is key for SMS in bundle
//Object [] pdus now contains array of bytes
messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]); //Returns one message, in array because multipart message due to sms max char
Message += messages[i].getMessageBody(); // Using +=, because need to add multipart from before also
}
contactNumber = messages[0].getOriginatingAddress(); //This could also be inside the loop, but there is no need
}
Simplemente publico esta respuesta en caso de que alguien más tenga la misma confusión.
La respuesta aceptada es correcta y funciona en versiones anteriores de Android donde el sistema operativo Android solicita permisos durante la instalación de la aplicación. Sin embargo, en versiones más nuevas de Android no funciona de inmediato porque el sistema operativo Android más nuevo solicita permisos durante el tiempo de ejecución cuando la aplicación requiere esa función. . Por lo tanto, para recibir SMS en versiones más nuevas de Android utilizando la técnica mencionada en la respuesta aceptada, el programador también debe implementar un código que verificará y solicitará permisos al usuario durante el tiempo de ejecución. En este caso, la funcionalidad/código de verificación de permisos se puede implementar en onCreate() de la primera actividad de la aplicación. Simplemente copie y pegue los siguientes dos métodos en su primera actividad y llame al método checkForSmsReceivePermissions() al final de onCreate().
void checkForSmsReceivePermissions(){
// Check if App already has permissions for receiving SMS
if(ContextCompat.checkSelfPermission(getBaseContext(), "android.permission.RECEIVE_SMS") == PackageManager.PERMISSION_GRANTED) {
// App has permissions to listen incoming SMS messages
Log.d("adnan", "checkForSmsReceivePermissions: Allowed");
} else {
// App don't have permissions to listen incoming SMS messages
Log.d("adnan", "checkForSmsReceivePermissions: Denied");
// Request permissions from user
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.RECEIVE_SMS}, 43391);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 43391){
if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.d("adnan", "Sms Receive Permissions granted");
} else {
Log.d("adnan", "Sms Receive Permissions denied");
}
}
}
Si alguien se refiere a cómo hacer la misma función (leer OTP usando SMS recibidos) en Xamarin Android como yo:
Agregue este código a su archivo AndroidManifest.xml:
<receiver android:name=".listener.BroadcastReveiverOTP"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.BROADCAST_SMS" /> <uses-permission android:name="android.permission.READ_SMS" />
Luego crea tu clase BroadcastReveiver en tu proyecto de Android.
[BroadcastReceiver(Enabled = true)] [IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED" }, Priority = (int)IntentFilterPriority.HighPriority)] public class BroadcastReveiverOTP : BroadcastReceiver { public static readonly string INTENT_ACTION = "android.provider.Telephony.SMS_RECEIVED"; protected string message, address = string.Empty; public override void OnReceive(Context context, Intent intent) { if (intent.HasExtra("pdus")) { var smsArray = (Java.Lang.Object[])intent.Extras.Get("pdus"); foreach (var item in smsArray) { var sms = SmsMessage.CreateFromPdu((byte[])item); address = sms.OriginatingAddress; if (address.Equals("NotifyDEMO")) { message = sms.MessageBody; string[] pin = message.Split(' '); if (!string.IsNullOrWhiteSpace(pin[0])) { // NOTE : Here I'm passing received OTP to Portable Project using MessagingCenter. So I can display the OTP in the relevant entry field. MessagingCenter.Send<object, string>(this,MessengerKeys.OnBroadcastReceived, pin[0]); } } } } } }
Registre esta clase BroadcastReceiver en su clase MainActivity en el Proyecto Android:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity { // Initialize your class private BroadcastReveiverOTP _receiver = new BroadcastReveiverOTP (); protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); global::Xamarin.Forms.Forms.Init(this, bundle); LoadApplication(new App()); // Register your receiver : RegisterReceiver(_receiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED")); } }