短信發送--短信發送流程--應用層

短信發送流程應用層解析

一、涉及的類

[plain]  view plain copy
  1. com.android.mms.ui.ComposeMessageActivity  
  2. com.android.mms.data.WorkingMessage  
  3. com.android.mms.transaction.MessageSender  
  4. com.android.mms.transaction.SmsMessageSender  
  5. com.android.mms.transaction.SmsSingleRecipientSender  
  6. com.android.mms.transaction.SmsReceiverService  
  7. com.android.mms.transaction.SmsReceiver  
二、時序圖
說明:從ui界面開始,到調用中間層SmsManger的方法發送短信,大體時序就是這樣,參考代碼是android 2.3

三、流程解析

3.1 ComposeMessageActivity工做

該類是咱們編輯短信的UI,與用戶交互,以下圖所示 android


當用戶編輯完成,便可點擊發送的按鈕,將短信內容發送出去,點擊sendbutton就會觸發該button對應的監聽器,因爲ComposeMessageActivity實現了OnClickListener接口,因此最終調用到了onclick方法裏。 數據庫

1)onClick分析 app

   該方法作了兩件件事情: ide

    一是調用isPreparedForSending方法判斷當前短信是否準備發送,依據就是短信短信的接收者是否超過容許的上限,是否有接收者,以及短信是否有內容或者附件、主題之類的,不容許用戶發送一條什麼都沒有的短信出去。 函數

   二是,上面的檢查經過調用confirmSendMessageIfNeeded方法開始發送流程。固然並非調用了該方法就必定能發送成功,該方法一樣會作一系列的檢查,直到符合要求了纔會放行。 ui

2)confirmSendMessageIfNeeded分析  this

該方法的邏輯調用以下圖所示: spa

3)sendMessage方法分析
上圖能夠看出最後都要走到sendMessage來,咱們來看看這個方法到底作了哪些工做。
經過查看代碼咱們能夠發現最最核心的工做就是: 把發送短信的工做交給WorkingMessage,mWorkingMessage.send(mDebugRecipients);其餘的工做也僅僅是作一些輔助型的操做。
小結:到此爲止發送短信的工做交給了WorkingMessage,那 ComposeMessageActivity主要的工做便是對雙卡的處理。

3.2 WorkingMessage簡單分析

1)send()分析
該方法作了五項工做:
一是  檢查接收者列表時否爲空,這裏我就不作具體的分析。
二是將短信內容從8字節轉換成7字節;
三是判斷當前是不是發送彩信,咱們當前是短信發送,因此可定不會走彩信的發送流程。
四是,將短信的簽名加到短信的內容上。
五是調用preSendSmsWorker()方法。
2)preSendSmsWorker分析
一是重置界面,將界面上的各個組件所有清除
二是調用sendSmsWorker方法
三是刪除草稿。
3)sendSmsWorker()所作的工做
調用SmsMessageSender的sendMessage()方法

3.3 SmsMessageSender簡析

1)sendMessage()

該方法會調用queueMessage()方法把處理髮送的任務拋出去。 .net

2)queueMessage()
它的職責有兩個:
一是將要發送的短息保存到數據庫;
[plain]  view plain copy
  1. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);  
  2.   boolean requestDeliveryReport = prefs.getBoolean(  
  3.           MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,  
  4.           DEFAULT_DELIVERY_REPORT_MODE);  
  5.   
  6.   for (int i = 0; i < mNumberOfDests; i++) {  
  7.       try {  
  8.           log("updating Database with sub = " + mSubscription);  
  9.           Sms.addMessageToUri(mContext.getContentResolver(),  
  10.                   Uri.parse("content://sms/queued"), mDests[i],  
  11.                   mMessageText, null, mTimestamp,  
  12.                   true /* read */,  
  13.                   requestDeliveryReport,  
  14.                   mThreadId, mSubscription);  
  15.       } catch (SQLiteException e) {  
  16.           SqliteWrapper.checkSQLiteException(mContext, e);  
  17.       }  
  18.   }  
二是,將任務轉交到其餘人,只不過它採用的方式是發廣播;
[plain]  view plain copy
  1.    // Notify the SmsReceiverService to send the message out  
  2.       Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext, SmsReceiver.class);  
  3. intent.putExtra(SUBSCRIPTION, mSubscription);  
  4.       mContext.sendBroadcast(intent);  
小結:該類作了一個很重要的工做就是講要發送的短信保存進入數據庫,而後發廣播通知SmsReceiver;

3.4 SmsReceiver 到 SmsReceiverService 簡析

實際上SmsReceiver這傢伙也不是幹事的人,它僅僅是拿到手裏後立刻就轉交給SmsReceiverService服務了,「這事不歸我管,我就是一個送快遞的「,SmsReceiver的角色就是這樣的,調用的方法能夠參考時序圖;

3.5 SmsReceiverService 簡析

講了好久終於幹活的來了,它既然是一個服務,固然它會走本身的聲明周期函數,首先是onCrate,該方法近幾年是初始化,而後是onStartCommand(),該方法也沒作啥,僅僅是向ServiceHandler發送消息,看來人家作苦力都作出心得了。
1)ServiceHandler處理髮送請求
[plain]  view plain copy
  1. @Override  
  2.       public void handleMessage(Message msg) {  
  3.           int serviceId = msg.arg1;  
  4.           Intent intent = (Intent)msg.obj;  
  5.           if (intent != null) {  
  6.               String action = intent.getAction();  
  7.   
  8.               int error = intent.getIntExtra("errorCode", 0);  
  9.             if (SMS_RECEIVED_ACTION.equals(action)) {  
  10.                   handleSmsReceived(intent, error);  
  11.               } else if (SMS_CB_RECEIVED_ACTION.equals(action)) {  
  12.                   handleCbSmsReceived(intent, error);  
  13.               } else if (ACTION_BOOT_COMPLETED.equals(action)) {  
  14.                   handleBootCompleted();  
  15.               } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {  
  16.                   handleServiceStateChanged(intent);  
  17.               } else if (ACTION_SEND_MESSAGE.endsWith(action)) {  
  18.                   handleSendMessage(intent);  
  19.               }  
  20.           }  
  21.           // NOTE: We MUST not call stopSelf() directly, since we need to  
  22.           // make sure the wake lock acquired by AlertReceiver is released.  
  23.           SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);  
  24.       }  
  25.   }  
這裏接收到發送後會走handleSendMessage方法;
2)handleSendMessage()簡析:
一、判斷雙卡是否均可以使用,若是是獲取當前的卡並調用sendFirstQueuedMessage(int sub)
二、若是雙卡不是均可以使用,就直接調用sendFirstQueuedMessage()方法;
注意:這裏是調用的兩個不一樣的方法,看他們的參數你就知道了,但實際上sendFirstQueuedMessage()無參的函數最終仍是經過調用sendFirstQueuedMessage(int sub)來實現的;至關於最後仍是調用的sendFirstQueuedMessage(int sub)這個方法;
3)sendFirstQueuedMessage(int sub)簡析
  它首先是從數據庫中取出短信,而後調用SmsSingleRecipientSender的sendMessage()方法發送;
小結:你們能夠發現走了半天,最後仍是沒有開始發送。

3.6  SmsSingleRecipientSender簡析

sendMessage()說明:
一是對短信的內容進行分割
二是將短信保存到OUTBOX的數據庫表裏
三是將分割的短信分開發送
四是調用的SMSManger類的sendMultipartTextMessage()發送,將發送的具體操做轉移給中間層。
具體代碼以下:
[plain]  view plain copy
  1. if (mMessageText == null) {  
  2.             // Don't try to send an empty message, and destination should be just  
  3.             // one.  
  4.             throw new MmsException("Null message body or have multiple destinations.");  
  5.         }  
  6.         SmsManager smsManager = SmsManager.getDefault();  
  7.         ArrayList<String> messages = null;  
  8.         if ((MmsConfig.getEmailGateway() != null) &&  
  9.                 (Mms.isEmailAddress(mDest) || MessageUtils.isAlias(mDest))) {  
  10.             String msgText;  
  11.             msgText = mDest + " " + mMessageText;  
  12.             mDest = MmsConfig.getEmailGateway();  
  13.             messages = smsManager.divideMessage(msgText);  
  14.         } else {  
  15.            messages = smsManager.divideMessage(mMessageText);  
  16.            // remove spaces from destination number (e.g. "801 555 1212" -> "8015551212")  
  17.            mDest = mDest.replaceAll(" ", "");  
  18.         }  
  19.         int messageCount = messages.size();  
  20.   
  21.         if (messageCount == 0) {  
  22.             // Don't try to send an empty message.  
  23.             throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " +  
  24.                     "empty messages. Original message is \"" + mMessageText + "\"");  
  25.         }  
  26.   
  27.         boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);  
  28.         if (!moved) {  
  29.             throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " +  
  30.                     "to outbox: " + mUri);  
  31.         }  
  32.   
  33.         ArrayList<PendingIntent> deliveryIntents =  new ArrayList<PendingIntent>(messageCount);  
  34.         ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);  
  35.         for (int i = 0; i < messageCount; i++) {  
  36.             if (mRequestDeliveryReport) {  
  37.                 // TODO: Fix: It should not be necessary to  
  38.                 // specify the class in this intent.  Doing that  
  39.                 // unnecessarily limits customizability.  
  40.                 deliveryIntents.add(PendingIntent.getBroadcast(  
  41.                         mContext, 0,  
  42.                         new Intent(  
  43.                                 MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,  
  44.                                 mUri,  
  45.                                 mContext,  
  46.                                 MessageStatusReceiver.class),  
  47.                         0));  
  48.             }  
  49.             Intent intent  = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,  
  50.                     mUri,  
  51.                     mContext,  
  52.                     SmsReceiver.class);  
  53.   
  54.             int requestCode = 0;  
  55.             if (i == messageCount -1) {  
  56.                 // Changing the requestCode so that a different pending intent  
  57.                 // is created for the last fragment with  
  58.                 // EXTRA_MESSAGE_SENT_SEND_NEXT set to true.  
  59.                 requestCode = 1;  
  60.                 intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);  
  61.                 intent.putExtra(SUBSCRIPTION, mSubscription);  
  62.             }  
  63.             sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));  
  64.         }  
  65.         try {  
  66.             smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents,  
  67.                        deliveryIntents, mSubscription);  
  68.         } catch (Exception ex) {  
  69.             throw new MmsException("SmsMessageSender.sendMessage: caught " + ex +  
  70.                     " from SmsManager.sendTextMessage()");  
  71.         }  
  72.         if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {  
  73.             log("sendMessage: address=" + mDest + ", threadId=" + mThreadId +  
  74.                     ", uri=" + mUri + ", msgs.count=" + messageCount);  
  75.         }  
相關文章
相關標籤/搜索