前段时间(已经过去两个月了....)公司让搞一下android彩信的拦截与发送,于是就在网上找了一些资料,开始研究它的实现过程。

PS:需要从系统源码中扣取部分文件,大概在30个左右,不知道能不能精简,没认真看过。这里我重点说一下彩信的拦截和解析,因为彩信解析方面的资料相对较少。发送的部分我会提供一下我的参考文章,并且可能会转载一下这篇文章,我就是通过这篇文章实现的彩信发送。

 

因为代码量比较大,所以就只贴下关键源码,并且说下流程和要注意的问题。仔细搜索一下的话网上可以找到相关的demo和资料(主要是彩信发送方面的,解析的好像没有),但是在使用时要注意,他们说的并不是全对的,某些方面给你误导了,他们的整体流程和源码都是好的,但是在一些点上刻意写错了(主要是pdu组包、图片或附件的类型等)。

 

简要说一下我的流程吧:

     一、拦截彩信

     1、注册彩信接收器

           彩信的拦截和网上百度或google 出来的一样,都是注册一个广播接收器,然后把该接收器的权限设置成最大值,这个最大值不是网上说的1000而是2147483647(好像是整型的最大值)

在AdroidMainfest.xml里的代码如下:
 [html] <!-- MMS SMS接收器 --> 
         <receiver 
             android:name=".app.MmsSmsReceiver"> 
             <intent-filter android:priority="2147483647"> 
                 <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 
             </intent-filter> 
             <intent-filter android:priority="2147483647"> 
                 <action 
                     android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" /> 
                 <data 
                     android:mimeType="application/vnd.wap.mms-message" /> 
             </intent-filter> 
         </receiver> 
 <!-- MMS SMS接收器 -->
   <receiver
    android:name=".app.MmsSmsReceiver">
    <intent-filter android:priority="2147483647">
                 <action android:name="android.provider.Telephony.SMS_RECEIVED" />
             </intent-filter>
    <intent-filter android:priority="2147483647">
     <action
      android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
     <data
      android:mimeType="application/vnd.wap.mms-message" />
    </intent-filter>
   </receiver>
         2、定义自己的广播接收处理类             和普通的广播接收一样,我们要自己写一个广播接收处理的类,但是要在onReceive方法里添加一句:abortBroadcast();这样在我们拦截到该条彩信信息后,当执行这一句时,该系统广播(就是接收到彩信的系统广播)就不在继续往下发送。
           我的代码:
 PS:部分方法可能不通用,自己按自己的情况来。
 [java] import com.shanzha.activity.InvalidHeaderValueException; 
 import com.shanzha.activity.MmsContent; 
 import com.shanzha.activity.PduHeaders; 
 import com.shanzha.activity.PduParser; 
  
 import android.content.BroadcastReceiver; 
 import android.content.Context; 
 import android.content.Intent; 
  
 public class MmsSmsReceiver extends BroadcastReceiver { 
     /**
      * 接收短信
      */ 
     public static final String  SMS_RECEIVE_ACTION = "android.provider.Telephony.SMS_RECEIVED";  
     /**
      * 接收彩信
      */ 
     public static final String  MMS_RECEIVE_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED"; 
     public static long date = 0; 
      Context context; 
      byte[] TransactionId; 
     @Override 
     public void onReceive(final Context context, Intent intent) { 
         // TODO Auto-generated method stub  
         this.context=context; 
         String action = intent.getAction(); 
          
         //彩信  
         if(action.equals(MMS_RECEIVE_ACTION)){ 
         PduParser parser = new PduParser(); 
  
         try { 
              PduHeaders headers = parser.parseHeaders(intent.getByteArrayExtra("data")); 
              TransactionId = headers.getTransactionId(); 
              if (headers.getMessageType() == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) { 
             //号码获取  
             String from = headers.getFrom();                         
             final String content_location = headers.getContentLocation(); 
             if (content_location != null) { 
                  new Thread() { 
                 public void run() { 
                 MmsConnect mmsConnect = new MmsContent(context,content_location,TransactionId); 
                  try { 
                       mmsConnect.connect(); 
                      } catch (Exception e) { 
                     // TODO Auto-generated catch block  
                     e.printStackTrace();} 
                                          } 
                   }.start(); 
  
             } 
                          
              } 
      
         } catch (InvalidHeaderValueException e) { 
                 // TODO Auto-generated catch block  
                 e.printStackTrace();} 
                   //广播不在发送  
         abortBroadcast(); 
         } 
     } 
  
 } 
 import com.shanzha.activity.InvalidHeaderValueException;
 import com.shanzha.activity.MmsContent;
 import com.shanzha.activity.PduHeaders;
 import com.shanzha.activity.PduParser; import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent; public class MmsSmsReceiver extends BroadcastReceiver {
  /**
   * 接收短信
   */
  public static final String  SMS_RECEIVE_ACTION = "android.provider.Telephony.SMS_RECEIVED";
  /**
   * 接收彩信
   */
  public static final String  MMS_RECEIVE_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
  public static long date = 0;
   Context context;
   byte[] TransactionId;
  @Override
  public void onReceive(final Context context, Intent intent) {
   // TODO Auto-generated method stub
   this.context=context;
   String action = intent.getAction();
   
   //彩信
   if(action.equals(MMS_RECEIVE_ACTION)){
   PduParser parser = new PduParser();   try {
        PduHeaders headers = parser.parseHeaders(intent.getByteArrayExtra("data"));
        TransactionId = headers.getTransactionId();
        if (headers.getMessageType() == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) {
    //号码获取
    String from = headers.getFrom();        
    final String content_location = headers.getContentLocation();
    if (content_location != null) {
         new Thread() {
     public void run() {
     MmsConnect mmsConnect = new MmsContent(context,content_location,TransactionId);
      try {
           mmsConnect.connect();
          } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();}
                                          }
          }.start();    }
       
        }
  
   } catch (InvalidHeaderValueException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();}
                   //广播不在发送
   abortBroadcast();
   }
  } }
  
         3、彩信内容的获取与解析 (重点和难点,pdu的解析)               其实在第二步我们能获得的仅仅是一个号码(发送者的号码)和一个url(彩信内容下载地址)地址(需要扣取系统的源码来解析彩信信息)以及每条彩信的标识id,我们可以根据号码选择是不是把该条彩信屏蔽(当然还可以进行其他操作)。如果需要获取彩信内容,就需要从我们获得url地址下载彩信信息主体,下载获得的数据是byte[]类型的,需要转换才能成为可用数据(这一块是重点,详情参考系统源码)。
              我的关键代码:
  彩信数据(内容)下载:          
 [java] protected byte[] getPdu(String url) throws IOException { 
         //    ensureRouteToHost(url, mTransactionSettings);  
             return HttpUtils.httpConnection( 
                     context, -1L, 
                     url, null, HttpUtils.HTTP_GET_METHOD, 
                     true, 
                    "10.0.0.172", 
                     80); 
         } 
 protected byte[] getPdu(String url) throws IOException {
      //    ensureRouteToHost(url, mTransactionSettings);
          return HttpUtils.httpConnection(
            context, -1L,
                  url, null, HttpUtils.HTTP_GET_METHOD,
                  true,
                 "10.0.0.172",
                  80);
      }
 彩信数据解析: [java]                 //下载彩信数据  
 mmsData=getPdu(contentLocation); 
      
 //彩信数据解析  
 PduBody body = null; 
 GenericPdu pdu = new PduParser(mmsData).parse(); 
 if ((pdu == null) || (pdu.getMessageType() != 0x84)) { 
          
                         Log.e("xml", "数据为空或类型错误"); 
                 }else if (pdu instanceof MultimediaMessagePdu) { 
            body = ((MultimediaMessagePdu) pdu).getBody(); 
             
            //获取主题 www.2cto.com   
            String subject=((MultimediaMessagePdu) pdu).getSubject().getString(); 
  if (body != null) { 
                int partsNum = body.getPartsNum(); 
                for (int i = 0; i < partsNum; i++) { 
                    PduPart part = body.getPart(i); 
                     
                    //附件类型获取  
                    String contentType=new String( part.getContentType(),"gb2312"); 
                     
                    //文本类型  
                    if(contentType.contains("text")){ 
                      
                     //文本内容获取  
                         String content= new EncodedStringValue(part.getData()).getString(); 
                         //记录  
                         MMs_Content.put("text",part.getData());                     } 
                    //jpg图片类型  
                    else if(contentType.contains("jpeg")){ 
                      
                  //图片文件生成  
                     Bitmap bmp=BitmapFactory.decodeByteArray(part.getData(), 0,part.getData().length); 
                        if(bmp!=null){ 
                     //记录  
                           MMs_Content.put("jpeg",part.getData()); 
                        }else 
                         Log.i("xml","Bitmap is null"); 
                      
                    }else{ 
                     //其他类型数据:音频等,暂不处理。  
                    } 
                } 
            } 
        } 
                   //下载彩信数据
   mmsData=getPdu(contentLocation);
    
   //彩信数据解析
   PduBody body = null;
   GenericPdu pdu = new PduParser(mmsData).parse();
   if ((pdu == null) || (pdu.getMessageType() != 0x84)) {
     
                           Log.e("xml", "数据为空或类型错误");
                   }else if (pdu instanceof MultimediaMessagePdu) {
              body = ((MultimediaMessagePdu) pdu).getBody();
             
              //获取主题
              String subject=((MultimediaMessagePdu) pdu).getSubject().getString();
    if (body != null) {
                  int partsNum = body.getPartsNum();
                  for (int i = 0; i < partsNum; i++) {
                      PduPart part = body.getPart(i);
                     
                      //附件类型获取
                      String contentType=new String( part.getContentType(),"gb2312");
                     
                      //文本类型
                      if(contentType.contains("text")){
                       
                       //文本内容获取
                        String content= new EncodedStringValue(part.getData()).getString();
                        //记录
                        MMs_Content.put("text",part.getData());                     }
                      //jpg图片类型
                      else if(contentType.contains("jpeg")){
                       
                    //图片文件生成
                       Bitmap bmp=BitmapFactory.decodeByteArray(part.getData(), 0,part.getData().length);
                          if(bmp!=null){
                       //记录
                          MMs_Content.put("jpeg",part.getData());
                          }else
                           Log.i("xml","Bitmap is null");
                      
                      }else{
                       //其他类型数据:音频等,暂不处理。
                      }
                  }
              }
          }
        4、向彩信中心返回成功状态信息。              当我们成功下载数据后要向向彩信中心返回成功的状态(第三步解析获得的彩信id),彩信中心才认为我们成功接收到彩信。
           
 [java] //给彩信中心返回成功接收信息  
             NotifyRespInd notifyRespInd = new NotifyRespInd( 
                     PduHeaders.CURRENT_MMS_VERSION, 
                     TransactionId, PduHeaders.STATUS_RETRIEVED); 
          
             mHttpBox = new HttpBox(MMSC, new PduComposer(context,notifyRespInd).make()); 
              
             mHttpBox.setConnectTimeout(50 * 1000); 
             mHttpBox.setReadTimeout(30 * 1000); 
             mHttpBox.setRequestMethod(true); 
  
             mHttpBox.addHeader("User-Agent","Nokia6120c/4.21 (SymbianOS/9.2; U; Series60/3.1 Nokia6120c/4.21; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) Mozilla/5.0 AppleWebK"); 
             mHttpBox.addHeader("Accept","*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"); 
             mHttpBox.addHeader("Content-Type","application/vnd.wap.mms-message"); 
             mHttpBox.addHeader("Accept-Charset","iso-8859-1, utf-8; q=0.7, *; q=0.7"); 
             mHttpBox.addHeader("Accept-Language","zh-cn, zh;q=1.0,en;q=0.5"); 
  
             mHttpBox.connect(); 
              
     //      mHttpBox.read();  
     //      mmsData  = mHttpBox.getInData(); 
 //给彩信中心返回成功接收信息
    NotifyRespInd notifyRespInd = new NotifyRespInd(
      PduHeaders.CURRENT_MMS_VERSION,
      TransactionId, PduHeaders.STATUS_RETRIEVED);
   
    mHttpBox = new HttpBox(MMSC, new PduComposer(context,notifyRespInd).make());
    
    mHttpBox.setConnectTimeout(50 * 1000);
    mHttpBox.setReadTimeout(30 * 1000);
    mHttpBox.setRequestMethod(true);    mHttpBox.addHeader("User-Agent","Nokia6120c/4.21 (SymbianOS/9.2; U; Series60/3.1 Nokia6120c/4.21; Profile/MIDP-2.0 Configuration/CLDC-1.1 ) Mozilla/5.0 AppleWebK");
    mHttpBox.addHeader("Accept","*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
    mHttpBox.addHeader("Content-Type","application/vnd.wap.mms-message");
    mHttpBox.addHeader("Accept-Charset","iso-8859-1, utf-8; q=0.7, *; q=0.7");
    mHttpBox.addHeader("Accept-Language","zh-cn, zh;q=1.0,en;q=0.5");    mHttpBox.connect();
    
  //  mHttpBox.read();
  //  mmsData  = mHttpBox.getInData();


 

     二、发送彩信

     这部分相对而言没有那么复杂,难点是pdu的组包,很多问题都是由组包不正确引起的,另外需要注意的一点是:要注意APN的切换,这样才能提高发送成功的成功率。这一部分的资料相对很多啊,我就不贴代码了。注意我开篇说的问题就行了,自己多试一下吧。

    这里提供一篇作为参考的文章,我就是根据这篇文章实现的彩信发送,但是同样要注意我开篇说的问题哦。