J'essaie de créer une application pour surveiller les messages entrants SMS, et de lancer un programme via un SMS entrant. Il doit également lire le contenu du SMS.
Flux de travail:
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());
}
}
}
}
}
Remarque: dans votre fichier de manifeste, ajoutez le BroadcastReceiver-
<receiver Android:name=".listener.SmsListener">
<intent-filter>
<action Android:name="Android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Ajouter cette permission:
<uses-permission Android:name="Android.permission.RECEIVE_SMS" />
Notez que sur certains appareils, votre code ne fonctionnera pas sans Android: priority = "1000" dans le filtre d'intention:
<receiver Android:name=".listener.SmsListener">
<intent-filter Android:priority="1000">
<action Android:name="Android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Et voici quelques optimisations:
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();
}
}
}
}
Remarque :
La valeur doit être un entier, tel que "100". Les nombres plus élevés ont une priorité plus élevée. La valeur par défaut est 0. La valeur doit être supérieure à -1000 et inférieure à 1000.
@ Mike M. et moi avons trouvé un problème avec la réponse acceptée (voir nos commentaires):
Fondamentalement, il est inutile de passer par la boucle for si nous ne concaténons pas le message en plusieurs parties à chaque fois:
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();
}
Notez que nous venons de définir msgBody
sur la valeur de chaîne de la partie respective du message, quel que soit l'index sur lequel nous nous trouvons, ce qui rend tout le point de la boucle à travers les différentes parties du message SMS inutile, car il sera simplement mis à la toute dernière valeur d'index. Au lieu de cela, nous devrions utiliser +=
, ou comme Mike l'a noté, StringBuilder
:
Au total, voici à quoi ressemble mon code de réception 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
}
Il suffit de mettre cette réponse au cas où quelqu'un aurait la même confusion.
C'est ce que j'ai utilisé!
public class SMSListener extends BroadcastReceiver {
// Get the object of SmsManager
final SmsManager sms = SmsManager.getDefault();
String mobile,body;
public void onReceive(Context context, Intent intent) {
// Retrieves a map of extended data from the intent.
final Bundle bundle = intent.getExtras();
try {
if (bundle != null) {
final Object[] pdusObj = (Object[]) bundle.get("pdus");
for (int i = 0; i < pdusObj.length; i++) {
SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
String phoneNumber = currentMessage.getDisplayOriginatingAddress();
String senderNum = phoneNumber;
String message = currentMessage.getDisplayMessageBody();
mobile=senderNum.replaceAll("\\s","");
body=message.replaceAll("\\s","+");
Log.i("SmsReceiver", "senderNum: "+ senderNum + "; message: " + body);
// Show Alert
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context,
"senderNum: "+ mobile+ ", message: " + message, duration);
toast.show();
} // end for loop
} // bundle is null
} catch (Exception e) {
Log.e("SmsReceiver", "Exception smsReceiver" +e);
}
}
}
Si quelqu'un fait la même chose (lecture d'OTP avec SMS reçus) sur Xamarin Android comme moi:
Ajoutez ce code à votre fichier 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" />
Créez ensuite votre classe BroadcastReveiver dans votre projet 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]);
}
}
}
}
}
}
Enregistrez cette classe BroadcastReceiver dans votre classe MainActivity sur Android Project:
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"));
}
}
Si vous souhaitez gérer l’intention d’une activité ouverte, vous pouvez utiliser PendintIntent (procédez comme suit):
public class SMSReciver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
try {
if (bundle != null) {
final Object[] pdusObj = (Object[]) bundle.get("pdus");
for (int i = 0; i < pdusObj.length; i++) {
SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) pdusObj[i]);
String phoneNumber = currentMessage.getDisplayOriginatingAddress();
String senderNum = phoneNumber;
String message = currentMessage.getDisplayMessageBody();
try {
if (senderNum.contains("MOB_NUMBER")) {
Toast.makeText(context,"",Toast.LENGTH_SHORT).show();
Intent intentCall = new Intent(context, MainActivity.class);
intentCall.putExtra("message", currentMessage.getMessageBody());
PendingIntent pendingIntent= PendingIntent.getActivity(context, 0, intentCall, PendingIntent.FLAG_UPDATE_CURRENT);
pendingIntent.send();
}
} catch (Exception e) {
}
}
}
} catch (Exception e) {
}
}
}
manifeste:
<activity Android:name=".MainActivity"
Android:launchMode="singleTask"/>
<receiver Android:name=".SMSReciver">
<intent-filter Android:priority="1000">
<action Android:name="Android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
onNewIntent:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Toast.makeText(this, "onNewIntent", Toast.LENGTH_SHORT).show();
onSMSReceived(intent.getStringExtra("message"));
}
autorisations:
<uses-permission Android:name="Android.permission.RECEIVE_SMS" />
<uses-permission Android:name="Android.permission.READ_SMS" />
<uses-permission Android:name="Android.permission.SEND_SMS" />
implémentation broadcast sur Kotlin:
private class SmsListener : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "SMS Received!")
val txt = getTextFromSms(intent?.extras)
Log.d(TAG, "message=" + txt)
}
private fun getTextFromSms(extras: Bundle?): String {
val pdus = extras?.get("pdus") as Array<*>
val format = extras.getString("format")
var txt = ""
for (pdu in pdus) {
val smsmsg = getSmsMsg(pdu as ByteArray?, format)
val submsg = smsmsg?.displayMessageBody
submsg?.let { txt = "$txt$it" }
}
return txt
}
private fun getSmsMsg(pdu: ByteArray?, format: String?): SmsMessage? {
return when {
SDK_INT >= Build.VERSION_CODES.M -> SmsMessage.createFromPdu(pdu, format)
else -> SmsMessage.createFromPdu(pdu)
}
}
companion object {
private val TAG = SmsListener::class.Java.simpleName
}
}
Remarque: dans votre fichier de manifeste, ajoutez le BroadcastReceiver-
<receiver Android:name=".listener.SmsListener">
<intent-filter>
<action Android:name="Android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Ajouter cette permission:
<uses-permission Android:name="Android.permission.RECEIVE_SMS" />