Jak mogę programowo odczytać wiadomości SMS z urządzenia na Androidzie?

249

Chcę pobrać wiadomości SMS z urządzenia i wyświetlić je?

Manoj Perumarath
źródło
@David Freitas Zaufany link +1
Shahzad Imam
3
@DavidFreitas ten link nie działa, czy możesz udostępnić najnowszy link?
Khobaib
3
@Khobaib, jak zwykle rzeczy w Internecie są ulotne. Znalazłem kopię na archive.org stackoverflow.com/a/19966227/40961 , dzięki Bogu za nich (ostatnio przekazałem darowiznę, aby utrzymać ich działanie). Ale powinniśmy rozważyć konwersję zawartości strony z web.archive.org/web/20121022021217/http://mobdev.olin.edu/... do składni markdown w odpowiedzi na to pytanie. Prawdopodobnie godzina pracy.
David d C e Freitas

Odpowiedzi:

157

Użyj Content Resolver ( „content: // sms / inbox” ), aby odczytać SMS-y znajdujące się w skrzynce odbiorczej.

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

Dodaj uprawnienie READ_SMS .

Mam nadzieję, że to pomoże :)

Suryavel TR
źródło
7
Dziękuję Ci! Błędnie napisałeś „getColumnName”, poza tym działa to jak urok. Aha, a jeśli ktoś będzie tego używał, nie zapomnij dodać uprawnienia android.permission.READ_SMS.
qwerty
1
Dzięki. Zmodyfikowałem to :)
Suryavel TR
5
Czy wykorzystuje to również nieudokumentowane API, które @CommonsWare określiło w swoim komentarzu do zaakceptowanej odpowiedzi?
Krishnabhadra,
1
Uwaga! Nie przegap moveToFirsttak jak ja.
Alexandr Priymak
4
@Krishnabhadra Tak. Wykorzystuje nieudokumentowanego dostawcę treści „content: // sms / inbox”.
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();
    }

Ustaw aplikację jako domyślną aplikację do SMS-ów

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

Funkcja otrzymywania wiadomości 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;
}

Klasa SMS jest poniżej:

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

}

Nie zapomnij zdefiniować uprawnień w pliku AndroidManifest.xml

<uses-permission android:name="android.permission.READ_SMS" />
Atif Mahmood
źródło
2
To niezły kawałek kodu. Tylko jedno, czas jest uzyskiwany w milisekundach. Myślę, że lepiej będzie, aby był to format czytelny dla człowieka, taki jakString receiveDayTime = Functions.dateFromMilisec(Long.valueOf(c.getColumnIndexOrThrow("date")), "hh:mm a MMM dd, yyyy");
Bibaswann Bandyopadhyay
1
jaki jest cel tworzenia wszystkiego za pomocą gettera i settera, naprawdę nie rozumiem, dlaczego po prostu nie użyć tablicy lub klasy assoc, do której elementów można uzyskać bezpośredni dostęp
michnovka,
1
@TomasNavara: Sprawdź ten kod, aby zrozumieć korzystanie z metody pobierającej i ustawiającej. pastebin.com/Nh8YXtyJ
Błędy występowały
@BibaswannBandyopadhyay Jeśli nie chcesz używać niczego oprócz bibliotek Androida i bibliotek Java. new SimpleDateFormat("hh:mm", Locale.US).format(new Date(Long.parseLong(_time)));To da ci 24 godziny.
Chris - Jr
mActivitynie jest zdefiniowany. Co to jest?
dthree
61

To jest trywialny proces. Dobry przykład możesz zobaczyć w kodzie źródłowym SMSPopup

Sprawdź następujące metody:

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)

to jest metoda czytania:

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
źródło
47
To nie jest część zestawu SDK systemu Android. Ten kod błędnie zakłada, że ​​wszystkie urządzenia obsługują tego nieudokumentowanego i nieobsługiwanego dostawcę treści. Google wyraźnie wskazał, że poleganie na tym nie jest dobrym pomysłem: android-developers.blogspot.com/2010/05/…
CommonsWare
1
@Janusz: Nie ma udokumentowanych i obsługiwanych środków, które działałyby we wszystkich klientach SMS na wszystkich urządzeniach.
CommonsWare
9
@CommonsWare to smutno słyszeć. Może wtedy trzeba będzie żyć z tym interfejsem API.
Janusz
@Omer Masz pomysł, jak policzyć liczbę wiadomości SMS na kontakt?
SpicyWeenie
4
Kod został przeniesiony. Przeszukując SmsPopupUtils.java otrzymałem nowy link do niego w kodzie Google. Na wypadek, gdyby przenieśli go ponownie lub całkowicie przerwie, oto link do kopii zapasowej - pastebin.com/iPt7MLyM
KalEl
25

Począwszy od API 19, możesz do tego wykorzystywać klasę telefonii; Ponieważ wartości zapisane na stałe nie będą pobierać wiadomości z każdego urządzenia, ponieważ dostawca treści Uri zmienia się od urządzeń i producentów.

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
źródło
9
Wydaje się, że jest to jedyna odpowiedź, która nie korzysta z nieudokumentowanego interfejsu API i nie odnosi się do bibliotek stron trzecich.
Ishamael
Próbowałem użyć tego kodu, aby otrzymywać wiadomości SMS z Hangouts (jest to moja domyślna aplikacja do SMS-ów). Zamiast tego pobierał ostatnią wiadomość wychodzącą wysłaną przez Messenger ... Czy wiesz, co to powoduje?
Miki P
@MikiP używając moich uprawnień do zgadywania powiem, że aplikacja Messenger poprosiła cię o zastąpienie zarządzania SMS-em komunikatorem Messenger. Zdarza się to w przypadku innej aplikacji do przesyłania wiadomości. Nie mam innego wytłumaczenia.
m3nda
2
Nie zapomnij wywołać c.close ();
Cícero Moura,
1
@SardarAgabejli Jeśli użyjemy zapisanych wartości, takich jak „contenturi: sms”, nie będzie to takie samo dla każdego urządzenia, ale jeśli użyjemy klasy Telephony, otrzymamy bezpośredni dostęp do tego conetnt uri lub ścieżki sms db tego urządzenia, to klasa pomocnicza wskazująca na db sms
Manoj Perumarath
23

Ten post jest trochę stary, ale oto inne łatwe rozwiązanie do pobierania danych związanych z SMSdostawcą treści w systemie Android:

Użyj tej biblioteki: https://github.com/EverythingMe/easy-content-providers

  • Zbierz wszystkie SMS:

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

    Każdy SMS ma wszystkie pola, dzięki czemu możesz uzyskać wszelkie potrzebne informacje:
    adres, treść, otrzymano Data, typ (SKRZYNKA, WYSŁANE, PROJEKT, ...), wątek, ...

  • Żel wszystko MMS:

    List<Mms> mmses = telephonyProvider.getMms(Filter.ALL).getList();
  • Żel wszystko Thread:

    List<Thread> threads = telephonyProvider.getThreads().getList();
  • Żel wszystko Conversation:

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

Działa z Listlub Cursori jest przykładowa aplikacja, aby zobaczyć, jak to wygląda i działa.

W rzeczywistości istnieje wsparcie dla wszystkich dostawców treści dla Androida, takich jak: Kontakty, dzienniki połączeń, kalendarz, ... Pełny dokument ze wszystkimi opcjami: https://github.com/EverythingMe/easy-content-providers/wiki/Android- dostawcy

Mam nadzieję, że to również pomogło :)

sromku
źródło
1
Kod źródłowy i przykłady na githubie są bardzo przydatne. To jest dobre opakowanie / fasada dla większości popularnych dostawców. Dziękuję Ci.
m3nda
14

Krok 1: najpierw musimy dodać uprawnienia w pliku manifestu, takim jak

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

Krok 2: następnie dodaj klasę usługowego odbiornika SMS do odbierania wiadomości SMS

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

Krok 3: Dodaj uprawnienie w czasie wykonywania

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

Krok 4: Dodaj te klasy do swojej aplikacji i przetestuj klasę interfejsu

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
źródło
Co robi wzór?
Mark Buikema,
Cóż ... czy to („com.aquadeals.seller.services.SmsReceiver”) nazwa usługi wspólnej?
m3nda
Tak, to nie nazwa usługi, czyli ścieżka klasy SmsReceiver w mojej aplikacji
Venkatesh
Dlaczego potrzebujesz zezwolenia na LOKALIZACJĘ?
Zam Zatopiony
1
próbuję stworzyć aplikację, która wyskakuje zawartość sms do użytkownika, nawet jeśli aplikacja została zabita
Anjani Mittal
11

Istnieje wiele odpowiedzi, które są już dostępne, ale myślę, że we wszystkich brakuje ważnej części tego pytania. Przed odczytem danych z wewnętrznej bazy danych lub jej tabeli musimy zrozumieć, w jaki sposób dane są w niej przechowywane, a następnie możemy znaleźć rozwiązanie powyższego pytania, które brzmi:

Jak mogę programowo odczytać wiadomości SMS z urządzenia na Androidzie?

Tak więc w Androidzie Tabela SMS wygląda tak

wprowadź opis zdjęcia tutaj

Wiemy, że możemy wybrać z bazy danych wszystko, co chcemy, w naszym przypadku mamy tylko wymagane

identyfikator, adres i treść

W przypadku czytania SMS:

1. Zapytaj o uprawnienia

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

lub

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

2. Teraz twój kod wygląda tak

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

Mam nadzieję, że ten będzie pomocny. Dzięki.

Nitin Khanna
źródło
7

Usługi Google Play mają dwa interfejsy API, za pomocą których można usprawnić proces weryfikacji za pomocą wiadomości SMS

SMS Retriever API

Zapewnia w pełni zautomatyzowane środowisko użytkownika, bez konieczności ręcznego wpisywania kodów weryfikacyjnych i bez dodatkowych uprawnień aplikacji i należy z niego korzystać, gdy to możliwe. Wymaga to jednak umieszczenia niestandardowego kodu skrótu w treści wiadomości, więc musisz mieć kontrolę również po stronie serwera .

  • Wymagania dotyczące wiadomości - 11-cyfrowy kod skrótu, który jednoznacznie identyfikuje Twoją aplikację
  • Wymagania dotyczące nadawcy - brak
  • Interakcja użytkownika - Brak

Poproś o weryfikację SMS w aplikacji na Androida

Wykonaj weryfikację SMS na serwerze

Interfejs API zgody użytkownika SMS

Nie wymaga niestandardowego kodu skrótu, wymaga jednak od użytkownika zatwierdzenia prośby aplikacji o dostęp do wiadomości zawierającej kod weryfikacyjny. Aby zminimalizować ryzyko wyświetlenia niewłaściwej wiadomości użytkownikowi, SMS User Consentodfiltruje wiadomości od nadawców z listy kontaktów użytkownika.

  • Wymagania dotyczące wiadomości - 4–10 cyfrowy kod alfanumeryczny zawierający co najmniej jedną cyfrę
  • Wymagania nadawcy - nadawcy nie można znaleźć na liście kontaktów użytkownika
  • Interakcja użytkownika - jedno dotknięcie, aby zatwierdzić

The SMS User Consent APIjest częścią usług Google Play. Aby z niego skorzystać, potrzebujesz co najmniej wersji 17.0.0tych bibliotek:

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

Krok 1: Rozpocznij nasłuchiwanie wiadomości SMS

Zgoda użytkownika SMS będzie nasłuchiwać przychodzących wiadomości SMS zawierających jednorazowy kod przez maksymalnie pięć minut. Nie będzie patrzeć na żadne wiadomości wysłane przed jego uruchomieniem. Jeśli znasz numer telefonu, który wyśle ​​jednorazowy kod, możesz podać senderPhoneNumberlub, jeśli nie null, dopasować dowolny numer.

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

Krok 2: Poproś o zgodę na przeczytanie wiadomości

Gdy aplikacja otrzyma wiadomość zawierającą kod jednorazowy, zostanie o tym powiadomiona przez transmisję. W tym momencie nie masz zgody na przeczytanie wiadomości - zamiast tego otrzymujesz informację Intent, że możesz zacząć pytać użytkownika o zgodę. Wewnątrz BroadcastReceiverwyświetlasz monit za pomocą Intentw extras. Po uruchomieniu tego zamiaru użytkownik poprosi o zgodę na przeczytanie pojedynczej wiadomości. Wyświetlą się cały tekst, który udostępnią Twojej aplikacji.

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

wprowadź opis zdjęcia tutaj

Krok 3: Analizuj kod jednorazowy i zakończ weryfikację SMS

Gdy użytkownik kliknie “Allow”- nadszedł czas, aby przeczytać wiadomość! Wewnątrz onActivityResultmożesz uzyskać pełny tekst wiadomości SMS z danych:

val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)

Następnie parsujesz wiadomość SMS i przekazujesz jednorazowy kod do backendu!

Levon Petrosyan
źródło
4-10 digit alphanumeric code containing at least one numberCzy możesz wyjaśnić, co to znaczy? Czy to oznacza, że ​​długość całej wiadomości powinna wynosić 4–10 znaków samego kodu sms?
Zeeshan Shabbir
Dziękuję również
Levon Petrosyan
Działa to tylko w przypadku weryfikacji OTP, prawda? Co powiesz na czytanie wszystkich innych wiadomości w telefonie, wszystkich SMS-ów itp.? Czy jest jakiś nowy interfejs API, daj mi znać. Miłego kodowania! :)
Manoj Perumarath,
Zawsze występował błąd przekroczenia limitu czasu. Proszę o pomoc
Manikandan K
2
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;

zmienione przez:

String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0 " : SMS_READ_COLUMN + " = 1 ";
Van Hau Hoang
źródło
2

Kod Kotlin do czytania SMS:

1- Dodaj to uprawnienie do AndroidManifest.xml:

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

2-Utwórz klasę BroadCastreceiver:

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-Uzyskaj uprawnienie SMS, jeśli Android 6 i nowszy:

   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- Dodaj ten kod żądania do działania lub fragmentu:

 companion object {
    const val PERMISSIONS_REQUEST_READ_SMS = 100
   }

5- Przesłoń Sprawdź uprawnienia Prośba o wynik zabawy:

 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
źródło
1

Najłatwiejsza funkcja

Aby odczytać sms, napisałem funkcję, która zwraca obiekt konwersacji:

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

Za pomocą:

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

Lub uzyskaj tylko rozmowę o określonym numerze:

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
źródło