我想从设备中检索并显示SMS消息?


当前回答

目前已有多种答案,但我认为所有答案都忽略了这个问题的一个重要部分。 在从内部数据库或其表中读取数据之前,我们必须了解数据是如何存储在其中的,只有这样我们才能找到上述问题的解决方案:

如何在Android系统下以编程方式从设备上读取短信?

在android中,短信表是这样的

现在您可以从数据库中选择您想要的任何内容。在我们的例子中,我们只需要

身份,地址和正文

阅读短信时:

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

or

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

我希望这对你有所帮助。 谢谢。

其他回答

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

改变了:

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

目前已有多种答案,但我认为所有答案都忽略了这个问题的一个重要部分。 在从内部数据库或其表中读取数据之前,我们必须了解数据是如何存储在其中的,只有这样我们才能找到上述问题的解决方案:

如何在Android系统下以编程方式从设备上读取短信?

在android中,短信表是这样的

现在您可以从数据库中选择您想要的任何内容。在我们的例子中,我们只需要

身份,地址和正文

阅读短信时:

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

or

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

我希望这对你有所帮助。 谢谢。

这是一个微不足道的过程。您可以在源代码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;
}

最简单的函数

为了读取短信,我写了一个返回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)
    }

使用:

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

谷歌Play服务有两个api,可用于简化基于短信的验证过程

短信检索器接口

提供完全自动化的用户体验,不需要用户手动输入验证码,也不需要任何额外的应用权限,应该在可能的情况下使用。但是,它要求您在消息体中放置自定义哈希代码,因此您还必须控制服务器端。

消息要求-唯一标识应用程序的11位哈希码 发件人要求—无 用户交互—无

在Android应用程序中请求短信验证

在服务器上进行短信验证

短信用户同意API

不需要自定义哈希码,但需要用户批准你的应用程序的请求,以访问包含验证码的消息。为了最大限度地减少向用户显示错误消息的机会,SMS用户同意将从用户的联系人列表中过滤出发件人的消息。

消息要求-至少包含一个数字的4-10位字母数字代码 发件人要求-发件人不能在用户的联系人列表中 用户交互-一键批准

短信用户同意API是谷歌播放服务的一部分。要使用它,你至少需要这些库的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"

第一步:开始监听短信

SMS用户同意将监听包含一次性代码的传入SMS消息长达五分钟。它不会查看在启动之前发送的任何消息。如果知道发送一次性代码的电话号码,则可以指定senderPhoneNumber,如果不指定,则null将匹配任何号码。

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

步骤2:请求同意阅读消息

一旦你的应用程序接收到包含一次性代码的消息,它就会被广播通知。在这一点上,你没有同意阅读消息-相反,你给了一个意图,你可以开始提示用户同意。在你的BroadcastReceiver内部,你使用extras中的Intent来显示提示。 当您启动该意图时,它将提示用户允许读取单个消息。他们将会看到与你的应用共享的全部文本。

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

第三步:解析一次性代码,完成短信验证

当用户点击“允许”-是时候真正阅读消息了!在onActivityResult内部,你可以从数据中获得短信的全文:

val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)

然后解析SMS消息并将一次性代码传递到后端!