Wie kann ich in Android programmgesteuert SMS-Nachrichten vom Gerät lesen?

249

Ich möchte die SMS-Nachrichten vom Gerät abrufen und anzeigen.

Manoj Perumarath
quelle
@ David Freitas Vertrauenswürdiger Link +1
Shahzad Imam
3
@ DavidFreitas dieser Link funktioniert nicht, können Sie bitte den neuesten Link teilen?
Khobaib
3
@ Khobaib, wie immer sind die Dinge im Internet flüchtig. Ich habe eine Kopie auf archive.org stackoverflow.com/a/19966227/40961 gefunden , Gott sei Dank für sie (ich habe kürzlich gespendet, um sie am Laufen zu halten). Wir sollten jedoch in Betracht ziehen, den Inhalt der Seite von web.archive.org/web/20121022021217/http://mobdev.olin.edu/… in eine Markdown-Syntax in einer Antwort auf diese Frage zu konvertieren . Wahrscheinlich eine Stunde Arbeit.
David d C e Freitas

Antworten:

157

Verwenden Sie Content Resolver ( "content: // sms / inbox" ), um SMS zu lesen, die sich im Posteingang befinden.

// public static final String INBOX = "content://sms/inbox";
// public static final String SENT = "content://sms/sent";
// public static final String DRAFT = "content://sms/draft";
Cursor cursor = getContentResolver().query(Uri.parse("content://sms/inbox"), null, null, null, null);

if (cursor.moveToFirst()) { // must check the result to prevent exception
    do {
       String msgData = "";
       for(int idx=0;idx<cursor.getColumnCount();idx++)
       {
           msgData += " " + cursor.getColumnName(idx) + ":" + cursor.getString(idx);
       }
       // use msgData
    } while (cursor.moveToNext());
} else {
   // empty box, no SMS
}

Bitte fügen Sie die READ_SMS- Berechtigung hinzu.

Ich hoffe, es hilft :)

Suryavel TR
quelle
7
Danke dir! Sie haben "getColumnName" falsch geschrieben, ansonsten funktioniert es wie ein Zauber. Oh, und wenn jemand dies verwenden wird, vergessen Sie nicht, die Berechtigung android.permission.READ_SMS hinzuzufügen.
QWERTY
1
Vielen Dank. Ich habe es geändert :)
Suryavel TR
5
Verwendet dies auch die undokumentierte API, die @CommonsWare in seinem Kommentar zur akzeptierten Antwort angegeben hat?
Krishnabhadra
1
Beachtung! Verpassen Sie nicht moveToFirstwie ich.
Alexandr Priymak
4
@Krishnabhadra Ja. Es wird der undokumentierte Inhaltsanbieter "content: // sms / inbox" verwendet.
pm_labs
79
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        final String myPackageName = getPackageName();
        if (!Telephony.Sms.getDefaultSmsPackage(this).equals(myPackageName)) {

            Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
            intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, myPackageName);
            startActivityForResult(intent, 1);
        }else {
            List<Sms> lst = getAllSms();
        }
    }else {
        List<Sms> lst = getAllSms();
    }

Legen Sie die App als Standard-SMS-App fest

    @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
    if (resultCode == RESULT_OK) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            final String myPackageName = getPackageName();
            if (Telephony.Sms.getDefaultSmsPackage(mActivity).equals(myPackageName)) {

                List<Sms> lst = getAllSms();
            }
        }
    }
}
}

Funktion zum Abrufen von SMS

public List<Sms> getAllSms() {
    List<Sms> lstSms = new ArrayList<Sms>();
    Sms objSms = new Sms();
    Uri message = Uri.parse("content://sms/");
    ContentResolver cr = mActivity.getContentResolver();

    Cursor c = cr.query(message, null, null, null, null);
    mActivity.startManagingCursor(c);
    int totalSMS = c.getCount();

    if (c.moveToFirst()) {
        for (int i = 0; i < totalSMS; i++) {

            objSms = new Sms();
            objSms.setId(c.getString(c.getColumnIndexOrThrow("_id")));
            objSms.setAddress(c.getString(c
                    .getColumnIndexOrThrow("address")));
            objSms.setMsg(c.getString(c.getColumnIndexOrThrow("body")));
            objSms.setReadState(c.getString(c.getColumnIndex("read")));
            objSms.setTime(c.getString(c.getColumnIndexOrThrow("date")));
            if (c.getString(c.getColumnIndexOrThrow("type")).contains("1")) {
                objSms.setFolderName("inbox");
            } else {
                objSms.setFolderName("sent");
            }

            lstSms.add(objSms);
            c.moveToNext();
        }
    }
    // else {
    // throw new RuntimeException("You have no SMS");
    // }
    c.close();

    return lstSms;
}

SMS-Klasse ist unten:

public class Sms{
private String _id;
private String _address;
private String _msg;
private String _readState; //"0" for have not read sms and "1" for have read sms
private String _time;
private String _folderName;

public String getId(){
return _id;
}
public String getAddress(){
return _address;
}
public String getMsg(){
return _msg;
}
public String getReadState(){
return _readState;
}
public String getTime(){
return _time;
}
public String getFolderName(){
return _folderName;
}


public void setId(String id){
_id = id;
}
public void setAddress(String address){
_address = address;
}
public void setMsg(String msg){
_msg = msg;
}
public void setReadState(String readState){
_readState = readState;
}
public void setTime(String time){
_time = time;
}
public void setFolderName(String folderName){
_folderName = folderName;
}

}

Vergessen Sie nicht, die Berechtigung in Ihrer AndroidManifest.xml zu definieren

<uses-permission android:name="android.permission.READ_SMS" />
Atif Mahmood
quelle
2
Das ist ein schönes Stück Code. Nur eines: Die Zeit wird in Millisekunden angegeben. Ich denke, es wird besser sein, es zu einem für Menschen lesbaren Format wieString receiveDayTime = Functions.dateFromMilisec(Long.valueOf(c.getColumnIndexOrThrow("date")), "hh:mm a MMM dd, yyyy");
Bibaswann Bandyopadhyay
1
Was ist der Zweck, alles mit Getter und Setter zu machen? Ich verstehe wirklich nicht, warum ich nicht einfach ein Assoc-Array oder eine Assoc-Klasse verwende, auf deren Elemente direkt zugegriffen wird
michnovka
1
@TomasNavara: Überprüfen Sie diesen Code, um die Verwendung von Getter und Setter zu verstehen. pastebin.com/Nh8YXtyJ
Bugs Happen
@BibaswannBandyopadhyay Wenn Sie nichts anderes als Android-Bibliotheken und Java-Bibliotheken verwenden möchten. new SimpleDateFormat("hh:mm", Locale.US).format(new Date(Long.parseLong(_time)));Dies gibt Ihnen 24 Stunden Zeit.
Chris - Jr
mActivityist nicht definiert. Was ist das?
Drei
61

Es ist ein trivialer Prozess. Sie können ein gutes Beispiel im Quellcode SMSPopup sehen

Untersuchen Sie die folgenden Methoden:

SmsMmsMessage getSmsDetails(Context context, long ignoreThreadId, boolean unreadOnly)
long findMessageId(Context context, long threadId, long _timestamp, int messageType
void setMessageRead(Context context, long messageId, int messageType)
void deleteMessage(Context context, long messageId, long threadId, int messageType)

Dies ist die Methode zum Lesen:

SmsMmsMessage getSmsDetails(Context context,
                            long ignoreThreadId, boolean unreadOnly)
{
   String SMS_READ_COLUMN = "read";
   String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;
   String SORT_ORDER = "date DESC";
   int count = 0;
   // Log.v(WHERE_CONDITION);
   if (ignoreThreadId > 0) {
      // Log.v("Ignoring sms threadId = " + ignoreThreadId);
      WHERE_CONDITION += " AND thread_id != " + ignoreThreadId;
   }
   Cursor cursor = context.getContentResolver().query(
                      SMS_INBOX_CONTENT_URI,
                      new String[] { "_id", "thread_id", "address", "person", "date", "body" },
                      WHERE_CONDITION,
                      null,
                      SORT_ORDER);
   if (cursor != null) {
      try {
         count = cursor.getCount();
         if (count > 0) {
            cursor.moveToFirst();
            // String[] columns = cursor.getColumnNames();
            // for (int i=0; i<columns.length; i++) {
            // Log.v("columns " + i + ": " + columns[i] + ": " + cursor.getString(i));
            // }                                         
            long messageId = cursor.getLong(0);
            long threadId = cursor.getLong(1);
            String address = cursor.getString(2);
            long contactId = cursor.getLong(3);
            String contactId_string = String.valueOf(contactId);
            long timestamp = cursor.getLong(4);

            String body = cursor.getString(5);                             
            if (!unreadOnly) {
                count = 0;
            }

            SmsMmsMessage smsMessage = new SmsMmsMessage(context, address,
                          contactId_string, body, timestamp,
                          threadId, count, messageId, SmsMmsMessage.MESSAGE_TYPE_SMS);
            return smsMessage;
         }
      } finally {
         cursor.close();
      }
   }               
   return null;
}
Ömer
quelle
47
Dies ist nicht Teil des Android SDK. Dieser Code geht fälschlicherweise davon aus, dass alle Geräte diesen undokumentierten und nicht unterstützten Inhaltsanbieter unterstützen. Google hat ausdrücklich darauf hingewiesen, dass es keine gute Idee ist, sich darauf zu verlassen: android-developers.blogspot.com/2010/05/…
CommonsWare
1
@Janusz: Es gibt keine dokumentierten und unterstützten Mittel, die auf allen SMS-Clients auf allen Geräten funktionieren.
CommonsWare
9
@ CommonsWare das ist traurig zu hören. Möglicherweise muss dann mit dieser API leben.
Janusz
@Omer Hast du eine Idee, wie du die Anzahl der SMS-Nachrichten pro Kontakt zählen würdest?
SpicyWeenie
4
Der Code wurde verschoben. Durch die Suche in SmsPopupUtils.java habe ich einen neuen Link in Google Code erhalten. Im Fall , dass sie es wieder verschieben oder ganz einzustellen, hier ist eine Backup - Verbindung - pastebin.com/iPt7MLyM
Kalel
25

Ab API 19 können Sie dafür die Telefonieklasse verwenden; Da hartgesottene Werte nicht auf allen Geräten Nachrichten abrufen, ändert sich der Inhaltsanbieter Uri von Geräten und Herstellern.

public void getAllSms(Context context) {

    ContentResolver cr = context.getContentResolver();
    Cursor c = cr.query(Telephony.Sms.CONTENT_URI, null, null, null, null);
    int totalSMS = 0;
    if (c != null) {
        totalSMS = c.getCount();
        if (c.moveToFirst()) {
            for (int j = 0; j < totalSMS; j++) {
                String smsDate = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.DATE));
                String number = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.ADDRESS));
                String body = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.BODY));
                Date dateFormat= new Date(Long.valueOf(smsDate));
                String type;
                switch (Integer.parseInt(c.getString(c.getColumnIndexOrThrow(Telephony.Sms.TYPE)))) {
                    case Telephony.Sms.MESSAGE_TYPE_INBOX:
                        type = "inbox";
                        break;
                    case Telephony.Sms.MESSAGE_TYPE_SENT:
                        type = "sent";
                        break;
                    case Telephony.Sms.MESSAGE_TYPE_OUTBOX:
                        type = "outbox";
                        break;
                    default:
                        break;
                }


                c.moveToNext();
            }
        }

        c.close();

    } else {
        Toast.makeText(this, "No message to show!", Toast.LENGTH_SHORT).show();
    }
}
Manoj Perumarath
quelle
9
Scheint die einzige Antwort zu sein, die keine undokumentierte API verwendet und sich nicht auf Bibliotheken von Drittanbietern bezieht.
Ishamael
Ich habe versucht, diesen Code zu verwenden, um SMS-Nachrichten von Hangouts abzurufen (dies ist meine Standard-SMS-App). Stattdessen wurde die letzte ausgehende Nachricht abgerufen, die ich über Messenger gesendet habe ... Wissen Sie, was dies verursacht?
Miki P
@MikiP Mit meinen Vermutungsfähigkeiten werde ich sagen, dass die Messenger-App Sie gefragt hat, ob Sie die SMS-Verwaltung durch Messenger ersetzen möchten. Es passiert mit einer anderen Messaging-App. Ich habe keine andere Erklärung.
m3nda
2
Vergessen Sie nicht, c.close () aufzurufen.
Cícero Moura
1
@SardarAgabejli Wenn wir hartgesottene Werte wie "contenturi: sms" verwenden, ist dies nicht für jedes Gerät gleich. Wenn wir jedoch die Telefonieklasse verwenden, erhalten wir direkten Zugriff auf diese Inhalts-Uri oder den Pfad der SMS-Datenbank dieses Geräts eine
Helferklasse
23

Dieser Beitrag ist etwas alt, aber hier ist eine weitere einfache Lösung, um Daten zum SMSInhaltsanbieter in Android abzurufen:

Verwenden Sie diese Bibliothek: https://github.com/EverythingMe/easy-content-providers

  • Holen Sie sich alles SMS:

    TelephonyProvider telephonyProvider = new TelephonyProvider(context);
    List<Sms> smses = telephonyProvider.getSms(Filter.ALL).getList();

    Jede SMS hat alle Felder, so dass Sie alle Informationen erhalten können, die Sie benötigen:
    Adresse, Text, Empfangsdatum, Typ (INBOX, SENT, DRAFT, ..), threadId, ...

  • Gel alle MMS:

    List<Mms> mmses = telephonyProvider.getMms(Filter.ALL).getList();
  • Gel alle Thread:

    List<Thread> threads = telephonyProvider.getThreads().getList();
  • Gel alle Conversation:

    List<Conversation> conversations = telephonyProvider.getConversations().getList();

Es funktioniert mit ListoderCursor und es gibt eine Beispiel-App, um zu sehen, wie es aussieht und funktioniert.

In der Tat gibt es eine Unterstützung für alle Android-Inhaltsanbieter wie: Kontakte, Anrufprotokolle, Kalender, ... Vollständiges Dokument mit allen Optionen: https://github.com/EverythingMe/easy-content-providers/wiki/Android- Anbieter

Hoffe es hat auch geholfen :)

sromku
quelle
1
Quellcode und Beispiele auf dem Github sind sehr nützlich. Dies ist eine gute Hülle / Fassade für die meisten gängigen Anbieter. Danke dir.
m3nda
14

Schritt 1: Zuerst müssen wir Berechtigungen in Manifest-Dateien wie hinzufügen

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

Schritt 2: Fügen Sie dann die Service-SMS-Empfängerklasse zum Empfangen von SMS hinzu

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

Schritt 3: Laufzeitberechtigung hinzufügen

private boolean checkAndRequestPermissions()
{
    int sms = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS);

    if (sms != PackageManager.PERMISSION_GRANTED)
    {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_SMS}, REQUEST_ID_MULTIPLE_PERMISSIONS);
        return false;
    }
    return true;
}

Schritt 4: Fügen Sie diese Klassen in Ihre App ein und testen Sie die Interface-Klasse

public interface SmsListener {
   public void messageReceived(String messageText);
}

SmsReceiver.java

public class SmsReceiver extends BroadcastReceiver {
private static SmsListener mListener;
public Pattern p = Pattern.compile("(|^)\\d{6}");
@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();
        String phoneNumber = smsMessage.getDisplayOriginatingAddress();
        String senderNum = phoneNumber ;
        String messageBody = smsMessage.getMessageBody();
        try
        {
  if(messageBody!=null){
   Matcher m = p.matcher(messageBody);
    if(m.find()) {
      mListener.messageReceived(m.group(0));  }
 else {}}  }
        catch(Exception e){} } }
public static void bindListener(SmsListener listener) {
    mListener = listener; }}
Venkatesh
quelle
Was macht das Muster?
Mark Buikema
Nun ... ist das ("com.aquadeals.seller.services.SmsReceiver") der gebräuchliche Dienstname?
m3nda
Ya das ist kein Dienstname, das ist SmsReceiver Klassenpfad in meiner App
Venkatesh
Warum benötigen Sie eine Genehmigung für LOCATION?
Zam Sunk
1
Ich versuche, eine App zu erstellen, die den SMS-Inhalt für den Benutzer anzeigt, auch wenn die App getötet wurde
Anjani Mittal
11

Es gibt bereits viele Antworten, aber ich denke, allen fehlt ein wichtiger Teil dieser Frage. Bevor wir Daten aus einer internen Datenbank oder ihrer Tabelle lesen, müssen wir verstehen, wie Daten darin gespeichert sind, und dann können wir die Lösung der obigen Frage finden:

Wie kann ich in Android programmgesteuert SMS-Nachrichten vom Gerät lesen?

Also, in Android SMS Tabelle sieht so aus

Geben Sie hier die Bildbeschreibung ein

Wissen Sie, wir können aus der Datenbank auswählen, was wir wollen. In unserem Fall haben wir nur benötigt

ID, Adresse und Körper

Beim Lesen von SMS:

1. Fragen Sie nach Berechtigungen

int REQUEST_PHONE_CALL = 1;

   if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_SMS}, REQUEST_PHONE_CALL);
        }

oder

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

2. Jetzt geht Ihr Code so

// Create Inbox box URI
Uri inboxURI = Uri.parse("content://sms/inbox");

// List required columns
String[] reqCols = new String[]{"_id", "address", "body"};

// Get Content Resolver object, which will deal with Content Provider
ContentResolver cr = getContentResolver();

// Fetch Inbox SMS Message from Built-in Content Provider
Cursor c = cr.query(inboxURI, reqCols, null, null, null);

// Attached Cursor with adapter and display in listview
adapter = new SimpleCursorAdapter(this, R.layout.a1_row, c,
        new String[]{"body", "address"}, new int[]{
        R.id.A1_txt_Msg, R.id.A1_txt_Number});
lst.setAdapter(adapter);

Ich hoffe, dass dieser hilfreich sein wird. Vielen Dank.

Nitin Khanna
quelle
7

Die Google Play-Dienste verfügen über zwei APIs, mit denen Sie den SMS-basierten Überprüfungsprozess optimieren können

SMS Retriever API

Bietet eine vollautomatische Benutzererfahrung, ohne dass der Benutzer manuell Bestätigungscodes eingeben muss und ohne zusätzliche App-Berechtigungen, und sollte nach Möglichkeit verwendet werden. Es ist jedoch erforderlich, dass Sie einen benutzerdefinierten Hash-Code in den Nachrichtentext einfügen, sodass Sie auch die Kontrolle über die Serverseite haben müssen .

  • Nachrichtenanforderungen - 11-stelliger Hash-Code, der Ihre App eindeutig identifiziert
  • Absenderanforderungen - Keine
  • Benutzerinteraktion - Keine

Fordern Sie eine SMS-Bestätigung in einer Android-App an

Führen Sie eine SMS-Überprüfung auf einem Server durch

SMS User Consent API

Erfordert keinen benutzerdefinierten Hash-Code. Der Benutzer muss jedoch die Anforderung Ihrer App genehmigen, auf die Nachricht mit dem Bestätigungscode zuzugreifen. Um die Wahrscheinlichkeit zu minimieren, dass dem Benutzer die falsche Nachricht angezeigt SMS User Consentwird, werden Nachrichten von Absendern in der Kontaktliste des Benutzers herausgefiltert.

  • Nachrichtenanforderungen - 4-10-stelliger alphanumerischer Code mit mindestens einer Nummer
  • Absenderanforderungen - Der Absender darf nicht in der Kontaktliste des Benutzers enthalten sein
  • Benutzerinteraktion - Ein Tipp zum Genehmigen

The SMS User Consent APIist Teil von Google Play Services. Um es zu verwenden, benötigen Sie mindestens eine Version 17.0.0dieser Bibliotheken:

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

Schritt 1: Hören Sie auf SMS-Nachrichten

Die Zustimmung des SMS-Benutzers wartet bis zu fünf Minuten lang auf eingehende SMS-Nachrichten, die einen Einmalcode enthalten. Es werden keine Nachrichten angezeigt, die vor dem Start gesendet wurden. Wenn Sie die Telefonnummer kennen, die den Einmalcode sendet, können Sie die angeben senderPhoneNumber, oder wenn Sie nullmit keiner Nummer übereinstimmen.

 smsRetriever.startSmsUserConsent(senderPhoneNumber /* or null */)

Schritt 2: Fordern Sie die Zustimmung zum Lesen einer Nachricht an

Sobald Ihre App eine Nachricht mit einem Einmalcode erhält, wird diese per Broadcast benachrichtigt. Zu diesem Zeitpunkt haben Sie keine Einwilligung zum Lesen der Nachricht. Stattdessen erhalten Sie eine Einwilligung, mit der Sie Intentden Benutzer zur Einwilligung auffordern können. In Ihrem BroadcastReceiverzeigen Sie die Eingabeaufforderung mit der Intentin der extras. Wenn Sie diese Absicht starten, werden Sie aufgefordert, eine einzelne Nachricht zu lesen. Ihnen wird der gesamte Text angezeigt, den sie mit Ihrer App teilen.

val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)

Geben Sie hier die Bildbeschreibung ein

Schritt 3: Analysieren Sie den Einmalcode und schließen Sie die SMS-Überprüfung ab

Wenn der Benutzer klickt, ist “Allow”es Zeit, die Nachricht tatsächlich zu lesen! Innerhalb von onActivityResultkönnen Sie den vollständigen Text der SMS-Nachricht aus den Daten erhalten:

val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)

Sie analysieren dann die SMS-Nachricht und geben den Einmalcode an Ihr Backend weiter!

Levon Petrosyan
quelle
4-10 digit alphanumeric code containing at least one numberKönnen Sie erklären, was das bedeutet? Bedeutet dies, dass die Länge der gesamten Nachricht 4-10 Zeichen nur des SMS-Codes betragen sollte?
Zeeshan Shabbir
Vielen Dank auch
Levon Petrosyan
Dies funktioniert nur für die OTP-Überprüfung, oder? Was ist mit dem Lesen aller anderen Nachrichten im Telefon, aller SMS usw.? Gibt es dafür eine neue API? Bitte lassen Sie es mich wissen. Viel Spaß beim Codieren! :)
Manoj Perumarath
Wir haben immer den Timeout-Fehler. Bitte helfen Sie mir
Manikandan K
2
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;

verändert von:

String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0 " : SMS_READ_COLUMN + " = 1 ";
Van Hau Hoang
quelle
2

Kotlin Code zum Lesen von SMS:

1- Fügen Sie diese Berechtigung zu AndroidManifest.xml hinzu:

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

2-Erstellen Sie eine BroadCastreceiver-Klasse:

package utils.broadcastreceivers

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.telephony.SmsMessage
import android.util.Log

class MySMSBroadCastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
    var body = ""
    val bundle = intent?.extras
    val pdusArr = bundle!!.get("pdus") as Array<Any>
    var messages: Array<SmsMessage?>  = arrayOfNulls(pdusArr.size)

 // if SMSis Long and contain more than 1 Message we'll read all of them
    for (i in pdusArr.indices) {
        messages[i] = SmsMessage.createFromPdu(pdusArr[i] as ByteArray)
    }
      var MobileNumber: String? = messages[0]?.originatingAddress
       Log.i(TAG, "MobileNumber =$MobileNumber")         
       val bodyText = StringBuilder()
        for (i in messages.indices) {
            bodyText.append(messages[i]?.messageBody)
        }
        body = bodyText.toString()
        if (body.isNotEmpty()){
       // Do something, save SMS in DB or variable , static object or .... 
                       Log.i("Inside Receiver :" , "body =$body")
        }
    }
 }

3-SMS-Berechtigung ab Android 6 abrufen:

   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && 
    ActivityCompat.checkSelfPermission(context!!,
            Manifest.permission.RECEIVE_SMS
        ) != PackageManager.PERMISSION_GRANTED
    ) { // Needs permission

            requestPermissions(arrayOf(Manifest.permission.RECEIVE_SMS),
            PERMISSIONS_REQUEST_READ_SMS
        )

    } else { // Permission has already been granted

    }

4- Fügen Sie diesen Anforderungscode zu Aktivität oder Fragment hinzu:

 companion object {
    const val PERMISSIONS_REQUEST_READ_SMS = 100
   }

5- Override Check permisstion Ergebnis anfordern Spaß:

 override fun onRequestPermissionsResult(
    requestCode: Int, permissions: Array<out String>,
    grantResults: IntArray
) {
    when (requestCode) {

        PERMISSIONS_REQUEST_READ_SMS -> {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.i("BroadCastReceiver", "PERMISSIONS_REQUEST_READ_SMS Granted")
            } else {
                //  toast("Permission must be granted  ")
            }
        }
    }
}
Hamed Jaliliani
quelle
1

Die einfachste Funktion

Um die SMS zu lesen, habe ich eine Funktion geschrieben, die ein Conversation-Objekt zurückgibt:

class Conversation(val number: String, val message: List<Message>)
class Message(val number: String, val body: String, val date: Date)

fun getSmsConversation(context: Context, number: String? = null, completion: (conversations: List<Conversation>?) -> Unit) {
        val cursor = context.contentResolver.query(Telephony.Sms.CONTENT_URI, null, null, null, null)

        val numbers = ArrayList<String>()
        val messages = ArrayList<Message>()
        var results = ArrayList<Conversation>()

        while (cursor != null && cursor.moveToNext()) {
            val smsDate = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.DATE))
            val number = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.ADDRESS))
            val body = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.BODY))

            numbers.add(number)
            messages.add(Message(number, body, Date(smsDate.toLong())))
        }

        cursor?.close()

        numbers.forEach { number ->
            if (results.find { it.number == number } == null) {
                val msg = messages.filter { it.number == number }
                results.add(Conversation(number = number, message = msg))
            }
        }

        if (number != null) {
            results = results.filter { it.number == number } as ArrayList<Conversation>
        }

        completion(results)
    }

Verwenden von:

getSmsConversation(this){ conversations ->
    conversations.forEach { conversation ->
        println("Number: ${conversation.number}")
        println("Message One: ${conversation.message[0].body}")
        println("Message Two: ${conversation.message[1].body}")
    }
}

Oder erhalten Sie nur ein Gespräch mit einer bestimmten Nummer:

getSmsConversation(this, "+33666494128"){ conversations ->
    conversations.forEach { conversation ->
        println("Number: ${conversation.number}")
        println("Message One: ${conversation.message[0].body}")
        println("Message Two: ${conversation.message[1].body}")
    }
}
Mickael Belhassen
quelle