He descubierto cómo enviar y recibir mensajes SMS. Para enviar mensajes SMS tuve que llamar a los métodos sendTextMessage()
y sendMultipartTextMessage()
de la SmsManager
clase. Para recibir mensajes SMS, tuve que registrar un receptor en el AndroidMainfest.xml
archivo. Luego tuve que anular el onReceive()
método de BroadcastReceiver
. He incluido ejemplos a continuación.
MainActivity.java
public class MainActivity extends Activity {
private static String SENT = "SMS_SENT";
private static String DELIVERED = "SMS_DELIVERED";
private static int MAX_SMS_MESSAGE_LENGTH = 160;
// ---sends an SMS message to another device---
public static void sendSMS(String phoneNumber, String message) {
PendingIntent piSent = PendingIntent.getBroadcast(mContext, 0, new Intent(SENT), 0);
PendingIntent piDelivered = PendingIntent.getBroadcast(mContext, 0,new Intent(DELIVERED), 0);
SmsManager smsManager = SmsManager.getDefault();
int length = message.length();
if(length > MAX_SMS_MESSAGE_LENGTH) {
ArrayList<String> messagelist = smsManager.divideMessage(message);
smsManager.sendMultipartTextMessage(phoneNumber, null, messagelist, null, null);
}
else
smsManager.sendTextMessage(phoneNumber, null, message, piSent, piDelivered);
}
}
//More methods of MainActivity ...
}
SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver {
private final String DEBUG_TAG = getClass().getSimpleName().toString();
private static final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private Context mContext;
private Intent mIntent;
// Retrieve SMS
public void onReceive(Context context, Intent intent) {
mContext = context;
mIntent = intent;
String action = intent.getAction();
if(action.equals(ACTION_SMS_RECEIVED)){
String address, str = "";
int contactId = -1;
SmsMessage[] msgs = getMessagesFromIntent(mIntent);
if (msgs != null) {
for (int i = 0; i < msgs.length; i++) {
address = msgs[i].getOriginatingAddress();
contactId = ContactsUtils.getContactId(mContext, address, "address");
str += msgs[i].getMessageBody().toString();
str += "\n";
}
}
if(contactId != -1){
showNotification(contactId, str);
}
// ---send a broadcast intent to update the SMS received in the
// activity---
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("SMS_RECEIVED_ACTION");
broadcastIntent.putExtra("sms", str);
context.sendBroadcast(broadcastIntent);
}
}
public static SmsMessage[] getMessagesFromIntent(Intent intent) {
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
byte[][] pduObjs = new byte[messages.length][];
for (int i = 0; i < messages.length; i++) {
pduObjs[i] = (byte[]) messages[i];
}
byte[][] pdus = new byte[pduObjs.length][];
int pduCount = pdus.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
for (int i = 0; i < pduCount; i++) {
pdus[i] = pduObjs[i];
msgs[i] = SmsMessage.createFromPdu(pdus[i]);
}
return msgs;
}
/**
* The notification is the icon and associated expanded entry in the status
* bar.
*/
protected void showNotification(int contactId, String message) {
//Display notification...
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myexample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.WRITE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:debuggable="true"
android:icon="@drawable/ic_launcher_icon"
android:label="@string/app_name" >
<activity
//Main activity...
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
//Activity 2 ...
</activity>
//More acitivies ...
// SMS Receiver
<receiver android:name="com.myexample.receivers.SMSReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
Sin embargo, me preguntaba si podría enviar y recibir mensajes MMS de manera similar. Después de investigar un poco, muchos ejemplos proporcionados en blogs simplemente pasan una Intent
aplicación de mensajería nativa. Estoy tratando de enviar un MMS sin salir de mi aplicación. No parece haber una forma estándar de enviar y recibir MMS. ¿Alguien ha conseguido que esto funcione?
Además, soy consciente de que el ContentProvider de SMS / MMS no forma parte del SDK oficial de Android, pero estaba pensando que alguien pudo haberlo implementado. Cualquier ayuda es muy apreciada.
Actualizar
He agregado una BroadcastReceiver
al AndroidManifest.xml
archivo para recibir mensajes MMS
<receiver android:name="com.sendit.receivers.MMSReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
En la clase MMSReceiver, el onReceive()
método solo puede tomar el número de teléfono desde el que se envió el mensaje. ¿Cómo se toman otras cosas importantes de un MMS, como la ruta del archivo al archivo adjunto de medios (imagen / audio / video) o el texto en el MMS?
MMSReceiver.java
public class MMSReceiver extends BroadcastReceiver {
private final String DEBUG_TAG = getClass().getSimpleName().toString();
private static final String ACTION_MMS_RECEIVED = "android.provider.Telephony.WAP_PUSH_RECEIVED";
private static final String MMS_DATA_TYPE = "application/vnd.wap.mms-message";
// Retrieve MMS
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String type = intent.getType();
if(action.equals(ACTION_MMS_RECEIVED) && type.equals(MMS_DATA_TYPE)){
Bundle bundle = intent.getExtras();
Log.d(DEBUG_TAG, "bundle " + bundle);
SmsMessage[] msgs = null;
String str = "";
int contactId = -1;
String address;
if (bundle != null) {
byte[] buffer = bundle.getByteArray("data");
Log.d(DEBUG_TAG, "buffer " + buffer);
String incomingNumber = new String(buffer);
int indx = incomingNumber.indexOf("/TYPE");
if(indx>0 && (indx-15)>0){
int newIndx = indx - 15;
incomingNumber = incomingNumber.substring(newIndx, indx);
indx = incomingNumber.indexOf("+");
if(indx>0){
incomingNumber = incomingNumber.substring(indx);
Log.d(DEBUG_TAG, "Mobile Number: " + incomingNumber);
}
}
int transactionId = bundle.getInt("transactionId");
Log.d(DEBUG_TAG, "transactionId " + transactionId);
int pduType = bundle.getInt("pduType");
Log.d(DEBUG_TAG, "pduType " + pduType);
byte[] buffer2 = bundle.getByteArray("header");
String header = new String(buffer2);
Log.d(DEBUG_TAG, "header " + header);
if(contactId != -1){
showNotification(contactId, str);
}
// ---send a broadcast intent to update the MMS received in the
// activity---
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("MMS_RECEIVED_ACTION");
broadcastIntent.putExtra("mms", str);
context.sendBroadcast(broadcastIntent);
}
}
}
/**
* The notification is the icon and associated expanded entry in the status
* bar.
*/
protected void showNotification(int contactId, String message) {
//Display notification...
}
}
De acuerdo con la documentación de android.provider.Telephony :
Acción de difusión: el dispositivo ha recibido un nuevo mensaje de texto basado en SMS. La intención tendrá los siguientes valores adicionales:
pdus
- UnaObject[]
de lasbyte[]
s que contienen las PDU que componen el mensaje.Los valores adicionales se pueden extraer utilizando
getMessagesFromIntent(android.content.Intent)
Si un BroadcastReceiver encuentra un error mientras procesa esta intención, debe establecer el código de resultado de manera adecuada.@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
Acción de difusión: el dispositivo ha recibido un nuevo mensaje SMS basado en datos. La intención tendrá los siguientes valores adicionales:
pdus
- UnaObject[]
de lasbyte[]
s que contienen las PDU que componen el mensaje.Los valores adicionales se pueden extraer usando getMessagesFromIntent (android.content.Intent). Si un BroadcastReceiver encuentra un error al procesar esta intención, debe establecer el código de resultado de manera adecuada.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
Acción de difusión: el dispositivo ha recibido un nuevo mensaje WAP PUSH. La intención tendrá los siguientes valores adicionales:
transactionId (Integer)
- La identificación de la transacción WAP
pduType (Integer)
- El tipo de PDU WAP`
header (byte[])
- El encabezado del mensaje
data (byte[])
- La carga útil de datos del mensaje.
contentTypeParameters (HashMap<String,String>)
- Cualquier parámetro asociado con el tipo de contenido (decodificado desde el encabezado WSP Content-Type)Si un BroadcastReceiver encuentra un error al procesar esta intención, debe establecer el código de resultado de manera adecuada. El valor adicional contentTypeParameters es un mapa de parámetros de contenido con sus nombres. Si se encuentran parámetros conocidos no asignados, la clave del mapa será 'sin asignar / 0x ...', donde '...' es el valor hexadecimal del parámetro sin asignar. Si un parámetro no tiene valor, el valor en el mapa será nulo.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
Actualización n. ° 2
He descubierto cómo pasar extras en un PendingIntent
para ser recibido por BroadcastReceiver
:
Android PendingIntent extras, no recibidos por BroadcastReceiver
Sin embargo, el extra se pasa al SendBroadcastReceiver, no al SMSReceiver . ¿Cómo puedo pasar un extra al SMSReceiver ?
Actualización n. ° 3
Recibiendo MMS
Entonces, después de investigar más, vi algunas sugerencias para registrar a ContentObserver
. De esa manera, puede detectar cuándo hay cambios en el content://mms-sms/conversations
proveedor de contenido, lo que le permite detectar MMS entrantes. Aquí está el ejemplo más cercano para que esto funcione que he encontrado: Recibir MMS
Sin embargo, hay una variable mainActivity
de tipo ServiceController
. ¿Dónde se ServiceController
implementa la clase? ¿Hay otras implementaciones de un registrado ContentObserver
?
Enviando MMS
En cuanto al envío de MMS, me he encontrado con este ejemplo: Enviar MMS
El problema es que intenté ejecutar este código en mi Nexus 4, que está en Android v4.2.2, y recibo este error:
java.lang.SecurityException: No permission to write APN settings: Neither user 10099 nor current process has android.permission.WRITE_APN_SETTINGS.
El error se genera después de consultar Carriers
ContentProvider en el getMMSApns()
método de la APNHelper
clase.
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);
Aparentemente no puedes leer APNs en Android 4.2
¿Cuál es la alternativa para todas aquellas aplicaciones que usan datos móviles para realizar operaciones (como enviar MMS) y no conocen la configuración de APN predeterminada presente en el dispositivo?
Actualización n. ° 4
Enviando MMS
He intentado seguir este ejemplo: Enviar MMS
Como @Sam sugirió en su respuesta:
You have to add jsoup to the build path, the jar to the build path and import com.droidprism.*; To do that in android, add the jars to the libs directory first, then configure the project build path to use the jars already in the libs directory, then on the build path config click order and export and check the boxes of the jars and move jsoup and droidprism jar to the top of the build order.
Entonces ahora ya no recibo los errores de SecurityException. Estoy probando ahora en un Nexus 5 en Android KitKat. Después de ejecutar el código de muestra, me da un código de respuesta 200 después de la llamada a
MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);
Sin embargo, verifiqué con la persona a la que intenté enviarle el MMS. Y dijeron que nunca recibieron el MMS.