Como posso ler mensagens SMS do dispositivo programaticamente no Android?

249

Quero recuperar as mensagens SMS do dispositivo e exibi-las?

Manoj Perumarath
fonte
@David Freitas Link confiável +1
Shahzad Imam
3
@DavidFreitas este link não está funcionando, você pode compartilhar o último link?
Khobaib
3
@ Khobaib, como sempre, as coisas na internet são passageiras. Encontrei uma cópia no archive.org stackoverflow.com/a/19966227/40961 , graças a Deus por eles (doei recentemente para mantê-los funcionando). Mas devemos considerar a conversão do conteúdo da página de web.archive.org/web/20121022021217/http://mobdev.olin.edu/… para sintaxe de remarcação em uma resposta a esta pergunta. Provavelmente uma hora de trabalho.
David d C e Freitas

Respostas:

157

Use o resolvedor de conteúdo ( "content: // sms / inbox" ) para ler o SMS que está na caixa de entrada.

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

Por favor, adicione a permissão READ_SMS .

Espero que ajude :)

Suryavel TR
fonte
7
Obrigado! Você digitou incorretamente "getColumnName"; além disso, ele funciona como um encanto. Ah, e se alguém usar isso, não se esqueça de adicionar a permissão android.permission.READ_SMS.
QWERTY
1
Obrigado. Eu modifiquei :) #
Suryavel TR
5
Isso também usa a API não documentada que @CommonsWare especificou em seu comentário para a resposta aceita?
precisa saber é o seguinte
1
Atenção! Não perca moveToFirstcomo eu.
Alexandr Priymak
4
@Krishnabhadra Yes. Ele usa o provedor de conteúdo "document: // sms / inbox" não documentado.
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();
    }

Definir aplicativo como aplicativo SMS padrão

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

Função para receber 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;
}

A classe Sms está abaixo:

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

}

Não se esqueça de definir a permissão no seu AndroidManifest.xml

<uses-permission android:name="android.permission.READ_SMS" />
Atif Mahmood
fonte
2
Esse é um bom pedaço de código. Apenas uma coisa, o tempo é obtido em milissegundos. Eu acho que será melhor torná-lo um formato legível por humanos comoString receiveDayTime = Functions.dateFromMilisec(Long.valueOf(c.getColumnIndexOrThrow("date")), "hh:mm a MMM dd, yyyy");
Bibaswann Bandyopadhyay
1
qual é o propósito de fazer tudo com getter e setter, eu realmente não entendo por que não usar um array assoc ou classe cujos elementos são acessados diretamente
michnovka
1
@TomasNavara: verifique este código para entender o uso de getter e setter. pastebin.com/Nh8YXtyJ
erros acontecem
@BibaswannBandyopadhyay Se você não quiser usar nada, exceto as bibliotecas Android e as bibliotecas Java. new SimpleDateFormat("hh:mm", Locale.US).format(new Date(Long.parseLong(_time)));Isso lhe dará tempo de 24 horas.
Chris - Jr
mActivitynão está definido. O que é isso?
dthree
61

É um processo trivial. Você pode ver um bom exemplo no código-fonte SMSPopup

Examine os seguintes métodos:

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)

este é o método para leitura:

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
fonte
47
Isso não faz parte do SDK do Android. Esse código pressupõe incorretamente que todos os dispositivos suportem esse provedor de conteúdo não documentado e não suportado. Google indicou explicitamente que depender de esta não é uma boa idéia: android-developers.blogspot.com/2010/05/...
CommonsWare
1
@ Janusz: Não há meios documentados e suportados que funcionem em todos os clientes SMS em todos os dispositivos.
CommonsWare
9
@CommonsWare que é triste de ouvir. Pode ter que viver com essa API então.
Janusz
@Omer Alguma idéia de como você contaria o número de mensagens SMS por contato?
SpicyWeenie
4
O código foi movido. Pesquisando SmsPopupUtils.java me deu um novo link para ele no código do google. No caso de eles se movem-lo novamente ou interrompê-la completamente, aqui está um link de backup - pastebin.com/iPt7MLyM
kalel
25

A partir da API 19, você pode fazer uso da classe de telefonia para isso; Como os valores marcados não recuperam mensagens em todos os dispositivos, porque o provedor de conteúdo Uri muda de dispositivos e fabricantes.

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
fonte
9
Parece ser a única resposta que não usa API não documentada e não se refere a bibliotecas de terceiros.
Ishamael 19/01/19
Tentei usar esse código para receber mensagens SMS do Hangouts (que é meu aplicativo de SMS padrão). Em vez disso, ele recuperou a última mensagem que enviei via Messenger ... Você sabe o que está causando isso?
Miki P
@MikiP usando meus poderes de adivinhação, direi que o Messenger App pediu para você substituir o gerenciamento de SMS pelo Messenger. Isso acontece com outro aplicativo de mensagens. Não tenho outra explicação.
M3nda 17/08
2
Não esqueça de chamar c.close ();
Cícero Moura
1
@SardarAgabejli Se usarmos valores rígidos como "contenturi: sms", não será o mesmo para todos os dispositivos, mas se usarmos a classe Telephony, obteremos acesso direto a essa interface do usuário ou ao caminho do sms db desse dispositivo. uma classe auxiliar para apontar para o db de sms
Manoj Perumarath
23

Esta postagem é um pouco antiga, mas aqui está outra solução fácil para obter dados relacionados ao SMSprovedor de conteúdo no Android:

Use esta lib: https://github.com/EverythingMe/easy-content-providers

  • Obter tudo SMS:

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

    Cada SMS tem todos os campos, para que você possa obter qualquer informação que você precise:
    endereço, corpo, dataData, tipo (INBOX, SENT, DRAFT, ..), threadId, ...

  • Gel tudo MMS:

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

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

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

Ele funciona com Listou Cursore existe um aplicativo de exemplo para ver como ele funciona e como funciona.

De fato, há suporte para todos os provedores de conteúdo do Android, como: Contatos, Logs de chamadas, Calendário ... Documento completo com todas as opções: https://github.com/EverythingMe/easy-content-providers/wiki/Android- fornecedores

Espero que também tenha ajudado :)

sromku
fonte
1
O código-fonte e os exemplos no github são bastante úteis. Esse é um bom invólucro / fachada para os fornecedores mais comuns. Obrigado.
M3nda
14

Etapa 1: primeiro temos que adicionar permissões no arquivo de manifesto, como

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

Etapa 2: em seguida, adicione a classe de receptor de serviço sms para receber sms

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

Etapa 3: adicionar permissão de tempo de execução

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

Etapa 4: adicione essas classes ao seu aplicativo e teste a classe Interface

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
fonte
O que o padrão faz?
precisa
Bem ... é esse ("com.aquadeals.seller.services.SmsReceiver") o nome do serviço comum?
M3nda
Ya que não é o nome do serviço, que é SmsReceiver caminho de classe em meu aplicativo
Venkatesh
Por que precisa de permissão para LOCATION?
Zam Sunk
1
Eu estou tentando fazer um aplicativo que aparece o conteúdo sms para o usuário mesmo se o aplicativo foi morto
Anjani Mittal
11

Já existem muitas respostas disponíveis, mas acho que todas elas estão faltando uma parte importante desta pergunta. Antes de ler os dados de um banco de dados interno ou de sua tabela, precisamos entender como os dados são armazenados nele e, em seguida, podemos encontrar a solução da pergunta acima:

Como posso ler mensagens SMS do dispositivo programaticamente no Android?

Então, na tabela SMS do Android, é assim:

insira a descrição da imagem aqui

Saiba, podemos selecionar o que quisermos do banco de dados. No nosso caso, apenas solicitamos

id, endereço e corpo

Em caso de leitura de SMS:

1. Peça permissões

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

ou

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

2.Agora, seu código fica assim

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

Espero que este seja útil. Obrigado.

Nitin Khanna
fonte
7

Os serviços do Google Play têm duas APIs que você pode usar para otimizar o processo de verificação por SMS

API do SMS Retriever

Fornece uma experiência de usuário totalmente automatizada, sem exigir que o usuário digite manualmente códigos de verificação e sem exigir permissões extras de aplicativos e deve ser usado quando possível. No entanto, exige que você coloque um código de hash personalizado no corpo da mensagem, portanto, você também deve ter controle sobre o lado do servidor .

  • Requisitos de mensagem - código hash de 11 dígitos que identifica exclusivamente seu aplicativo
  • Requisitos de remetente - Nenhum
  • Interação do usuário - Nenhuma

Solicitar verificação de SMS em um aplicativo Android

Executar verificação de SMS em um servidor

API de consentimento do usuário do SMS

Não requer o código hash personalizado, mas exige que o usuário aprove a solicitação do seu aplicativo para acessar a mensagem que contém o código de verificação. Para minimizar as chances de aparecer a mensagem errada para o usuário, SMS User Consentfiltrará as mensagens dos remetentes na lista de contatos do usuário.

  • Requisitos de mensagem - código alfanumérico de 4 a 10 dígitos contendo pelo menos um número
  • Requisitos do remetente - O remetente não pode estar na lista de contatos do usuário
  • Interação do usuário - um toque para aprovar

The SMS User Consent APIfaz parte do Google Play Services. Para usá-lo, você precisará de pelo menos a versão 17.0.0dessas bibliotecas:

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

Etapa 1: comece a ouvir as mensagens SMS

O consentimento do usuário do SMS escutará as mensagens SMS recebidas que contenham um código único por até cinco minutos. Ele não examinará nenhuma mensagem enviada antes de ser iniciada. Se você souber o número de telefone que enviará o código único, poderá especificar o senderPhoneNumber, ou se não nullcorresponderá a nenhum número.

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

Etapa 2: solicitar consentimento para ler uma mensagem

Depois que seu aplicativo receber uma mensagem contendo um código único, ele será notificado por uma transmissão. Neste ponto, você não tem consentimento para ler a mensagem. Em vez disso, você recebe um Intentaviso de que pode começar a solicitar o consentimento do usuário. Dentro do seu BroadcastReceiver, você mostra o prompt usando o Intentno extras. Quando você inicia essa intenção, ele solicita ao usuário permissão para ler uma única mensagem. Eles mostrarão o texto inteiro que compartilharão com seu aplicativo.

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

insira a descrição da imagem aqui

Etapa 3: analisar o código único e concluir a verificação por SMS

Quando o usuário clica “Allow”- é hora de realmente ler a mensagem! Dentro de onActivityResultvocê, você pode obter o texto completo da mensagem SMS a partir dos dados:

val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)

Você analisa a mensagem SMS e passa o código único para o seu back-end!

Levon Petrosyan
fonte
4-10 digit alphanumeric code containing at least one numberVocê pode explicar o que isso significa? Isso significa que o comprimento da mensagem inteira deve ser de 4 a 10 caracteres apenas do código sms?
Zeeshan Shabbir
Obrigado também
Levon Petrosyan
Isso funciona apenas para verificação OTP, certo? Que tal ler todas as outras mensagens dentro do telefone, todos os SMS, etc? Existe alguma nova API para isso? Entre em contato. Feliz codificação! :)
Manoj Perumarath
Sempre temos o erro de tempo limite. Por favor me ajude
Manikandan K
2
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;

Alterado por:

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

Código Kotlin para ler SMS:

1- Adicione esta permissão ao AndroidManifest.xml:

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

2-Crie uma classe 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-Obtenha permissão de SMS se o Android 6 e superior:

   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- Adicione este código de solicitação à Atividade ou fragmento:

 companion object {
    const val PERMISSIONS_REQUEST_READ_SMS = 100
   }

5- Substituição da permissão de verificação Solicitar resultado divertido:

 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
fonte
1

A função mais fácil

Para ler o sms, escrevi uma função que retorna um objeto de conversa:

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

Usando:

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

Ou obtenha apenas uma conversa de número específico:

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
fonte