Recibe mensajes MMS en Android KitKat

Por lo que este video Android 4.4 SMS API de #DevBytes explica los cambios recientes en las API de SMS en KitKat. También proporcionan un vínculo con un proyecto de ejemplo. Http://goo.gl/uQ3Nih

Sugieren que usted maneja la recepción de un MMS en un servicio. Que todo parece bien, excepto que se olvidan de mencionar la pieza más indocumentada. Cómo manejar un MMS entrante.

Aquí está la muestra del proyecto https://gist.github.com/lawloretienne/8970938

He tratado de "manejar el MMS"

Https://gist.github.com/lawloretienne/8971050

Puedo obtener los extras de la intención, pero la única cosa significativa que puedo extraer es el número desde el que se envió el MMS.

¿Puede alguien señalarme en la dirección correcta acerca de cómo hacer esto?

Me di cuenta de que un WAP_PUSH_MESSAGE contiene algunas cosas, un FROM, SUBJECT y CONTENT_LOCATION.

La ubicación del contenido parece ser la url donde está contenido el contenido del MMS. ¿Cómo puedo acceder a esto?

Aquí hay un ejemplo de esa URL

https://atl1mmsget.msg.eng.t-mobile.com/mms/wapenc?location=XXXXXXXXXXX_14zbwk&rid=027

Donde la X es un dígito en el número de teléfono del dispositivo en el que estoy probando.

Parece que el MMSC (Multimedia Messaging Service Center) para T-Mobile en los Estados Unidos es http://mms.msg.eng.t-mobile.com/mms/wapenc

De acuerdo con esta lista: http://www.activexperts.com/xmstoolkit/mmsclist/

Hay cero documentación así que aquí hay algo de información para ayudar.

1) com.google.android.mms.pdu desde el origen. Usted necesita el Pdu utils.

2) Recibe el impulso de notificación de la matriz de bytes extra de la transmisión de mms entrante (intention.getByteArrayExtra ("datos")).

3) Analizar el empuje de notificación en un GenericPdu (nuevo PduParser (rawPdu) .parse ()).

4) Necesitará TransactionSettings para comunicarse con el servidor wap del transportista. Recibo los ajustes de transacción después de # 5 a continuación. Yo suelo:

 TransactionSettings transactionSettings = new TransactionSettings(mContext, mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS).getExtraInfo()); 

5) Forzar el comm de la red sobre wifi. Yo uso lo siguiente.

 private boolean beginMmsConnectivity() { try { int result = mConnMgr.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_MMS); NetworkInfo info = mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS); boolean isAvailable = info != null && info.isConnected() && result == Phone.APN_ALREADY_ACTIVE && !Phone.REASON_VOICE_CALL_ENDED.equals(info.getReason()); return isAvailable; } catch(Exception e) { return false; } } 

6) A continuación, debe garantizar una ruta hacia el host.

 private static void ensureRouteToHost(ConnectivityManager cm, String url, TransactionSettings settings) throws IOException { int inetAddr; if (settings.isProxySet()) { String proxyAddr = settings.getProxyAddress(); inetAddr = lookupHost(proxyAddr); if (inetAddr == -1) { throw new IOException("Cannot establish route for " + url + ": Unknown host"); } else { if (!cm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_MMS, inetAddr)) throw new IOException("Cannot establish route to proxy " + inetAddr); } } else { Uri uri = Uri.parse(url); inetAddr = lookupHost(uri.getHost()); if (inetAddr == -1) { throw new IOException("Cannot establish route for " + url + ": Unknown host"); } else { if (!cm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_MMS, inetAddr)) throw new IOException("Cannot establish route to " + inetAddr + " for " + url); } } } 

Aquí está el método lookupHost:

 private static int lookupHost(String hostname) { InetAddress inetAddress; try { inetAddress = InetAddress.getByName(hostname); } catch (UnknownHostException e) { return -1; } byte[] addrBytes; int addr; addrBytes = inetAddress.getAddress(); addr = ((addrBytes[3] & 0xff) << 24) | ((addrBytes[2] & 0xff) << 16) | ((addrBytes[1] & 0xff) << 8) | (addrBytes[0] & 0xff); return addr; } 

También me gusta usar un método basado en la reflexión para mejorar la funcionalidad de asegurarRouteToHost:

 private static void ensureRouteToHostFancy(ConnectivityManager cm, String url, TransactionSettings settings) throws IOException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Method m = cm.getClass().getMethod("requestRouteToHostAddress", new Class[] { int.class, InetAddress.class }); InetAddress inetAddr; if (settings.isProxySet()) { String proxyAddr = settings.getProxyAddress(); try { inetAddr = InetAddress.getByName(proxyAddr); } catch (UnknownHostException e) { throw new IOException("Cannot establish route for " + url + ": Unknown proxy " + proxyAddr); } if (!(Boolean) m.invoke(cm, new Object[] { ConnectivityManager.TYPE_MOBILE_MMS, inetAddr })) throw new IOException("Cannot establish route to proxy " + inetAddr); } else { Uri uri = Uri.parse(url); try { inetAddr = InetAddress.getByName(uri.getHost()); } catch (UnknownHostException e) { throw new IOException("Cannot establish route for " + url + ": Unknown host"); } if (!(Boolean) m.invoke(cm, new Object[] { ConnectivityManager.TYPE_MOBILE_MMS, inetAddr })) throw new IOException("Cannot establish route to " + inetAddr + " for " + url); } } 

7) Después de asegurar una ruta al anfitrión usted puede entonces necesitar HttpUtls del origen. He modificado considerablemente mi implementación usando OkHttp para mejorar las comunicaciones.

 byte[] rawPdu = HttpUtils.httpConnection(mContext, mContentLocation, null, HttpUtils.HTTP_GET_METHOD, mTransactionSettings.isProxySet(), mTransactionSettings.getProxyAddress(), mTransactionSettings.getProxyPort()); 

8) De la matriz de bytes resultante utilice el PduParser para separar el GenericPdu. Entonces usted puede extraer el cuerpo y echar a un MultimediaMessagePdu.

9) A continuación, puede iterar las partes de la PDU.

Hay innumerables cosas a considerar con MMS. Una cosa que viene a la mente es cómo molesta presentación de diapositivas son, por lo que lo que hago es detectar si hay más de 1 partes en la PDU, a continuación, copiar los encabezados y crear MultimediaMessagePdu separado de los cuales los guardo al proveedor de contenido MMS del teléfono por separado . No olvide copiar los encabezados especialmente si está apoyando mensajes de grupo. La mensajería de grupo es otra historia porque el número de teléfono entrante en la PDU no cuenta toda la historia (MultimediaMessagePdu.mmpdu ()). Hay más contactos en el encabezado que extrae utilizando el código siguiente.

 private HashSet<String> getRecipients(GenericPdu pdu) { PduHeaders header = pdu.getPduHeaders(); HashMap<Integer, EncodedStringValue[]> addressMap = new HashMap<Integer, EncodedStringValue[]>(ADDRESS_FIELDS.length); for (int addrType : ADDRESS_FIELDS) { EncodedStringValue[] array = null; if (addrType == PduHeaders.FROM) { EncodedStringValue v = header.getEncodedStringValue(addrType); if (v != null) { array = new EncodedStringValue[1]; array[0] = v; } } else { array = header.getEncodedStringValues(addrType); } addressMap.put(addrType, array); } HashSet<String> recipients = new HashSet<String>(); loadRecipients(PduHeaders.FROM, recipients, addressMap, false); loadRecipients(PduHeaders.TO, recipients, addressMap, true); return recipients; } 

Este es el método de los destinatarios de carga:

 private void loadRecipients(int addressType, HashSet<String> recipients, HashMap<Integer, EncodedStringValue[]> addressMap, boolean excludeMyNumber) { EncodedStringValue[] array = addressMap.get(addressType); if (array == null) { return; } // If the TO recipients is only a single address, then we can skip loadRecipients when // we're excluding our own number because we know that address is our own. if (excludeMyNumber && array.length == 1) { return; } String myNumber = excludeMyNumber ? mTelephonyManager.getLine1Number() : null; for (EncodedStringValue v : array) { if (v != null) { String number = v.getString(); if ((myNumber == null || !PhoneNumberUtils.compare(number, myNumber)) && !recipients.contains(number)) { // Only add numbers which aren't my own number. recipients.add(number); } } } } 

A continuación se muestra cómo iterar las partes de MultimediaMessagePdu.

 private void processPduAttachments() throws Exception { if (mGenericPdu instanceof MultimediaMessagePdu) { PduBody body = ((MultimediaMessagePdu) mGenericPdu).getBody(); if (body != null) { int partsNum = body.getPartsNum(); for (int i = 0; i < partsNum; i++) { try { PduPart part = body.getPart(i); if (part == null || part.getData() == null || part.getContentType() == null || part.getName() == null) continue; String partType = new String(part.getContentType()); String partName = new String(part.getName()); Log.d("Part Name: " + partName); Log.d("Part Type: " + partType); if (ContentType.isTextType(partType)) { } else if (ContentType.isImageType(partType)) { } else if (ContentType.isVideoType(partType)) { } else if (ContentType.isAudioType(partType)) { } } catch (Exception e) { e.printStackTrace(); // Bad part shouldn't ruin the party for the other parts } } } } else { Log.d("Not a MultimediaMessagePdu PDU"); } } 

Hay muchas más consideraciones como el soporte de GIF animado, que es totalmente posible 🙂 Algunas compañías de soporte reconocen los informes y los informes de entrega también, lo más probable es que se olvide de estas comunicaciones wap a menos que un usuario realmente quiere informes de entrega mms.

  • ¿Por qué se destruye el servicio remoto cuando se cierra la actividad principal?
  • ¿Cómo iniciar un servicio Android desde una actividad y detener el servicio en otra actividad?
  • ¿Debería extender la clase Binder o usar un Messenger?
  • Android geofencing cuando se mata la aplicación
  • Cómo solicitar un IntentService para obtener información sobre su cola
  • ¿Comunicación Bluetooth en hilo o servicio en Android?
  • La notificación sigue en la barra después de matar al servicio
  • Compartir una biblioteca nativa en dos aplicaciones
  • Mi BroadcastReceiver no está recibiendo la intención BOOT_COMPLETED después de mis botas N1
  • Mataron el servicio de Android y las variables estáticas
  • Android: Transmisión de datos entre servicio y actividad
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.