Cómo leer datos MMS en Android?

Quiero leer los datos MMS He visto la tabla de partes en el mmssms.db donde se almacenan las entradas mms; Estoy usando un cursor y quiero saber el URI apropiado; Estoy usando "content: // mms-sms / conversations" y los nombres de columnas de "Address" (Sent to), "Text" o "Subject" y "Data" nombre de columna de la imagen.

He visto el esquema de mmssms.db y su columna de la tabla de la parte.

Es un poco difícil encontrar documentación sobre esto, así que recopilaré 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 una sección de SMS .

Contenido: // mms-sms / conversaciones

Este es el URI del proveedor MMS y SMS … que nos permite consultar las bases de datos MMS y SMS al mismo tiempo, y mezclarlas en un solo hilo (que se llaman conversaciones ).

¿Por qué es importante? Bueno, esa es la forma estándar de obtener mensajes MMS y SMS; Por ejemplo, cuando reciba un SMS y haga clic en la barra de notificación, enviará una intención de difusión como esta: content://mms-sms/conversations/XXX , donde XXX es el id de la conversación.

Obtener 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: por lo general, al llamar 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 lo que estoy usando * .

Ahora puedes recorrer el Cursor como de costumbre. Estas son las columnas más importantes que desea usar:

  • _id es el ID del mensaje. Capitán obvio para el rescate? Realmente no. Este ID se puede utilizar para recuperar información detallada utilizando el content://sms o el content://mms .
  • date no se necesita ninguna explicación.
  • thread_id es el ID de la conversación
  • body El contenido del último SMS de esta conversación. Si se trata de un MMS, incluso si tiene una parte de texto, esto será null .

Nota: si consulta el content://mms-sms/conversations devolverá 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 es xxx .

Cómo diferenciar entre SMS y MMS

Por lo general, usted querrá saber qué tipo de mensaje que está manejando. La documentación dice:

Una columna virtual, MmsSms.TYPE_DISCRIMINATOR_COLUMN , se puede solicitar en la proyección de 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 sido capaz de hacer que funcione. Si usted tiene por favor decirme cómo o editar este post.

Hasta ahora esto es lo que he hecho y parece que funciona, pero debe haber mejores maneras:

 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

Así que tienes el 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 datos MMS?

Los MMS son un poco diferentes. Pueden ser construidos con diferentes partes (texto, audio, imágenes, etc.); Así que aquí veremos cómo recuperar cada tipo de datos por separado.

Así que supongamos que tenemos el ID MMS en la variable mmsId . Podemos obtener información detallada acerca de 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 ha sido leído.

Cómo obtener contenido de texto desde 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 del texto … pero normalmente sería sólo uno. Así que si desea eliminar el bucle que 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 la imagen de MMS

Es lo mismo que conseguir la parte de texto … la única diferencia es que usted estará buscando un tipo 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

Necesitará usar el proveedor de content://mms/xxx/addr , donde xxx es el id 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 paga a un estudiante oa otra persona para documentar esta API. Tienes que comprobar el código fuente para saber cómo funciona y, lo que es peor, no hacen públicas las constantes utilizadas en las columnas de la base de datos, por lo que tenemos que escribirlas manualmente.
  • Para otro tipo de datos dentro de un MMS se puede aplicar la misma idea aprendida anteriormente … es sólo una cuestión de saber el tipo mime.

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 nueva String (…)?.

En el dispositivo, el recuento del cursor es 2 o más. El primero normalmente tiene un "tipo" de 137 y los otros tienen un "tipo" de 151. No puedo encontrar dónde está documentado, pero uno puede deducir que 137 es "de" y 151 es "a". Por lo tanto, si ejecuto el método como es, no recibo una excepción, y devuelve la última fila, que es un destinatario y sólo uno de varios 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 manera de eliminar todo, excepto los números como un comentario si eso es deseado. Se puede modificar fácilmente para devolver todos los destinatarios, también.

Supongo que funcionó para él. Parece que daría la respuesta correcta si la excepción ocurrió en la primera fila.

Tuve que hacer algunas modificaciones para conseguir que esto funcione para mí.

  1. Cuando recupero el cursor.getString (cursor.getColumnIndex ("type")) desde el contenido de mms-sms / conversations, ("content: // mms-sms / conversations /") pruebo el valor del campo "type" Para null. 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 tiene que probar para ambos tipos de mime como sigue: –

     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... 
  2. Cuando utiliza un ContentObserver para supervisar el contenido del mensaje para los cambios, activa varias notificaciones para el mismo mensaje. Utilizo una variable estática – en mi caso lastMMSID – para realizar un seguimiento del mensaje.
  3. Este código funciona bien para recuperar el contenido de los mensajes entrantes y salientes. Es importante iterar a través de todos los registros que son devueltos por el "contenido: // mms / part /" uri para llegar al contenido – texto y / o archivos adjuntos – del MMS.
  4. La única manera que podría encontrar que funciona bastante bien para diferenciar entre los MMS entrantes y salientes, es probar el estado nulo del campo "m_id" del contenido mms-sms / conversations.

     String m_id = c.getString(c.getColumnIndex("m_id")); String mDirection = m_id == null? "OUT": "IN"; 

Un pensamiento final sobre cómo obtener el campo de dirección. Por alguna razón, el contenido de la dirección no le gusta que se le consulte 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. Una pieza de código completamente funcional se verá así:

 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 han precedido en este post, ¡te doy gracias desde el fondo de mi corazón!

La respuesta dada anteriormente para obtener getMMSAddress () no debe contener el bucle while (cursor.moveToNext ()) ;. Sólo debe extraer la dirección del primer elemento del cursor. Por alguna razón que me es desconocida, 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. Así, el código como se devuelve la dirección de los receptores y no la dirección del remitente.

Esto ha sido muy útil para abrir el contenido de un MMS.

Sólo he estado luchando con esto; Sin embargo, finalmente conseguí que funcione y pensé que este hilo podría beneficiarse de mi experiencia.

Podría consultar en el content://mms-sms/conversations/ (Telephony.Threads.CONTENT_URI) y obtener direcciones y partes como útilmente descrito en el hilo, pero he encontrado que este URI no recuperar hilos que sólo tenía mensajes MMS en ellos – por ejemplo, roscas con más de dos corresponsales.

Después de hacer un poco de excavación en la fuente de la aplicación AOSP MMS, encontré que estaba usando una variante en Telephony.Threads.CONTENT_URI para generar su lista de conversación – estaba agregando el parámetro "simple" con el valor "true". Cuando agregué este parámetro, descubrí que el proveedor consultaría una tabla completamente diferente, que de hecho tenía todos los subprocesos SMS y MMS.

Esta tabla tiene un esquema completamente diferente de la regular Telephony.Threads.CONTENT_URI uno (???); Esta es la proyección que utiliza 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 el ID del hilo – por lo que un ID en Telephony.Sms.CONTENT_URI o Telephony.Mms.CONTENT_URI.

Después de descubrir este extraño detalle, las cosas empezaron a funcionar mucho mejor! Tenga en cuenta, sin embargo, que la columna DATE en la variante "simple = true" no es fiable, tuve que usar la fecha del mensaje Sms o Mms más reciente.

Otra cosa que probablemente debería mencionar es que con el fin de obtener una lista adecuada de los mensajes de un hilo en particular, tuve que consultar tanto en los proveedores MMS y Sms, a continuación, combinar los resultados en una lista, a continuación, clasificar por fecha.

Comprobé el comportamiento en Android 5.xy 7.x.

Espero que esto ayude un poco más.

  • Caracteres especiales en sms de Android
  • Envío de MMS por programación en Android
  • Activa la aplicación MMS de Android para enviar mensajes pendientes
  • Enviar MMS desde Mi aplicación en android
  • Guardar / Crear MMS en la bandeja de entrada de Android
  • Android que envía la imagen vía mms programatically (operación agotada)
  • Cómo obtener todos los mensajes de ThreadID en android
  • Cómo diferenciar MMS y SMS en android?
  • Cómo enviar un MMS mediante programación?
  • Guardar / Crear MMS en la bandeja de entrada de Android
  • SDK de Android MMS
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.