Android - Gelen SMS Mesajlarını Dinle


155

Gelen SMS mesajlarını izlemek için bir uygulama oluşturmaya ve gelen SMS ile bir program başlatmaya çalışıyorum, ayrıca SMS'den içeriği okumalıdır.

İş Akışı:

  • Android cihaza SMS gönderildi
  • kendi kendine yürütülebilir uygulama
  • SMS bilgilerini okuyun

1
SMS göndermek için bir uygulama oluşturmak biliyorum, ama burada SMS bilgi almak ve SQLite Veritabanı'na kaydetmek bir SMS uygulaması oluşturmak gerekir ..... Nasıl böyle bir uygulama geliştirebilirim
iShader

@ iShader umarım uygulama oluşturmada başarılı oldunuz, sadece cihazı ve sunucuyu msj / s senkronize etmeyi nasıl başardığınızı bilmek istedim
John x

Yanıtlar:


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

Not: Manifest dosyanıza BroadcastReceiver-

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

Bu izni ekle:

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

2
Neden ikincil alıcı kullandığınızı açıklayabilir misiniz?
WindRider

2
@VineetShukla pdus nedir açıklayabilir misiniz ??
TheGraduateGuy

11
sabit kodlu yerine Intents.SMS_RECEIVED_ACTION kullanın.
Ahmad Kayyali

6
Yukarıdaki yorum doğru değil. Herhangi bir uygulama SMS_RECEIVEDyayını 4.4+ sürümünde alabilir ve şimdi bu yayın iptal edilemediğinden, önceki sürümlerden daha kesin.
Mike

3
@RuchirBaronia Çok parçalı mesajlar. Tek bir SMS mesajının karakter sınırı vardır (kullandığınız karakter kümesine bağlı olarak değişir, ancak ortak sınırlar 70, 140, 160 karakterdir). Bir mesaj bu sınırı aşarsa, birden fazla mesaja, parçaya bölünebilir. Bu dizi, iletinin tamamını almak için birleştirmeniz gereken parça dizisidir. Alıcınız bir seferde yalnızca bir tam mesaj alacaktır; sadece birden fazla kısımda olabilir.
Mike M.16

65

Bazı cihazlarda kodunuzun android olmadan çalışmadığını unutmayın : niyet filtresinde öncelik = "1000" :

<receiver android:name=".listener.SmsListener">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

İşte bazı optimizasyonlar:

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

Not :
Değer, "100" gibi bir tam sayı olmalıdır. Daha yüksek sayıların önceliği daha yüksektir. Varsayılan değer 0'dır. Değer -1000'den büyük ve 1000'den küçük olmalıdır.

İşte bir bağlantı.


30
Bu yanıt daha zarif olabilir, ancak API 19 gerektirir.
baekacaek

10
Göre , bu , android:prioritydaha yüksek olamaz 1000(ya da daha az -1000).
craned

2
Android 5.1 ile Xiaomi Redmi Note 3 Pro üzerinde çalışmaz. Herkes bu çözümü sağlıyor, ama benim için işe yaramıyor gibi görünüyor.
15'te Sermilion

Manifest dosyasına <alıcı ... işaretlemesi nerede eklenir?
John Ward

3
@Mermilion Mobil uygulama yöneticisinde SMS okuma iznini manuel olarak izin vermelisiniz.
Sanjay Kushwah

6

@Mike M. ve ben kabul edilen cevapla ilgili bir sorun bulduk (yorumlarımıza bakın):

Temel olarak, her seferinde çok parçalı mesajı birleştirmiyorsak for döngüsünün içinden geçmenin bir anlamı yoktur:

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

msgBodyHangi dizinde olursak olalım, mesajın ilgili kısmının dize değerine ayarladığımıza dikkat edin , bu da SMS mesajının farklı bölümleri arasında döngü noktasını işe yaramaz hale getirir, çünkü sadece son dizin değeri. Bunun yerine +=, Mike'ın belirttiği gibi kullanmalıyız StringBuilder:

Sonuçta, SMS alma kodum şöyle görünüyor:

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
}

Başka birinin aynı karışıklığa sahip olması durumunda bu yanıtı ortaya koymak.


4

Kullandığım bu!

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

        }
    }
}

2

Açılmış etkinliğin amacını ele almak istiyorsanız, PendintIntent'i kullanabilirsiniz (Aşağıdaki adımları tamamlayın):

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

belirgin:

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

            }

izinleri:

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

Google Play Store için Google yöneticileri, RECEIVE_SMS izninin (bahsettiğiniz öğreticide) tehlikeli olduğunu düşünmektedir. Sonuç olarak, izni içeren bir uygulama reddedilecektir. Ardından geliştiricinin onay için Google Play yöneticilerine bir form göndermesi gerekir. Diğer geliştiriciler, sürecin haftalar süren geri bildirimlerle ve açıklama veya genel geri bildirim olmadan doğrudan reddetmelerle korkunç olduğunu belirtti. Nasıl önleneceğine dair bir fikrin var mı?
AJW

2

Benim gibi Xamarin Android'de aynı özelliğin nasıl yapılacağından bahseden (alınan SMS kullanarak OTP'yi okuma):

  1. Bu kodu AndroidManifest.xml dosyanıza ekleyin:

    <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" />
  2. Ardından Android Projenizde BroadcastReveiver sınıfınızı oluşturun.

    [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]);
                            }
                            }
                    }
                }
            }
    }
  3. Bu BroadcastReceiver sınıfını Android Project'te MainActivity sınıfınıza kaydedin:

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

"Android.permission.BROADCAST_SMS" dosyasının yalnızca sistem uygulamalarına verildiğini söyleyen bir derleyici hatası aldınız.
committedandroider

2

@Vineet Shukla (kabul edilen cevap) ve @Ruchir Baronia'ya (sorunu kabul edilen cevapta buldu) teşekkür ederim, aşağıdaki Kotlinsürüm:

İzin ekle:

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

Android'de BroadcastReceiver'ı kaydettir

<receiver
    android:name=".receiver.SmsReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter android:priority="2332412">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

BroadcastReceiver için uygulama ekle:

class SmsReceiver : BroadcastReceiver() {
    private var mLastTimeReceived = System.currentTimeMillis()

    override fun onReceive(p0: Context?, intent: Intent?) {
        val currentTimeMillis = System.currentTimeMillis()
        if (currentTimeMillis - mLastTimeReceived > 200) {
            mLastTimeReceived = currentTimeMillis

            val pdus: Array<*>
            val msgs: Array<SmsMessage?>
            var msgFrom: String?
            var msgText: String?
            val strBuilder = StringBuilder()
            intent?.extras?.let {
                try {
                    pdus = it.get("pdus") as Array<*>
                    msgs = arrayOfNulls(pdus.size)
                    for (i in msgs.indices) {
                        msgs[i] = SmsMessage.createFromPdu(pdus[i] as ByteArray)
                        strBuilder.append(msgs[i]?.messageBody)
                    }

                    msgText = strBuilder.toString()
                    msgFrom = msgs[0]?.originatingAddress

                    if (!msgFrom.isNullOrBlank() && !msgText.isNullOrBlank()) {
                        //
                        // Do some thing here
                        //
                    }
                } catch (e: Exception) {
                }
            }
        }
    }
}

Bazen olay iki kez tetiklenir, bu yüzden mLastTimeReceived = System.currentTimeMillis()


1

Kotlin'de yayın uygulaması:

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

Not: Manifest dosyanıza BroadcastReceiver-

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

Bu izni ekle:

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

1

Kabul edilen cevap doğrudur ve Android işletim sisteminin uygulama yüklemesinde izin istediği Android'in eski sürümlerinde çalışır, ancak daha yeni Android işletim sistemi, uygulama bu özelliği gerektirdiğinde çalışma zamanı sırasında izin ister, . Bu nedenle, kabul edilen yanıt programlayıcısında bahsedilen tekniği kullanarak Android'in daha yeni sürümlerinde SMS almak için, çalışma zamanı sırasında kullanıcıdan izinleri kontrol edecek ve isteyecek kod da uygulamalıdır. Bu durumda, uygulamanın ilk etkinliğinin onCreate () öğesinde izin denetimi işlevselliği / kodu uygulanabilir. İlk etkinliğinizde aşağıdaki iki yöntemi kopyalayıp yapıştırmanız ve onCreate () öğesinin sonunda checkForSmsReceivePermissions () yöntemini çağırmanız yeterlidir.

    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");
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.