如何在 Android 中以编程方式从设备读取 SMS 消息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/848728/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I read SMS messages from the device programmatically in Android?
提问by
I want to retrieve the SMS messages from the device and display them?
我想从设备中检索 SMS 消息并显示它们?
回答by Suryavel TR
Use Content Resolver ("content://sms/inbox") to read SMS which are in inbox.
使用内容解析器(“content://sms/inbox”)读取收件箱中的短信。
// 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
}
Please add READ_SMSpermission.
请添加READ_SMS权限。
I Hope it helps :)
我希望它有帮助:)
回答by Atif Mahmood
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();
}
Set app as default SMS app
将应用设置为默认短信应用
@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();
}
}
}
}
}
Function to get 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 class is below:
短信类如下:
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;
}
}
Don't forget to define permission in your AndroidManifest.xml
不要忘记在 AndroidManifest.xml 中定义权限
<uses-permission android:name="android.permission.READ_SMS" />
回答by ?mer
It is a trivial process. You can see a good example in the source code SMSPopup
这是一个微不足道的过程。你可以在源代码SMSPopup 中看到一个很好的例子
Examine the following methods:
检查以下方法:
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)
this is the method for reading:
这是阅读方法:
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;
}
回答by Manoj Perumarath
From API 19 onwards you can make use of the Telephony Class for that; Since hardcored values won't retrieve messages in every devices because the content provider Uri changes from devices and manufacturers.
从 API 19 开始,您可以为此使用 Telephony Class;由于硬核值不会在每个设备中检索消息,因为内容提供者 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();
}
}
回答by sromku
This post is a little bit old, but here is another easy solution for getting data related to SMS
content provider in Android:
这篇文章有点旧,但这里有另一种SMS
在 Android 中获取与内容提供者相关的数据的简单解决方案:
Use this lib: https://github.com/EverythingMe/easy-content-providers
使用这个库:https: //github.com/EverythingMe/easy-content-providers
Get all
SMS
:TelephonyProvider telephonyProvider = new TelephonyProvider(context); List<Sms> smses = telephonyProvider.getSms(Filter.ALL).getList();
Each Smshas all fields, so you can get any info you need:
address, body, receivedDate, type(INBOX, SENT, DRAFT, ..), threadId, ...Gel all
MMS
:List<Mms> mmses = telephonyProvider.getMms(Filter.ALL).getList();
Gel all
Thread
:List<Thread> threads = telephonyProvider.getThreads().getList();
Gel all
Conversation
:List<Conversation> conversations = telephonyProvider.getConversations().getList();
获取所有
SMS
:TelephonyProvider telephonyProvider = new TelephonyProvider(context); List<Sms> smses = telephonyProvider.getSms(Filter.ALL).getList();
每个短信都有所有字段,因此您可以获得所需的任何信息:
地址、正文、接收日期、类型(收件箱、发送、草稿、..)、线程 ID、...凝胶全部
MMS
:List<Mms> mmses = telephonyProvider.getMms(Filter.ALL).getList();
凝胶全部
Thread
:List<Thread> threads = telephonyProvider.getThreads().getList();
凝胶全部
Conversation
:List<Conversation> conversations = telephonyProvider.getConversations().getList();
It works with List
or Cursor
and there is a sample app to see how it looks and works.
它与List
or一起使用,Cursor
并且有一个示例应用程序可以查看它的外观和工作方式。
In fact, there is a support for all Android content providers like: Contacts, Call logs, Calendar, ...Full doc with all options: https://github.com/EverythingMe/easy-content-providers/wiki/Android-providers
事实上,它支持所有 Android 内容提供程序,例如:联系人、通话记录、日历……包含所有选项的完整文档:https: //github.com/EverythingMe/easy-content-providers/wiki/Android-提供者
Hope it also helped :)
希望它也有帮助:)
回答by Venkatesh
Step 1:first we have to add permissions in manifest file like
第 1 步:首先我们必须在清单文件中添加权限,例如
<uses-permission android:name="android.permission.RECEIVE_SMS" android:protectionLevel="signature" />
<uses-permission android:name="android.permission.READ_SMS" />
Step 2:then add service sms receiver class for receiving sms
第二步:然后添加服务短信接收器类用于接收短信
<receiver android:name="com.aquadeals.seller.services.SmsReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
Step 3:Add run time permission
第 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;
}
Step 4:Add this classes in your app and test Interface class
第 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; }}
回答by Nitin Khanna
There are lots of answers are already available but i think all of them are missing an important part of this question. Before reading data from an internal database or its table we have to understand how data is stored in it and then we can find the solution of the above question that is :
已经有很多答案可用,但我认为所有答案都遗漏了这个问题的一个重要部分。在从内部数据库或其表中读取数据之前,我们必须了解数据是如何存储在其中的,然后我们才能找到上述问题的解决方案:
How can I read SMS messages from the device programmatically in Android?
如何在 Android 中以编程方式从设备读取 SMS 消息?
So,In android SMS table is like look like this
所以,在 android SMS 表是这样的
Know,we can select whatever we want from the database.In our case we have only required
知道,我们可以从数据库中选择我们想要的任何东西。在我们的例子中,我们只需要
id,address and body
ID、地址和正文
In case of reading SMS:
在阅读短信的情况下:
1.Ask for permissions
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.Now your code goes like this
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);
I hope this one will be helpful. Thanks.
我希望这会有所帮助。谢谢。
回答by Levon Petrosyan
Google Play services has two APIs you can use to streamline the SMS-based verification process
Google Play 服务有两个 API,可用于简化基于 SMS 的验证过程
Provides a fully automated user experience, without requiring the user to manually type verification codes and without requiring any extra app permissions and should be used when possible. It does, however, require you to place a custom hash code in the message body, so you must have control over server side as well.
提供完全自动化的用户体验,无需用户手动输入验证码,无需任何额外的应用程序权限,应尽可能使用。但是,它确实需要您在消息正文中放置自定义哈希码,因此您也必须控制服务器端。
- Message requirements- 11-digit hash code that uniquely identifies your app
- Sender requirements- None
- User interaction- None
- 消息要求- 唯一标识您的应用程序的 11 位哈希码
- 发件人要求- 无
- 用户交互- 无
Request SMS Verification in an Android App
Perform SMS Verification on a Server
Does not require the custom hash code, however require the user to approve your app's request to access the message containing the verification code. In order to minimize the chances of surfacing the wrong message to the user, SMS User Consent
will filter out messages from senders in the user's Contacts list.
不需要自定义哈希码,但需要用户批准您的应用程序访问包含验证码的消息的请求。为了尽量减少向用户显示错误消息的机会,SMS User Consent
将在用户的联系人列表中过滤掉来自发件人的消息。
- Message requirements- 4-10 digit alphanumeric code containing at least one number
- Sender requirements- Sender cannot be in the user's Contacts list
- User interaction- One tap to approve
- 消息要求- 4-10 位字母数字代码,至少包含一个数字
- 发件人要求- 发件人不能在用户的联系人列表中
- 用户交互- 一键批准
The SMS User Consent API
is part of Google Play Services. To use it you'll need at least version 17.0.0
of these libraries:
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"
Step 1: Start listening for SMS messages
第 1 步:开始侦听 SMS 消息
SMS User Consent will listen for incoming SMS messages that contain a one-time-code for up to five minutes. It won't look at any messages that are sent before it's started. If you know the phone number that will send the one-time-code, you can specify the senderPhoneNumber
, or if you don't null
will match any number.
SMS 用户同意将侦听包含一次性代码的传入 SMS 消息长达五分钟。它不会查看在启动之前发送的任何消息。如果您知道将发送一次性代码的电话号码,您可以指定senderPhoneNumber
,否则null
将匹配任何号码。
smsRetriever.startSmsUserConsent(senderPhoneNumber /* or null */)
Step 2: Request consent to read a message
第 2 步:请求同意阅读消息
Once your app receives a message containing a one-time-code, it'll be notified by a broadcast. At this point, you don't have consent to read the message — instead you're given an Intent
that you can start to prompt the user for consent. Inside your BroadcastReceiver
, you show the prompt using the Intent
in the extras
.
When you start that intent, it will prompt the user for permission to read a single message. They'll be shown the entire text that they will share with your app.
一旦您的应用收到一条包含一次性代码的消息,它就会收到广播通知。在这一点上,您没有同意阅读该消息——相反,您会得到一个Intent
,您可以开始提示用户同意。里面您BroadcastReceiver
,您可以使用显示提示Intent
中extras
。当您启动该意图时,它会提示用户授予阅读单条消息的权限。他们将看到他们将与您的应用共享的整个文本。
val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
Step 3: Parse the one-time-code and complete SMS Verification
第三步:解析一次性代码并完成短信验证
When the user clicks “Allow”
— it's time to actually read the message! Inside of onActivityResult
you can get the full text of the SMS Message from the data:
当用户点击时“Allow”
——是时候真正阅读消息了!在里面onActivityResult
你可以从数据中获取短信的全文:
val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
You then parse the SMS message and pass the one-time-code to your backend!
然后您解析 SMS 消息并将一次性代码传递给您的后端!
回答by Van Hau Hoang
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;
changed by:
更改为:
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0 " : SMS_READ_COLUMN + " = 1 ";
回答by Hamed Jaliliani
Kotlin Code to read SMS :
Kotlin 代码读取短信:
1- Add this permission to AndroidManifest.xml :
1- 将此权限添加到 AndroidManifest.xml :
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
2-Create a BroadCastreceiver Class :
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-Get SMS Permission if Android 6 and above:
3-如果 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- Add this request code to Activity or fragment :
4- 将此请求代码添加到 Activity 或 fragment :
companion object {
const val PERMISSIONS_REQUEST_READ_SMS = 100
}
5- Override Check permisstion Request result fun :
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 ")
}
}
}
}