Comment puis-je lire les messages SMS de l'appareil par programmation dans Android?

249

Je veux récupérer les messages SMS de l'appareil et les afficher?

Manoj Perumarath
la source
@David Freitas Lien de confiance +1
Shahzad Imam
3
@DavidFreitas ce lien ne fonctionne pas, pouvez-vous partager le dernier lien?
Khobaib
3
@Khobaib, comme d'habitude, les choses sur Internet sont éphémères. J'ai trouvé une copie sur archive.org stackoverflow.com/a/19966227/40961 , Dieu merci pour eux (j'ai fait un don récemment pour les faire fonctionner). Mais nous devrions envisager de convertir le contenu de la page de web.archive.org/web/20121022021217/http://mobdev.olin.edu/… en syntaxe de démarque dans une réponse à cette question. Probablement une heure de travail.
David d C e Freitas

Réponses:

157

Utilisez Content Resolver ( "content: // sms / mailbox" ) pour lire les SMS qui se trouvent dans la boîte de réception.

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

Veuillez ajouter l' autorisation READ_SMS .

J'espère que ça aide :)

Suryavel TR
la source
7
Je vous remercie! Vous avez mal orthographié "getColumnName", sinon cela fonctionne comme un charme. Oh, et si quelqu'un veut l'utiliser, n'oubliez pas d'ajouter l'autorisation android.permission.READ_SMS.
qwerty
1
Merci. Je l'ai modifié :)
Suryavel TR
5
Est-ce que cela utilise également l'API non documentée que @CommonsWare a spécifiée dans son commentaire à la réponse acceptée?
Krishnabhadra
1
Attention! Ne manquez pas moveToFirstcomme moi.
Alexandr Priymak
4
@ Krishnabhadra Oui. Il utilise le fournisseur de contenu "content: // sms / mailbox" non documenté.
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();
    }

Définir l'application comme application SMS par défaut

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

Fonction pour recevoir des 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;
}

La classe SMS est ci-dessous:

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'oubliez pas de définir l'autorisation dans votre AndroidManifest.xml

<uses-permission android:name="android.permission.READ_SMS" />
Atif Mahmood
la source
2
C'est un joli morceau de code. Une seule chose, le temps est obtenu en millisecondes. Je pense qu'il vaudra mieux en faire un format lisible par l'homme commeString receiveDayTime = Functions.dateFromMilisec(Long.valueOf(c.getColumnIndexOrThrow("date")), "hh:mm a MMM dd, yyyy");
Bibaswann Bandyopadhyay
1
quel est le but de tout faire avec getter et setter, je ne comprends vraiment pas pourquoi ne pas simplement utiliser un tableau ou une classe assoc dont les éléments sont accessibles directement
michnovka
1
@TomasNavara: Vérifiez ce code pour comprendre l'utilisation de getter et setter. pastebin.com/Nh8YXtyJ
Bugs Happen
@BibaswannBandyopadhyay Si vous ne voulez rien utiliser sauf les bibliothèques Android et les bibliothèques Java. new SimpleDateFormat("hh:mm", Locale.US).format(new Date(Long.parseLong(_time)));Cela vous donnera 24 heures.
Chris - Jr
mActivityn'est pas défini. Qu'est-ce que c'est?
2017 à 6h39
61

C'est un processus trivial. Vous pouvez voir un bon exemple dans le code source SMSPopup

Examinez les méthodes suivantes:

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)

c'est la méthode de lecture:

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
la source
47
Cela ne fait pas partie du SDK Android. Ce code fait l'hypothèse incorrecte que tous les appareils prennent en charge ce fournisseur de contenu non documenté et non pris en charge. Google a explicitement indiqué que faire appel à cette est pas une bonne idée: android-developers.blogspot.com/2010/05/...
CommonsWare
1
@Janusz: Il n'existe aucun moyen documenté et pris en charge qui fonctionne sur tous les clients SMS sur tous les appareils.
CommonsWare
9
@CommonsWare qui est triste à entendre. Il faudra peut-être alors vivre avec cette API.
Janusz
@Omer Une idée de la façon dont vous compteriez le nombre de messages SMS par contact?
SpicyWeenie
4
Le code a bougé. La recherche sur SmsPopupUtils.java m'a donné un nouveau lien vers celui-ci dans le code google. Dans le cas où ils le déplaceraient à nouveau ou l'arrêteraient complètement, voici un lien de sauvegarde - pastebin.com/iPt7MLyM
KalEl
25

À partir de l'API 19, vous pouvez utiliser la classe de téléphonie pour cela; Étant donné que les valeurs enregistrées en dur ne récupèrent pas les messages sur tous les appareils, car le fournisseur de contenu Uri change d'appareil et de fabricant.

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
la source
9
Semble être la seule réponse qui n'utilise pas d'API non documentée et ne fait pas référence à des bibliothèques tierces.
Ishamael
J'ai essayé d'utiliser ce code pour obtenir des SMS à partir de Hangouts (qui est mon application SMS par défaut). Au lieu de cela, il a récupéré le dernier message sortant que j'ai envoyé via Messenger ... Savez-vous ce qui cause cela?
Miki P
@MikiP en utilisant mes pouvoirs de devinette, je dirai que l'application Messenger vous a demandé de remplacer la gestion des SMS par Messenger. Cela arrive avec une autre application de messagerie. Je n'ai pas d'autre explication.
m3nda
2
N'oubliez pas d'appeler c.close ();
Cícero Moura
1
@SardarAgabejli Si nous utilisons des valeurs enregistrées comme "contenturi: sms", ce ne sera pas le même pour tous les appareils, mais si nous utilisons la classe de téléphonie, nous obtenons un accès direct à cet uri conetnt ou au chemin du sms db de cet appareil, c'est une classe d'aide pour pointer vers la base de données de sms
Manoj Perumarath
23

Ce message est un peu ancien, mais voici une autre solution simple pour obtenir des données liées au SMSfournisseur de contenu dans Android:

Utilisez cette lib: https://github.com/EverythingMe/easy-content-providers

  • Obtenez tout SMS:

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

    Chaque Sms possède tous les champs, vous pouvez donc obtenir toutes les informations dont vous avez besoin:
    adresse, corps, date de réception, type (INBOX, SENT, DRAFT, ..), threadId, ...

  • Gel tout MMS:

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

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

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

Il fonctionne avec Listou Cursoret il existe un exemple d'application pour voir à quoi il ressemble et fonctionne.

En fait, il existe un support pour tous les fournisseurs de contenu Android tels que: contacts, journaux d'appels, calendrier, ... Doc complet avec toutes les options: https://github.com/EverythingMe/easy-content-providers/wiki/Android- fournisseurs

J'espère que cela a également aidé :)

sromku
la source
1
Le code source et les exemples sur le github sont assez utiles. Il s'agit d'une bonne enveloppe / façade pour la plupart des fournisseurs courants. Je vous remercie.
m3nda
14

Étape 1: nous devons d'abord ajouter des autorisations dans le fichier manifeste comme

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

Étape 2: puis ajoutez la classe de récepteur SMS de service pour recevoir des SMS

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

Étape 3: ajouter l'autorisation d'exécution

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

Étape 4: Ajoutez ces classes dans votre application et testez la 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
la source
Que fait le motif?
Mark Buikema
Eh bien ... est-ce ("com.aquadeals.seller.services.SmsReceiver") le nom de service commun?
m3nda
Ya qui n'est pas le nom du service, c'est le chemin de classe SmsReceiver dans mon application
Venkatesh
Pourquoi avoir besoin d'une autorisation pour LOCATION?
Zam Sunk
1
j'essaye de faire une application qui fait apparaître le contenu sms à l'utilisateur même si l'application a été tuée
Anjani Mittal
11

Il y a beaucoup de réponses déjà disponibles mais je pense que toutes manquent une partie importante de cette question. Avant de lire les données d'une base de données interne ou de sa table, nous devons comprendre comment les données y sont stockées et ensuite nous pouvons trouver la solution de la question ci-dessus qui est:

Comment puis-je lire les messages SMS de l'appareil par programmation dans Android?

Donc, dans la table SMS Android, c'est comme ça

entrez la description de l'image ici

Sachez que nous pouvons sélectionner ce que nous voulons dans la base de données. Dans notre cas, nous

identifiant, adresse et corps

En cas de lecture de SMS:

1.Demander des autorisations

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

Maintenant, votre code va comme ça

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

J'espère que celui-ci vous sera utile. Merci.

Nitin Khanna
la source
7

Les services Google Play disposent de deux API que vous pouvez utiliser pour rationaliser le processus de vérification par SMS

API SMS Retriever

Fournit une expérience utilisateur entièrement automatisée, sans obliger l'utilisateur à taper manuellement les codes de vérification et sans nécessiter d'autorisations d'application supplémentaires et doit être utilisé lorsque cela est possible. Cependant, il vous oblige à placer un code de hachage personnalisé dans le corps du message, vous devez donc également contrôler le côté serveur .

  • Exigences relatives aux messages - Code de hachage à 11 chiffres qui identifie de manière unique votre application
  • Exigences de l'expéditeur - Aucune
  • Interaction utilisateur - Aucune

Demander une vérification par SMS dans une application Android

Effectuer une vérification SMS sur un serveur

API de consentement de l'utilisateur SMS

Ne nécessite pas le code de hachage personnalisé, mais oblige l'utilisateur à approuver la demande de votre application pour accéder au message contenant le code de vérification. Afin de minimiser les chances de faire apparaître le mauvais message à l'utilisateur, SMS User Consentfiltrera les messages des expéditeurs dans la liste des contacts de l'utilisateur.

  • Exigences relatives aux messages - Code alphanumérique de 4 à 10 chiffres contenant au moins un numéro
  • Conditions requises pour l'expéditeur - L'expéditeur ne peut pas figurer dans la liste des contacts de l'utilisateur
  • Interaction avec l'utilisateur - Un robinet pour approuver

The SMS User Consent APIfait partie des services Google Play. Pour l'utiliser, vous aurez besoin d'au moins une version 17.0.0de ces bibliothèques:

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

Étape 1: Commencez à écouter les messages SMS

Le consentement de l'utilisateur SMS écoutera les messages SMS entrants contenant un code à usage unique pendant cinq minutes maximum. Il ne regardera aucun message envoyé avant son démarrage. Si vous connaissez le numéro de téléphone qui enverra le code à usage unique, vous pouvez spécifier le senderPhoneNumber, ou si vous ne nullcorrespondez à aucun numéro.

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

Étape 2: demander le consentement pour lire un message

Une fois que votre application reçoit un message contenant un code à usage unique, elle sera notifiée par une diffusion. À ce stade, vous n'avez pas le consentement pour lire le message - à la place, vous obtenez un Intentque vous pouvez commencer à inviter l'utilisateur à donner son consentement. Dans votre BroadcastReceiver, vous affichez l'invite en utilisant le Intentdans le extras. Lorsque vous démarrez cette intention, il demandera à l'utilisateur l'autorisation de lire un seul message. Ils verront l'intégralité du texte qu'ils partageront avec votre application.

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

entrez la description de l'image ici

Étape 3: analyser le code unique et terminer la vérification SMS

Lorsque l'utilisateur clique “Allow”- il est temps de lire le message! À l'intérieur de onActivityResultvous, vous pouvez obtenir le texte intégral du message SMS à partir des données:

val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)

Vous analysez ensuite le message SMS et passez le code à usage unique à votre backend!

Levon Petrosyan
la source
4-10 digit alphanumeric code containing at least one numberPouvez-vous expliquer ce que cela signifie? Cela signifie-t-il que la longueur du message entier doit être de 4 à 10 caractères uniquement du code sms?
Zeeshan Shabbir
Merci aussi
Levon Petrosyan
Cela ne fonctionne que pour la vérification OTP, non? Qu'en est-il de la lecture de tous les autres messages à l'intérieur du téléphone, de tous les SMS, etc.? Existe-t-il une nouvelle API pour cela, faites-le moi savoir. Bon codage! :)
Manoj Perumarath
Nous avons toujours eu l'erreur de timeout. S'il vous plaît aidez-moi
Manikandan K
2
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;

changé par:

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

Code Kotlin pour lire les SMS:

1- Ajoutez cette autorisation à AndroidManifest.xml:

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

2-Créez une 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-Obtenez l'autorisation SMS si Android 6 et supérieur:

   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- Ajoutez ce code de demande à l'activité ou au fragment:

 companion object {
    const val PERMISSIONS_REQUEST_READ_SMS = 100
   }

5- Override Check permissionstion Request result fun:

 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
la source
1

La fonction la plus simple

Pour lire le sms j'ai écrit une fonction qui retourne un objet Conversation:

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

En utilisant:

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 obtenez uniquement la conversation d'un numéro spécifique:

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
la source