¿Quiero recuperar los mensajes SMS del dispositivo y mostrarlos?
¿Quiero recuperar los mensajes SMS del dispositivo y mostrarlos?
Respuestas:
Use Content Resolver ( "content: // sms / inbox" ) para leer los SMS que están en la bandeja 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 agregue READ_SMS permiso.
Espero que ayude :)
moveToFirst
como yo lo hice.
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();
}
Establecer aplicación como aplicación de SMS predeterminada
@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();
}
}
}
}
}
Función para recibir 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 clase de SMS está abajo:
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;
}
}
No olvides definir el permiso en tu AndroidManifest.xml
<uses-permission android:name="android.permission.READ_SMS" />
String receiveDayTime = Functions.dateFromMilisec(Long.valueOf(c.getColumnIndexOrThrow("date")), "hh:mm a MMM dd, yyyy");
new SimpleDateFormat("hh:mm", Locale.US).format(new Date(Long.parseLong(_time)));
Esto te dará 24 horas de tiempo.
mActivity
no está definido. ¿Que es esto?
Es un proceso trivial. Puedes ver un buen ejemplo en el código fuente SMSPopup
Examine los siguientes 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 es el método de lectura:
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;
}
Desde API 19 en adelante, puede hacer uso de la Clase de telefonía para eso; Dado que los valores codificados no recuperarán mensajes en todos los dispositivos porque el proveedor de contenido Uri cambia de dispositivos y 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();
}
}
Esta publicación es un poco antigua, pero aquí hay otra solución fácil para obtener datos relacionados con SMS
proveedor de contenido en Android:
Use esta biblioteca: https://github.com/EverythingMe/easy-content-providers
Obtén todo SMS
:
TelephonyProvider telephonyProvider = new TelephonyProvider(context);
List<Sms> smses = telephonyProvider.getSms(Filter.ALL).getList();
Cada SMS tiene todos los campos, por lo que puede obtener cualquier información que necesite:
dirección, cuerpo, fecha de recepción, tipo (INBOX, SENT, DRAFT, ..), threadId, ...
Gel todo MMS
:
List<Mms> mmses = telephonyProvider.getMms(Filter.ALL).getList();
Gel todo Thread
:
List<Thread> threads = telephonyProvider.getThreads().getList();
Gel todo Conversation
:
List<Conversation> conversations = telephonyProvider.getConversations().getList();
Funciona con List
o Cursor
y hay una aplicación de muestra para ver cómo se ve y funciona.
De hecho, hay un soporte para todos los proveedores de contenido de Android como: Contactos, Registros de llamadas, Calendario, ... Documento completo con todas las opciones: https://github.com/EverythingMe/easy-content-providers/wiki/Android- proveedores
Espero que también haya ayudado :)
Paso 1: primero tenemos que agregar permisos en el archivo de manifiesto como
<uses-permission android:name="android.permission.RECEIVE_SMS" android:protectionLevel="signature" />
<uses-permission android:name="android.permission.READ_SMS" />
Paso 2: luego agregue la clase de receptor de sms de servicio para recibir sms
<receiver android:name="com.aquadeals.seller.services.SmsReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
Paso 3: Agregar permiso de tiempo de ejecución
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;
}
Paso 4: Agregue estas clases en su aplicación y pruebe la clase de interfaz
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; }}
Ya hay muchas respuestas disponibles, pero creo que a todas ellas les falta una parte importante de esta pregunta. Antes de leer los datos de una base de datos interna o su tabla, debemos comprender cómo se almacenan los datos en ella y luego podemos encontrar la solución de la pregunta anterior que es:
¿Cómo puedo leer mensajes SMS desde el dispositivo mediante programación en Android?
Entonces, en la tabla de SMS de Android es como se ve así
Sabe, podemos seleccionar lo que queramos de la base de datos. En nuestro caso solo hemos requerido
identificación, dirección y cuerpo
En caso de leer SMS:
1. Pida permisos
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);
}
o
<uses-permission android:name="android.permission.READ_SMS" />
2. Ahora su código va así
// 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 sea útil. Gracias.
Los servicios de Google Play tienen dos API que puede usar para optimizar el proceso de verificación basado en SMS
Proporciona una experiencia de usuario totalmente automatizada, sin requerir que el usuario escriba manualmente códigos de verificación y sin requerir ningún permiso adicional de la aplicación y debe usarse cuando sea posible. Sin embargo, requiere que coloque un código hash personalizado en el cuerpo del mensaje, por lo que también debe tener control sobre el lado del servidor .
Solicitar verificación de SMS en una aplicación de Android
Realizar verificación de SMS en un servidor
API de consentimiento de usuario de SMS
No requiere el código hash personalizado, sin embargo, requiere que el usuario apruebe la solicitud de su aplicación para acceder al mensaje que contiene el código de verificación. Para minimizar las posibilidades de que el usuario muestre un mensaje incorrecto, SMS User Consent
filtrará los mensajes de los remitentes en la lista de Contactos del usuario.
The SMS User Consent API
forma parte de los servicios de Google Play. Para usarlo, necesitará al menos la versión 17.0.0
de estas 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"
Paso 1: Comience a escuchar mensajes SMS
El consentimiento del usuario de SMS escuchará los mensajes SMS entrantes que contengan un código único durante un máximo de cinco minutos. No verá ningún mensaje que se envíe antes de que comience. Si conoce el número de teléfono que enviará el código de una sola vez, puede especificar el senderPhoneNumber
, o si no null
, coincidirá con cualquier número.
smsRetriever.startSmsUserConsent(senderPhoneNumber /* or null */)
Paso 2: Solicite consentimiento para leer un mensaje
Una vez que su aplicación recibe un mensaje que contiene un código único, se le notificará por una transmisión. En este punto, no tiene consentimiento para leer el mensaje; en su lugar, se le otorga un Intent
mensaje que puede comenzar a solicitar al usuario para obtener su consentimiento. Dentro de su BroadcastReceiver
, muestra el mensaje utilizando Intent
el extras
. Cuando comience esa intención, solicitará al usuario permiso para leer un solo mensaje. Se les mostrará el texto completo que compartirán con su aplicación.
val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
Paso 3: Analice el código único y complete la verificación por SMS
Cuando el usuario hace clic “Allow”
, ¡es hora de leer el mensaje! Dentro de onActivityResult
usted puede obtener el texto completo del mensaje SMS de los datos:
val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
¡Luego analiza el mensaje SMS y pasa el código único a tu backend!
4-10 digit alphanumeric code containing at least one number
¿Puedes explicar qué significa eso? ¿Significa que la longitud del mensaje completo debe ser de 4 a 10 caracteres solo del código sms?
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;
cambiado por:
String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0 " : SMS_READ_COLUMN + " = 1 ";
Código de Kotlin para leer SMS:
1- Agregue este permiso a AndroidManifest.xml:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
2-Crear una clase de receptor BroadCast:
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-Obtenga permiso de SMS si Android 6 y 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- Agregue este código de solicitud a la Actividad o fragmento:
companion object {
const val PERMISSIONS_REQUEST_READ_SMS = 100
}
5- Anulación de verificación de permisos 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 ")
}
}
}
}
La función más fácil
Para leer el sms escribí una función que devuelve un objeto de conversación:
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)
}
Utilizando:
getSmsConversation(this){ conversations ->
conversations.forEach { conversation ->
println("Number: ${conversation.number}")
println("Message One: ${conversation.message[0].body}")
println("Message Two: ${conversation.message[1].body}")
}
}
O obtenga solo una conversación de un 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}")
}
}