samsung - Cómo leer datos MMS en Android?
porque no puedo mandar fotos por mensaje (5)
Es un poco difícil encontrar documentación sobre esto, así que recogeré aquí toda la información que he encontrado. Si tiene prisa o simplemente no le gusta leer, vaya a la sección Cómo obtener datos de un SMS .
contenido: // mms-sms / conversaciones
Este es el URI del proveedor de SMS y SMS ... que nos permite consultar las bases de datos de MMS y SMS al mismo tiempo, y mezclarlas en un solo hilo (que se llaman conversaciones ).
¿Por qué es uri importante? Bueno, esa es la forma estándar de recibir mensajes MMS y SMS; por ejemplo, cuando recibe un SMS y hace clic en la barra de notificaciones, enviará un intento de transmisión como este: content://mms-sms/conversations/XXX
, donde XXX
es la identificación de la conversación.
Obtenga una lista de todas las conversaciones
Lo único que tienes que hacer es consultar el content://mms-sms/conversations
Uri:
ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"*"};
Uri uri = Uri.parse("content://mms-sms/conversations/");
Cursor query = contentResolver.query(uri, projection, null, null, null);
Nota: generalmente, cuando llama a la query
y desea devolver todas las columnas, puede pasar null
como parámetro de projection
. Sin embargo, no puede hacer eso con este proveedor, por eso estoy usando *
.
Ahora puede recorrer el Cursor
como de costumbre. Estas son las columnas más importantes que le gustaría usar:
-
_id
es la ID del mensaje. Capitán obvio para el rescate? Realmente no. Esta ID se puede usar para recuperar información detallada utilizandocontent://sms
ocontent://mms
. -
date
no se necesita explicación. -
thread_id
es el ID de la conversación -
body
El contenido del último SMS en esta conversación. Si se trata de un MMS, incluso si tiene una parte de texto, seránull
.
Nota: si consulta content://mms-sms/conversations
, obtendrá una lista de diferentes conversaciones cuyo _id
es el último SMS o MMS en cada conversación. Si consulta content://mms-sms/conversations/xxx
, devolverá cada SMS y / o MMS en la conversación cuyo ID sea xxx
.
Cómo diferenciar entre SMS y MMS
Generalmente, querrá saber qué tipo de mensaje está manejando. La documentación dice:
Se puede solicitar una columna virtual,
MmsSms.TYPE_DISCRIMINATOR_COLUMN
, en la proyección para una consulta. Su valor es "mms" o "sms", dependiendo de si el mensaje representado por la fila es un mensaje MMS o un mensaje SMS, respectivamente.
Creo que se está refiriendo a esta variable ... sin embargo, no he podido hacerlo funcionar. Si tiene, por favor dígame cómo o edite esta publicación.
Hasta ahora esto es lo que hice y parece funcionar, pero debe haber mejores formas:
ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"_id", "ct_t"};
Uri uri = Uri.parse("content://mms-sms/conversations/");
Cursor query = contentResolver.query(uri, projection, null, null, null);
if (query.moveToFirst()) {
do {
String string = query.getString(query.getColumnIndex("ct_t"));
if ("application/vnd.wap.multipart.related".equals(string)) {
// it''s MMS
} else {
// it''s SMS
}
} while (query.moveToNext());
}
Cómo obtener datos de un SMS
Entonces tienes la ID del SMS, entonces lo único que tienes que hacer es:
String selection = "_id = "+id;
Uri uri = Uri.parse("content://sms");
Cursor cursor = contentResolver.query(uri, null, selection, null, null);
String phone = cursor.getString(cursor.getColumnIndex("address"));
int type = cursor.getInt(cursor.getColumnIndex("type"));// 2 = sent, etc.
String date = cursor.getString(cursor.getColumnIndex("date"));
String body = cursor.getString(cursor.getColumnIndex("body"));
¿Cómo obtener datos de una información MMS?
Los MMS son un poco diferentes. Se pueden construir con diferentes partes (texto, audio, imágenes, etc.); así que aquí verá cómo recuperar cada tipo de datos por separado.
Así que supongamos que tenemos la identificación MMS en la variable mmsId
. Podemos obtener información detallada sobre este MMS utilizando el content://mms/
provider:
Uri uri = Uri.parse("content://mms/");
String selection = "_id = " + mmsId;
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
Sin embargo, se read
la única columna interesante que es 1
si el mensaje ya se ha leído.
Cómo obtener contenido de texto de MMS
Aquí tenemos que usar el content://mms/part
... por ejemplo:
String selectionPart = "mid=" + mmsId;
Uri uri = Uri.parse("content://mms/part");
Cursor cursor = getContentResolver().query(uri, null,
selectionPart, null, null);
if (cursor.moveToFirst()) {
do {
String partId = cursor.getString(cursor.getColumnIndex("_id"));
String type = cursor.getString(cursor.getColumnIndex("ct"));
if ("text/plain".equals(type)) {
String data = cursor.getString(cursor.getColumnIndex("_data"));
String body;
if (data != null) {
// implementation of this method below
body = getMmsText(partId);
} else {
body = cursor.getString(cursor.getColumnIndex("text"));
}
}
} while (cursor.moveToNext());
}
Podría contener diferentes partes de texto ... pero generalmente sería solo una. Entonces, si desea eliminar el bucle, funcionará la mayoría de las veces. Así es como se getMmsText
método getMmsText
:
private String getMmsText(String id) {
Uri partURI = Uri.parse("content://mms/part/" + id);
InputStream is = null;
StringBuilder sb = new StringBuilder();
try {
is = getContentResolver().openInputStream(partURI);
if (is != null) {
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader reader = new BufferedReader(isr);
String temp = reader.readLine();
while (temp != null) {
sb.append(temp);
temp = reader.readLine();
}
}
} catch (IOException e) {}
finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {}
}
}
return sb.toString();
}
Cómo obtener una imagen de MMS
Es lo mismo que obtener la parte del texto ... la única diferencia es que buscarás un tipo de mime diferente:
String selectionPart = "mid=" + mmsId;
Uri uri = Uri.parse("content://mms/part");
Cursor cPart = getContentResolver().query(uri, null,
selectionPart, null, null);
if (cPart.moveToFirst()) {
do {
String partId = cPart.getString(cPart.getColumnIndex("_id"));
String type = cPart.getString(cPart.getColumnIndex("ct"));
if ("image/jpeg".equals(type) || "image/bmp".equals(type) ||
"image/gif".equals(type) || "image/jpg".equals(type) ||
"image/png".equals(type)) {
Bitmap bitmap = getMmsImage(partId);
}
} while (cPart.moveToNext());
}
Así es como se getMmsImage
método getMmsImage
:
private Bitmap getMmsImage(String _id) {
Uri partURI = Uri.parse("content://mms/part/" + _id);
InputStream is = null;
Bitmap bitmap = null;
try {
is = getContentResolver().openInputStream(partURI);
bitmap = BitmapFactory.decodeStream(is);
} catch (IOException e) {}
finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {}
}
}
return bitmap;
}
Cómo obtener la dirección del remitente
Deberá usar el proveedor de content://mms/xxx/addr
, donde xxx
es la identificación del MMS:
private String getAddressNumber(int id) {
String selectionAdd = new String("msg_id=" + id);
String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
Uri uriAddress = Uri.parse(uriStr);
Cursor cAdd = getContentResolver().query(uriAddress, null,
selectionAdd, null, null);
String name = null;
if (cAdd.moveToFirst()) {
do {
String number = cAdd.getString(cAdd.getColumnIndex("address"));
if (number != null) {
try {
Long.parseLong(number.replace("-", ""));
name = number;
} catch (NumberFormatException nfe) {
if (name == null) {
name = number;
}
}
}
} while (cAdd.moveToNext());
}
if (cAdd != null) {
cAdd.close();
}
return name;
}
Pensamientos finales
- No puedo entender por qué Google, con esos miles de millones de dólares, no le paga a un alumno u otra persona para documentar esta API. Debes verificar el código fuente para saber cómo funciona y, lo que es peor, no hacen públicas esas constantes utilizadas en las columnas de la base de datos, así que tenemos que escribirlas manualmente.
- Para otro tipo de datos dentro de un MMS puede aplicar la misma idea que se aprendió anteriormente ... solo se trata de conocer el tipo de mimo.
Quiero leer datos de MMS. He visto la tabla de partes en mmssms.db
donde se almacenan las entradas de mms; Estoy usando un cursor y quiero saber el URI
apropiado; Estoy usando "content: // mms-sms / conversaciones" y los nombres de columna de "Dirección" (Enviado a), "Texto" o "Asunto" y "Datos" nombre de la columna de la imagen.
He visto el esquema de mmssms.db
y Su columna de la tabla de partes.
He estado luchando con esto; sin embargo, finalmente lo hice funcionar y pensé que este hilo podría beneficiarse de mi experiencia.
Pude consultar sobre el content://mms-sms/conversations/ (Telephony.Threads.CONTENT_URI)
y obtuve las direcciones y partes como se describe en la secuencia, pero encontré que este URI no recuperaría los hilos que solo tenían mensajes MMS en ellos - por ejemplo, hilos con más de dos corresponsales.
Después de investigar en la fuente de la aplicación AOSP MMS, descubrí que estaba usando una variante en Telephony.Threads.CONTENT_URI
para generar su lista de conversación: agregaba el parámetro "simple" con el valor "verdadero". cuando agregué este parámetro, encontré que el proveedor consultaría una tabla completamente diferente, que efectivamente tenía todos los hilos de SMS y MMS.
Esta tabla tiene un esquema completamente diferente del habitual de Telephony.Threads.CONTENT_URI (???); esta es la proyección que usa la aplicación AOSP -
public static final String[] ALL_THREADS_PROJECTION = {
Threads._ID, Threads.DATE, Threads.MESSAGE_COUNT, Threads.RECIPIENT_IDS,
Threads.SNIPPET, Threads.SNIPPET_CHARSET, Threads.READ, Threads.ERROR,
Threads.HAS_ATTACHMENT
};
El _ID aquí es la ID del hilo, por lo tanto, una ID en Telephony.Sms.CONTENT_URI o Telephony.Mms.CONTENT_URI.
¡Después de descubrir este detalle extraño, las cosas comenzaron a funcionar mucho mejor! Sin embargo, tenga en cuenta que la columna DATE en la variante "simple = verdadera" no es confiable, en su lugar tuve que usar la fecha del mensaje más reciente de Sms o Mms.
Otra cosa que probablemente debería mencionar es que para obtener una lista adecuada de mensajes para un hilo en particular, tuve que consultar en los proveedores de Mms y Sms, luego combinar los resultados en una lista, luego ordenarlos por fecha.
Verifiqué el comportamiento en Android 5.xy 7.x.
Espero que esto ayude un poco más.
La respuesta dada anteriormente para obtener getMMSAddress () no debe contener el bucle while (cursor.moveToNext ()) ;. Solo debería extraer la dirección del primer elemento en el cursor. Por alguna razón desconocida para mí, este cursor tiene más de un registro. El primero contiene la dirección del remitente. Los otros elementos del cursor más allá del primero, contienen la dirección del receptor. Por lo tanto, el código como es devolver la dirección de los receptores y no la dirección del remitente.
Esto ha sido muy útil para abrir los contenidos de un MMS.
La respuesta de Christian es excelente. Sin embargo, el método para obtener la dirección del remitente no funcionó para mí. La instrucción Long.parseLong no hace nada, excepto posiblemente lanzar una excepción y una nueva cadena (...)?
En mi dispositivo, el recuento del cursor es 2 o más. El primero típicamente tiene un "tipo" de 137 y los otros tienen un "tipo" de 151. No puedo encontrar dónde está documentado esto, pero se puede deducir que 137 es "desde" y 151 es "hasta". Por lo tanto, si ejecuto el método como está, no obtengo una excepción, y devuelve la última fila, que es un destinatario y solo una de varias en muchos casos.
También AFAICT la selección no es necesaria ya que todas las filas tienen el mismo msg_id. Sin embargo, no duele.
Esto es lo que funciona para mí para obtener la dirección del remitente:
public static String getMMSAddress(Context context, String id) {
String addrSelection = "type=137 AND msg_id=" + id;
String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
Uri uriAddress = Uri.parse(uriStr);
String[] columns = { "address" };
Cursor cursor = context.getContentResolver().query(uriAddress, columns,
addrSelection, null, null);
String address = "";
String val;
if (cursor.moveToFirst()) {
do {
val = cursor.getString(cursor.getColumnIndex("address"));
if (val != null) {
address = val;
// Use the first one found if more than one
break;
}
} while (cursor.moveToNext());
}
if (cursor != null) {
cursor.close();
}
// return address.replaceAll("[^0-9]", "");
return address;
}
No me importaba si todo era numérico, pero incluí una forma de eliminar todo, excepto los numerales, como un comentario si así lo deseaba. También se puede modificar fácilmente para devolver todos los destinatarios.
Supongo que funcionó para él. Parece que daría la respuesta correcta si la excepción se produjo en la primera fila.
Tuve que hacer algunas modificaciones para que esto funcione para mí.
Cuando recupero el cursor.getString (cursor.getColumnIndex ("type")) del contenido mms-sms / conversaciones, ("content: // mms-sms / conversaciones /") pruebo el valor del campo "type" para nulo. Si la variable es nula, es decir,
String otype = c.getString(c.getColumnIndex("type")); if(otype != null) { //this is an sms - handle it...
el mensaje es un SMS, de lo contrario es un MMS. Para MMS, debe probar ambos tipos de mime de la siguiente manera:
if (("application/vnd.wap.multipart.related".equalsIgnoreCase(msg_type) ||"application/vnd.wap.multipart.mixed".equalsIgnoreCase(msg_type)) && !id.equalsIgnoreCase(lastMMSID)) { //this is a MMS - handle it...
- Cuando utiliza ContentObserver para supervisar el contenido del mensaje en busca de cambios, se activan varias notificaciones para el mismo mensaje. Utilizo una variable estática, en mi caso lastMMSID, para hacer un seguimiento del mensaje.
- Este código funciona bien para recuperar el contenido de los mensajes entrantes y salientes. Es importante recorrer todos los registros devueltos por el uri "content: // mms / part /" para acceder al contenido - texto y / o adjuntos - del MMS.
La única forma en que pude encontrar que funciona bastante bien para diferenciar entre MMS entrantes y salientes, es probar el estado nulo del campo "m_id" del contenido de mms-sms / conversaciones.
String m_id = c.getString(c.getColumnIndex("m_id")); String mDirection = m_id == null? "OUT": "IN";
Una reflexión final sobre cómo obtener el campo de dirección. Por alguna razón, el contenido de la dirección no desea ser consultado con un parámetro {"*"}, pero esto funciona:
final String[] projection = new String[] {"address", "contact_id", "charset", "type"};
Si se trata de un mensaje saliente, el "tipo" a buscar será 151. Para un mensaje entrante, el "tipo" será 137. Un fragmento de código completamente funcional tendrá el siguiente aspecto: -
private String getANumber(int id) {
String add = "";
final String[] projection = new String[] {"address","contact_id","charset","type"};
final String selection = "type=137 or type=151"; // PduHeaders
Uri.Builder builder = Uri.parse("content://mms").buildUpon();
builder.appendPath(String.valueOf(id)).appendPath("addr");
Cursor cursor = context.getContentResolver().query(
builder.build(),
projection,
selection,
null, null);
if (cursor.moveToFirst()) {
do {
String add = cursor.getString(cursor.getColumnIndex("address"));
String type: cursor.getString(cursor.getColumnIndex("type"));
} while(cursor.moveToNext());
}
// Outbound messages address type=137 and the value will be ''insert-address-token''
// Outbound messages address type=151 and the value will be the address
// Additional checking can be done here to return the correct address.
return add;
}
A todos los valientes guerreros que me precedieron en este post, ¡te agradezco desde el fondo de mi corazón!