2014-02-13 61 views
13

因此,來自#DevBytes的此視頻Android 4.4 SMS APIs解釋了對KitKat中SMS API的最近更改。他們還提供與示例項目的鏈接。 http://goo.gl/uQ3Nih在Android KitKat中接收MMS消息

他們建議您在服務中處理MMS的接收。這一切看起來都很好,只是他們忽略了提及最無證的作品。如何實際處理傳入的彩信。

下面是該項目 https://gist.github.com/lawloretienne/8970938

我曾經試圖「處理MMS」

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

我可以從意向的羣衆演員,但唯一有意義的事情樣品,我可以提取的是MMS發送的號碼。

任何人都可以指出我正確的方向如何去做這件事?

我注意到WAP_PUSH_MESSAGE包含一些東西,FROM,SUBJECT和CONTENT_LOCATION。

內容位置似乎是包含MMS內容的網址。我怎樣才能訪問這個?

這裏是一個URL

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

,其中X是在我測試的設備的電話號碼的數字的例子。

它看起來像在美國的MMSC(多媒體信息服務中心)爲T-Mobile是http://mms.msg.eng.t-mobile.com/mms/wapenc

根據此列表:http://www.activexperts.com/xmstoolkit/mmsclist/

+0

如果您的聲望是** 158 **,您如何提供** 300 **的賞金?烏伊需要至少142個聲望點。我錯過了什麼嗎? –

+0

我以前有458名聲望,並且願意提供大量的賞金,因爲我很久沒有遇到過這個問題的任何解決方案。 – toobsco42

+0

我明白了......在分配賞金之前,我們已經拿到了積分。對不起,我沒有賞金的經驗,但它對我來說顯得很奇怪。 ;) –

回答

21

有零文檔所以這裏的一些信息,以幫助。

1)com.google.android.mms.pdu來源。您需要Pdu utils。

2)您從傳入的mms廣播(intent.getByteArrayExtra(「data」))的額外字節數組中獲得通知推送。

3)將通知push解析爲GenericPdu(new PduParser(rawPdu).parse())。

4)您需要使用TransactionSettings與運營商的wap服務器進行通信。我在下面的#5之後獲得交易設置。我使用:

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

5)強制通過WiFi網絡通信。我使用以下。

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)然後您需要確保到主機的路由。

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

這裏的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; 
} 

我也喜歡使用基於反射方法改進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)確保路由到主機你之後然後可以從源頭需要HttpUtls。爲了改善通信,我使用OkHttp大量修改了我的實現。

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

8)從生成的字節數組中使用PduParser來使用GenericPdu。然後你可以提取身體並投射到一個MultimediaMessagePdu。

9)然後你可以迭代PDU的各個部分。

有無數的事情要考慮與彩信。想到的一件事是幻燈片是多麼令人討厭,所以我所做的是檢測PDU中是否有多於一個的部分,然後我複製標題並創建單獨的MultimediaMessagePdu,將其分別保存到手機的MMS內容提供程序中。不要忘記複製標題,特別是如果您支持羣組消息。羣發消息是另一回事,因爲PDU中的電話號碼並不能說明整個故事(MultimediaMessagePdu.mmpdu())。使用以下代碼可以提取標題中的更多聯繫人。

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

這裏的負載收件人方法:

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

這裏是如何迭代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"); 
    } 
} 

有更多的考慮,如動畫GIF支持,這是完全有可能的:)某些運營商支持承認報告,並送達報告過,你最可能忽視這些WAP通信,除非用戶真的希望彩信交付報告。

+0

Hey @Noah,android源代碼中有大量的類與mms有關。是否有一組特定的類,我需要這些工作?因爲有大量的依賴項需要用無效導入來解決。 – toobsco42

+0

主要你需要pdu工具。 com.google.android.mms.pdu。您需要TransactionSettings及其依賴項,它有一些問題,需要在很多方面進行大量簡化,至少是內容提供者查詢的投影和where子句。請記住,交易設置中的查詢只能在KitKat設備上可靠運行。 –

+0

我不理解像ADDRESS_FIELDS.length這樣的常量的用法,你能澄清這些東西應該被初始化爲什麼嗎? –