2014-02-13 2 views
13

#DevBytes의이 비디오 Android 4.4 SMS APIs은 KitKat의 SMS API에 대한 최근 변경 사항을 설명합니다. 또한 샘플 프로젝트에 대한 링크를 제공합니다. http://goo.gl/uQ3Nih안드로이드에서 MMS 메시지 받기 KitKat

서비스에서 MMS 수신을 처리하는 것이 좋습니다. 가장 잘 알려진 부분을 언급하는 것을 게을리하는 것을 제외하고는 모두 괜찮아 보입니다. 들어오는 MMS를 실제로 처리하는 방법. 여기

내가

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

내가 의도에서 엑스트라하지만 유일한 의미있는 일을 얻을 수있다 "는 MMS 처리"하는 것을 시도했다 https://gist.github.com/lawloretienne/8970938

프로젝트에서 샘플입니다 I 추출 할 수있는 번호는 MMS가 전송 된 번호입니다.

아무에게도이 문제를 해결하는 방법에 대해 올바른 방향을 제시 할 수 있습니까?

WAP_PUSH_MESSAGE에 FROM, SUBJECT 및 CONTENT_LOCATION이라는 몇 가지 항목이 포함되어 있습니다.

콘텐츠 위치는 MMS의 콘텐츠가 포함 된 URL 인 것으로 보입니다. 어떻게 접근 할 수 있습니까? 여기

는 X가 I가 테스트하고있는 기기의 휴대 전화 번호 숫자입니다 URL

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

의 예입니다.

그것은 미국의 T 모바일의 MMSC (멀티미디어 메시징 서비스 센터)처럼 보이는이 목록에 따르면 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 from source. Pdu 유틸리티가 필요합니다.

2) 들어오는 mms 브로드 캐스트의 바이트 배열 여분에서 통지 푸시를받습니다 (intent.getByteArrayExtra ("data")).

3) 통지 푸시를 GenericPdu (새 PduParser (rawPdu) .parse())로 구문 분석하십시오.

4) 통신사의 wap 서버와 통신하려면 TransactionSettings가 필요합니다. 아래 # 5 이후에 트랜잭션 설정이 표시됩니다. 내가 사용

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

5) 강제 네트워크 통신 무선 랜을 통해. 나는 다음을 사용한다.

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를 parge하십시오. 그런 다음 본문을 추출하여 MultimediaMessagePdu로 전송할 수 있습니다.

9) 그런 다음 PDU의 부분을 반복 할 수 있습니다.

MMS에는 수많은 것들이 있습니다. 한 가지 염두에 떠오르는 것은 Slideshows의 성가신 부분입니다. 그래서 PDU에 1 개 이상의 부품이 있으면 감지하고 머리글을 복사하여 별도의 MultimediaMessagePdu를 만듭니다.이 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 지원, 등 많은 고려 사항이있다, 당신은 사용자가 정말 정말 MMS 전송을 대부분 무시이 WAP 통신을 원하는하지 않는 한 보고서.

+0

안녕하세요. @ 노아, 안드로이드 소스 코드에 mms와 관련된 수많은 수업이 있습니다. 이 작업을 수행하는 데 필요한 특정 클래스 집합이 있습니까? 무효 수입으로 해결할 수있는 수많은 의존성이 있기 때문입니다. – toobsco42

+0

주로 pdu 유틸리티가 필요합니다. com.google.android.mms.pdu. TransactionSettings와 그것의 의존성이 필요합니다. 그것은 몇가지 문제가 있습니다. 적어도 많은 부분에서 단순화 될 필요가 있습니다. 적어도 콘텐츠 공급자 쿼리의 투영법과 where 절이 필요합니다. 거래 설정의 검색어는 KitKat 기기에서만 안정적으로 작동합니다. –

+0

ADDRESS_FIELDS.length와 같은 상수의 사용을 이해하지 못한다면 초기화 된 내용을 명확히 할 수 있습니까? –

관련 문제