Enviar, recibir y ver el historial de SMS con Android

En este tutorial te mostraremos un ejemplo práctico paso a paso sobre cómo enviar, recibir y listar el historial de SMS con Android para tus propios proyectos. Intentaremos explicar las distintas vías para hacer esto posible así como un pequeño desarrollo donde veréis todo lo explicado en práctica. Sin más dilación, paso a explicaros como enviar, recibir y ver el historial de SMS con Android

Podemos enviar SMS a través de 2 vías - con intent o sin intent. Cualquier envío de SMS requiere permiso android.permission.SEND_SMS:

 <manifest ...>
    
    <uses-sdk .../>    
    
    <uses-permission android:name="android.permission.SEND_SMS"/>

    <application
        ...>
        ...

</manifest>

Enviar SMS

Con Intent

Directamente a través de la aplicación SMS / MMS

Esto código fuerza a la aplicación SMS/MMS de Android a abrirse con un número de teléfono y un texto SMS especificado. A continuación, el usuario puede pulsar el botón "Enviar", y se enviará el SMS.

Requiere el permiso android.permission.SEND_SMS (ver arriba).

strPhone = "XXXXXXXXXXX";
strMessage = "LoremnIpsum";
            
Intent sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.setType("vnd.android-dir/mms-sms");
sendIntent.putExtra("address", strPhone);
sendIntent.putExtra("sms_body", strMessage); 
startActivity(sendIntent);

A través de aplicaciones por defecto

Este código ejecuta la url "smsto: + XXXXXXXXXXX", Android lo procesa, y ejecuta la aplicación por defecto que está asignada para manejar el protocolo smsto.

Por defecto, es la aplicación SMS/MMS de Android (ver intent de más arriba). Pero si instalamos cualquier aplicación de terceros que también pueda manejar SMS y se establezca como manejador smsto (es decir, Skype), la primera vez que recibamos uno de estos SMS nos aparecerá una ventana donde debemos elegir entre la aplicación integrada y esta aplicación de terceros. Todo un inconveniente.

Requiere el permiso android.permission.SEND_SMS (ver arriba).

strPhone = "XXXXXXXXXXX";
strMessage = "LoremnIpsum";
            
Uri sms_uri = Uri.parse("smsto:+" + strPhone); 
Intent sms_intent = new Intent(Intent.ACTION_SENDTO, sms_uri); 
sms_intent.putExtra("sms_body", txtMessage.getText().toString()); 
startActivity(sms_intent); 

Sin Intent

SmsManager.sendTextMessage()

Requiere el permiso android.permission.SEND_SMS (ver arriba).

String strPhone = "XXXXXXXXXXX";

String strMessage = "LoremnIpsum";
            
SmsManager sms = SmsManager.getDefault();
            
sms.sendTextMessage(strPhone, null, strMessage, null, null);
            
Toast.makeText(this, "Sent.", Toast.LENGTH_SHORT).show();

SmsManager.sendMultipartTextMessage() -  Si el mensaje es más largo de 160 caracteres

Si el tamaño del SMS supera cierto límite (normalmente son 160 caracteres), la función sendTextMessage() no lo enviará. Debemos usar sendMultipartTextMessage() en estos casos.

Requiere el permiso android.permission.SEND_SMS (ver arriba).

String strPhone = "XXXXXXXXXXX";
String strMessage = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890TEST";
            
SmsManager sms = SmsManager.getDefault();
            
ArrayList messageParts = sms.divideMessage(strMessage);
            
sms.sendMultipartTextMessage(strPhone, null, messageParts, null, null);
            
Toast.makeText(this, "Sent.", Toast.LENGTH_SHORT).show();

Comprobar si el dispositivo puede enviar SMS

PackageManager pm = this.getPackageManager();

if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) &&
    !pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA)) {
    Toast.makeText(this, "Lo sentimos, tu dispositivo probablemente no pueda enviar SMS...", Toast.LENGTH_SHORT).show();
 }

Recibir SMS

Permisos:

 <manifest ...>
    
    <uses-sdk .../>
    
    <uses-permission android:name="android.permission.WRITE_SMS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.RECEIVE_SMS"/>

    <application
        ...>
        ...

</manifest>

Implementación:

public class SmsReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle intentExtras = intent.getExtras();
        
        if (intentExtras != null) {
            /* Get Messages */
            Object[] sms = (Object[]) intentExtras.get("pdus");
            
            for (int i = 0; i < sms.length; ++i) {
                /* Parse Each Message */
                SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) sms[i]);

                String phone = smsMessage.getOriginatingAddress();
                String message = smsMessage.getMessageBody().toString();
                
                Toast.makeText(context, phone + ": " + message, Toast.LENGTH_SHORT).show();
            }
        }
    }

}

Leyendo el historial de SMS

Permisos:

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

    <application
        ...>
        ...

</manifest> 

Implementacion:

Cursor cur = getContentResolver().query(Uri.parse("content://sms/"), null, null, null, null);

if (cur.moveToFirst()) { /* false = no sms */
    do {
       String msgInfo = "";

       for (int i = 0; i < cur.getColumnCount(); i++) {
           msgInfo += " " + cur.getColumnName(i) + ":" + cursor.getString(i);
       }

       Toast.makeText(this, msgInfo, Toast.LENGTH_SHORT).show();
    } while (cursor.moveToNext());
}

Para bandeja de entrada

Sustituye content://sms/ por content://sms/inbox

Para mensajes enviados

Sustituye content://sms/ por content://sms/sent

Para borradores

Sustituye content://sms/ por content://sms/draft

Proyecto completo

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="3dp"
    tools:context="${relativePackage}.${activityClass}" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btnAll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="All" />

        <Button
            android:id="@+id/btnInbox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dp"
            android:text="Inbox" />

        <Button
            android:id="@+id/btnSent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dp"
            android:text="Sent" />

        <Button
            android:id="@+id/btnDraft"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dp"
            android:text="Draft" />

    </LinearLayout>

    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginTop="3dp"
        android:scrollbars="vertical" >
    
        <HorizontalScrollView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scrollbars="horizontal" >
        
            <TableLayout
                android:id="@+id/tblMain"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent">
        
            </TableLayout>
        
        </HorizontalScrollView>
    
    </ScrollView>

</LinearLayout>
package com.example.androidreadsms;

import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity
    implements OnClickListener {

    Button btnAll;
    Button btnInbox;
    Button btnSent;
    Button btnDraft;
    TableLayout tblMain;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try {
            /*
             * Initializing Widgets
             */

            btnAll = (Button) findViewById(R.id.btnAll);
            btnAll.setOnClickListener(this);
            
            btnInbox = (Button) findViewById(R.id.btnInbox);
            btnInbox.setOnClickListener(this);
            
            btnSent = (Button) findViewById(R.id.btnSent);
            btnSent.setOnClickListener(this);
            
            btnDraft = (Button) findViewById(R.id.btnDraft);
            btnDraft.setOnClickListener(this);
            
            tblMain = (TableLayout) findViewById(R.id.tblMain);
            
        } catch (Exception ex) {
            Toast.makeText(this,
                    "Error in MainActivity.onCreate: " + ex.getMessage(),
                    Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onClick(View v) {
        Uri smsUri = Uri.parse("content://sms/");
        
        switch (v.getId()) {
        case R.id.btnInbox:
            smsUri = Uri.parse("content://sms/inbox");
            break;
        case R.id.btnSent:
            smsUri = Uri.parse("content://sms/sent");
            break;
        case R.id.btnDraft:
            smsUri = Uri.parse("content://sms/draft");
            break;
        }
        
        Cursor cursor = getContentResolver().query(smsUri, null, null, null, null);

        Cursor2TableLayout(cursor, tblMain);
    }
    
    public void Cursor2TableLayout(Cursor cur, TableLayout tblLayout) {
        
        /* Clearing Table If Contains Any Rows/Headers */
        tblLayout.removeAllViews();
        
        /* Moving To First */
        if (!cur.moveToFirst()) { /* false = cursor is empty */
            return;
        }

        /* Column Headers */
        
        TableRow headersRow = new TableRow(this);
        
        for (int j = 0; j < cur.getColumnCount(); j++) {
            TextView textView = new TextView(this);

            textView.setGravity(Gravity.CENTER_HORIZONTAL);
            
            textView.setText(cur.getColumnName(j));

            textView.setPadding(0, 0, 5, 0);
            
            textView.setAlpha(0.8f);
        
            headersRow.addView(textView);
        }

        headersRow.setPadding(10, 10, 10, 10);

        tblLayout.addView(headersRow);
        
        /* Rows */
    
        for (int i = 0; i < cur.getCount(); i++) {

            TableRow tableRow = new TableRow(this);

            for (int j = 0; j < cur.getColumnCount(); j++) {
                    TextView textView = new TextView(this);

                    textView.setGravity(Gravity.CENTER_HORIZONTAL);

                    textView.setText(cur.getString(j));

                    textView.setPadding(0, 0, 5, 0);
                
                    tableRow.addView(textView);
            }

            tableRow.setPadding(10, 10, 10, 10);

            tblLayout.addView(tableRow);
            cur.moveToNext();
        }

        cur.close();
    }
}

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP