Odbieraj wiadomości MMS w Android KitKat

Więc ten film Android 4.4 SMS API z #DevBytes wyjaśnia ostatnie zmiany w SMS API w KitKat. Zapewniają również link do przykładowego projektu. http://goo.gl/uQ3Nih

Sugerują, że zajmujesz się odbieraniem MMS w usłudze. Wszystko wygląda dobrze, z wyjątkiem tego, że nie wspominają o najbardziej nieudokumentowanym kawałku. Jak właściwie obsługiwać przychodzące MMS.

Oto próbka z projekt https://gist.github.com/lawloretienne/8970938

Próbowałem "obsługiwać MMS"

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

Mogę uzyskać dodatki z intencji, ale jedyną sensowną rzeczą, którą mogę wyodrębnić, jest numer, z którego wysłano MMS.

Czy ktoś może wskazać mi właściwy kierunek, jak to zrobić?

Zauważyłem, że WAP_PUSH_MESSAGE zawiera kilka rzeczy, od, temat i CONTENT_LOCATION.

Lokalizacja zawartości wydaje się być adresem url, w którym znajduje się zawartość MMS. Jak Mogę uzyskać do tego dostęp?

Oto przykład tego adresu URL

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

Gdzie X jest cyfrą w numerze telefonu urządzenia, na którym testuję.

Wygląda na to, że MMSC (Multimedia Messaging Service Center) dla T-Mobile w USA to http://mms.msg.eng.t-mobile.com/mms/wapenc

Według tej listy: http://www.activexperts.com/xmstoolkit/mmsclist/

Author: toobsco42, 2014-02-13

1 answers

Nie ma żadnej dokumentacji, więc tutaj jest kilka informacji, które pomogą.

[[9]}1) kom.google.android.mms.opracowano na podstawie materiału źródłowego. Potrzebujesz Pdu utils.

2) otrzymujesz powiadomienie push z tablicy bajtów extra o przychodzącej transmisji mms (intent.getByteArrayExtra("dane")).

3) Parse the notification push into a GenericPdu (new PduParser(rawPdu).parse()).

4) do komunikacji z serwerem WAP operatora potrzebne będą transakcje. Dostaję ustawienia transakcji po #5 poniżej. Używam:

TransactionSettings transactionSettings = new TransactionSettings(mContext, mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS).getExtraInfo());
[[9]}5) Wymuś komunikację sieciową przez wifi. Używam następujących.
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) Następnie należy zapewnić drogę do gospodarza.

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);
        }
    }
}

Oto metoda 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;
}

Lubię również używać metody opartej na odbiciu dla poprawy funkcjonalności ensureRouteToHost:

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) po zapewnieniu trasy do hosta możesz potrzebować HttpUtls ze źródła. Mocno zmodyfikowałem moją implementację używając OkHttp dla poprawy komunikacja.

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

8) z wynikowej tablicy bajtów użyj Pduparsera do parowania GenericPdu. Następnie można wyodrębnić ciało i rzucić do MultimediaMessagePdu.

9) następnie można iterację części PDU.

Istnieje niezliczona ilość rzeczy do rozważenia Z MMS. Jedną rzeczą, która przychodzi mi na myśl, jest to, jak irytujące są pokazy slajdów, więc to, co robię, to wykrywam, czy w PDU jest więcej niż 1 część, następnie kopiuję nagłówki i tworzę oddzielne MultimediaMessagePdu, z których zapisz je osobno u dostawcy treści mms telefonu. Nie zapomnij skopiować nagłówków, zwłaszcza jeśli obsługujesz wiadomości grupowe. Grupowe wiadomości to inna historia, ponieważ numer telefonu w PDU nie mówi całej historii (MultimediaMessagePdu.mmpdu ()). W nagłówku jest więcej kontaktów, które wyodrębniasz za pomocą następującego kodu.

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;
}

Oto metoda odbiorców obciążenia:

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);
            }
        }
    }
}

Oto jak iterować MultimediaMessagePdu części.

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");
    }
}

Jest o wiele więcej rozważań, takich jak animowane wsparcie GIF, które jest całkowicie możliwe :) niektórzy przewoźnicy obsługują raporty potwierdzające, a raporty dostawy też, najprawdopodobniej możesz zaniedbać te komunikaty wap, chyba że użytkownik naprawdę chce raportów dostawy mms.

 22
Author: Noah Seidman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-23 15:02:48