Как я могу читать SMS-сообщения с устройства программно в Android?

Я хочу получить SMS-сообщения с устройства и отобразить их?

Ответ 1

Используйте Content Resolver ("content://sms/inbox" ), чтобы читать SMS, находящиеся во входящих.

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

Добавьте READ_SMS.

Надеюсь, это поможет:)

Ответ 2

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

Установить приложение как приложение SMS по умолчанию

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

Функция получения 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 ниже:

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

}

Не забудьте указать разрешение в вашем AndroidManifest.xml

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

Ответ 3

Это тривиальный процесс. Вы можете увидеть хороший пример в исходном коде SMSPopup

Изучите следующие методы:

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)

это метод чтения:

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

Ответ 4

Это сообщение немного устарело, но вот еще одно простое решение для получения данных, связанных с SMS поставщиком контента в Android:

Используйте этот lib: https://github.com/EverythingMe/easy-content-providers

  • Получить все SMS:

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

    Каждый Sms имеет все поля, поэтому вы можете получить любую необходимую информацию:
    адрес, тело, receivedDate, тип (INBOX, SENT, DRAFT,..), threadId,...

  • Гель all MMS:

    List<Mms> mmses = telephonyProvider.getMms(Filter.ALL).getList();
    
  • Гель all Thread:

    List<Thread> threads = telephonyProvider.getThreads().getList();
    
  • Гель all Conversation:

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

Он работает с List или Cursor, и есть пример приложения, чтобы увидеть, как он выглядит и работает.

Фактически, есть поддержка для всех поставщиков контента Android, таких как: Контакты, Журналы вызовов, Календарь,... Полный документ со всеми опциями: https://github.com/EverythingMe/easy-content-providers/wiki/Android-providers

Надеюсь, это также помогло:)

Ответ 5

Начиная с API 19 для этого вы можете использовать класс телефонии; Так как жестко заданные значения не будут получать сообщения на всех устройствах, потому что поставщик контента Uri меняется от устройств и производителей.

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

Ответ 6

Шаг 1: сначала мы должны добавить разрешения в файл манифеста, как

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

Шаг 2: затем добавьте сервисный класс получателя смс для получения смс

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

Шаг 3: Добавить разрешение во время выполнения

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

Шаг 4. Добавьте эти классы в ваше приложение и протестируйте интерфейсный класс.

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

Ответ 7

Есть много уже доступных ответов, но я думаю, что все они упускают важную часть этого вопроса. Прежде чем читать данные из внутренней базы данных или ее таблицы, мы должны понять, как в ней хранятся данные, а затем найти решение вышеуказанного вопроса:

Как программно читать SMS-сообщения с устройства в Android?

Итак, в андроид смс таблица выглядит примерно так

enter image description here

Знайте, мы можем выбрать все, что мы хотим из базы данных. В нашем случае нам требуется только

идентификатор, адрес и тело

В случае чтения SMS:

1. Спросите разрешения

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

или

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

2. Теперь ваш код выглядит так

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

Я надеюсь, что это будет полезно. Благодарю.

Ответ 8

String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;

изменено:

String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0 " : SMS_READ_COLUMN + " = 1 ";

Ответ 9

Сервисы Google Play имеют два API, которые вы можете использовать для упрощения процесса проверки на основе SMS

API ретривера SMS

Предоставляет полностью автоматизированный пользовательский интерфейс, не требуя от пользователя ручного ввода кодов проверки и не требуя каких-либо дополнительных разрешений приложения, и должен использоваться по возможности. Однако он требует от вас размещения собственного хеш-кода в теле сообщения, поэтому вы должны также контролировать серверную часть.

  • Требования к сообщениям - 11-значный хэш-код, который однозначно идентифицирует ваше приложение
  • Требования к отправителю - нет
  • Взаимодействие с пользователем - нет

Запросить подтверждение по SMS в приложении для Android

Выполнить проверку SMS на сервере

API согласия пользователя SMS

Не требует специального хеш-кода, однако требует, чтобы пользователь одобрил ваш запрос приложения, чтобы получить доступ к сообщению, содержащему проверочный код. Чтобы свести к минимуму вероятность появления неправильного сообщения для пользователя, SMS User Consent отфильтровывает сообщения от отправителей в списке контактов пользователя.

  • Требования к сообщению - 4-10-значный буквенно-цифровой код, содержащий не менее одного номера
  • Требования к отправителю - Отправитель не может быть в списке контактов пользователя
  • Взаимодействие с пользователем - одно нажатие для подтверждения

The SMS User Consent API является частью Сервисов Google Play. Для его использования вам потребуется как минимум версия 17.0.0 этих библиотек:

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

Шаг 1. Начните прослушивать SMS-сообщения

SMS User Consent будет прослушивать входящие SMS-сообщения, содержащие одноразовый код, до пяти минут. Он не будет смотреть на любые сообщения, которые отправляются до его запуска. Если вы знаете номер телефона, на который будет отправлен одноразовый код, вы можете указать senderPhoneNumber, или, если вы не наберете null, он будет соответствовать любому номеру.

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

Шаг 2. Запрос согласия на чтение сообщения

Как только ваше приложение получит сообщение, содержащее одноразовый код, оно будет уведомлено о трансляции. На данный момент у вас нет согласия на чтение сообщения - вместо этого вы получили Intent, что вы можете начать запрашивать согласие пользователя. Внутри BroadcastReceiver вы показываете подсказку, используя Intent в extras. Когда вы запускаете это намерение, он запрашивает у пользователя разрешение на чтение одного сообщения. Им будет показан весь текст, которым они поделятся с вашим приложением.

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

enter image description here

Шаг 3. Разбор одноразового кода и завершение SMS-проверки.

Когда пользователь нажимает 'Allow' - самое время прочитать сообщение! Внутри onActivityResult вы можете получить полный текст SMS-сообщения из данных:

val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)

Затем вы анализируете SMS-сообщение и передаете одноразовый код своему бэкэнду!

Ответ 10

Код Котлина для чтения смс:

1- Добавьте это разрешение в AndroidManifest.xml:

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

2-Создать класс 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-Получить SMS-разрешение, если Android 6 и выше:

   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- Добавьте этот код запроса в Activity или фрагмент:

 companion object {
    const val PERMISSIONS_REQUEST_READ_SMS = 100
   }

5- Переопределить проверку разрешения запроса.

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

Ответ 11

Самая простая функция

Чтобы прочитать смс, я написал функцию, которая возвращает объект беседы:

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

С помощью:

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

Или получить только разговор на конкретный номер:

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

Ответ 12

Поскольку Google ограничил использование разрешения READ_SMS, здесь есть решение без разрешения READ_SMS.

API SMS Retriever

Основная функция состоит в том, чтобы избежать использования критического разрешения Android READ_SMS и выполнить задачу, используя этот метод. Удар это шаги, которые вам нужны.

Отправлять OTP на номер пользователя, проверять, может ли SMS Retriever API получать сообщения или нет

SmsRetrieverClient client = SmsRetriever.getClient(SignupSetResetPasswordActivity.this);
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
    @Override
    public void onSuccess(Void aVoid) {
        // Android will provide message once receive. Start your broadcast receiver.
        IntentFilter filter = new IntentFilter();
        filter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);
        registerReceiver(new SmsReceiver(), filter);
    }
});
task.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        // Failed to start retriever, inspect Exception for more details
    }
});

Код приемника вещания

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;

import com.google.android.gms.auth.api.phone.SmsRetriever;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;

public class SmsReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
            Bundle extras = intent.getExtras();
            Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

            switch (status.getStatusCode()) {
                case CommonStatusCodes.SUCCESS:
                    // Get SMS message contents
                    String otp;
                    String msgs = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);

                    // Extract one-time code from the message and complete verification
                    break;
                case CommonStatusCodes.TIMEOUT:
                    // Waiting for SMS timed out (5 minutes)
                    // Handle the error ...
                    break;
            }
        }
    }
}

Заключительный этап. Зарегистрируйте этот приемник в своем манифесте

<receiver android:name=".service.SmsReceiver" android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
    </intent-filter>
</receiver>