短信发送--短信发送流程--应用层
来源:互联网 发布:网络情缘陈星 编辑:程序博客网 时间:2024/05/20 07:36
短信发送流程应用层解析
1、涉及的类
com.android.mms.ui.ComposeMessageActivitycom.android.mms.data.WorkingMessagecom.android.mms.transaction.MessageSendercom.android.mms.transaction.SmsMessageSendercom.android.mms.transaction.SmsSingleRecipientSendercom.android.mms.transaction.SmsReceiverServicecom.android.mms.transaction.SmsReceiver
2、时序图
说明:从ui界面开始,到调用中间层SmsManger的方法发送短信,大致时序就是这样,参考代码是android 2.3
3、流程解析
3.1 ComposeMessageActivity工作
该类是我们编辑短信的UI,与用户交互,如下图所示
当用户编辑完成,即可点击发送的按钮,将短信内容发送出去,点击sendbutton就会触发该button对应的监听器,由于ComposeMessageActivity实现了OnClickListener接口,所以最终调用到了onclick方法里。
1)onClick分析
该方法做了两件件事情:
一是调用isPreparedForSending方法判断当前短信是否准备发送,依据就是短信短信的接收者是否超过允许的上限,是否有接收者,以及短信是否有内容或者附件、主题之类的,不允许用户发送一条什么都没有的短信出去。
二是,上面的检查通过调用confirmSendMessageIfNeeded方法开始发送流程。当然并不是调用了该方法就一定能发送成功,该方法同样会做一系列的检查,直到符合要求了才会放行。
2)confirmSendMessageIfNeeded分析
该方法的逻辑调用如下图所示:
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()方法把处理发送的任务抛出去。
2)queueMessage()
它的职责有两个:
一是将要发送的短息保存到数据库;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); boolean requestDeliveryReport = prefs.getBoolean( MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE, DEFAULT_DELIVERY_REPORT_MODE); for (int i = 0; i < mNumberOfDests; i++) { try { log("updating Database with sub = " + mSubscription); Sms.addMessageToUri(mContext.getContentResolver(), Uri.parse("content://sms/queued"), mDests[i], mMessageText, null, mTimestamp, true /* read */, requestDeliveryReport, mThreadId, mSubscription); } catch (SQLiteException e) { SqliteWrapper.checkSQLiteException(mContext, e); } }二是,将任务转交到其他人,只不过它采用的方式是发广播;
// Notify the SmsReceiverService to send the message out Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext, SmsReceiver.class);intent.putExtra(SUBSCRIPTION, mSubscription); mContext.sendBroadcast(intent);小结:该类做了一个很重要的工作就是讲要发送的短信保存进入数据库,然后发广播通知SmsReceiver;
3.4 SmsReceiver 到 SmsReceiverService 简析
实际上SmsReceiver这家伙也不是干事的人,它仅仅是拿到手里后马上就转交给SmsReceiverService服务了,“这事不归我管,我就是一个送快递的“,SmsReceiver的角色就是这样的,调用的方法可以参考时序图;3.5 SmsReceiverService 简析
讲了很久终于干活的来了,它既然是一个服务,当然它会走自己的声明周期函数,首先是onCrate,该方法近几年是初始化,然后是onStartCommand(),该方法也没做啥,仅仅是向ServiceHandler发送消息,看来人家做苦力都做出心得了。1)ServiceHandler处理发送请求
@Override public void handleMessage(Message msg) { int serviceId = msg.arg1; Intent intent = (Intent)msg.obj; if (intent != null) { String action = intent.getAction(); int error = intent.getIntExtra("errorCode", 0); if (SMS_RECEIVED_ACTION.equals(action)) { handleSmsReceived(intent, error); } else if (SMS_CB_RECEIVED_ACTION.equals(action)) { handleCbSmsReceived(intent, error); } else if (ACTION_BOOT_COMPLETED.equals(action)) { handleBootCompleted(); } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) { handleServiceStateChanged(intent); } else if (ACTION_SEND_MESSAGE.endsWith(action)) { handleSendMessage(intent); } } // NOTE: We MUST not call stopSelf() directly, since we need to // make sure the wake lock acquired by AlertReceiver is released. SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId); } }这里接收到发送后会走handleSendMessage方法;
2)handleSendMessage()简析:
1、判断双卡是否都可以使用,如果是获取当前的卡并调用sendFirstQueuedMessage(int sub)
2、如果双卡不是都可以使用,就直接调用sendFirstQueuedMessage()方法;
注意:这里是调用的两个不同的方法,看他们的参数你就知道了,但实际上sendFirstQueuedMessage()无参的函数最终还是通过调用sendFirstQueuedMessage(int sub)来实现的;相当于最后还是调用的sendFirstQueuedMessage(int sub)这个方法;
3)sendFirstQueuedMessage(int sub)简析
它首先是从数据库中取出短信,然后调用SmsSingleRecipientSender的sendMessage()方法发送;
小结:大家可以发现走了半天,最后还是没有开始发送。
3.6 SmsSingleRecipientSender简析
sendMessage()说明:一是对短信的内容进行分割
二是将短信保存到OUTBOX的数据库表里
三是将分割的短信分开发送
四是调用的SMSManger类的sendMultipartTextMessage()发送,将发送的具体操作转移给中间层。
具体代码如下:
if (mMessageText == null) { // Don't try to send an empty message, and destination should be just // one. throw new MmsException("Null message body or have multiple destinations."); } SmsManager smsManager = SmsManager.getDefault(); ArrayList<String> messages = null; if ((MmsConfig.getEmailGateway() != null) && (Mms.isEmailAddress(mDest) || MessageUtils.isAlias(mDest))) { String msgText; msgText = mDest + " " + mMessageText; mDest = MmsConfig.getEmailGateway(); messages = smsManager.divideMessage(msgText); } else { messages = smsManager.divideMessage(mMessageText); // remove spaces from destination number (e.g. "801 555 1212" -> "8015551212") mDest = mDest.replaceAll(" ", ""); } int messageCount = messages.size(); if (messageCount == 0) { // Don't try to send an empty message. throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " + "empty messages. Original message is \"" + mMessageText + "\""); } boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0); if (!moved) { throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " + "to outbox: " + mUri); } ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(messageCount); ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount); for (int i = 0; i < messageCount; i++) { if (mRequestDeliveryReport) { // TODO: Fix: It should not be necessary to // specify the class in this intent. Doing that // unnecessarily limits customizability. deliveryIntents.add(PendingIntent.getBroadcast( mContext, 0, new Intent( MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION, mUri, mContext, MessageStatusReceiver.class), 0)); } Intent intent = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION, mUri, mContext, SmsReceiver.class); int requestCode = 0; if (i == messageCount -1) { // Changing the requestCode so that a different pending intent // is created for the last fragment with // EXTRA_MESSAGE_SENT_SEND_NEXT set to true. requestCode = 1; intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true); intent.putExtra(SUBSCRIPTION, mSubscription); } sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0)); } try { smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents, mSubscription); } catch (Exception ex) { throw new MmsException("SmsMessageSender.sendMessage: caught " + ex + " from SmsManager.sendTextMessage()"); } if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { log("sendMessage: address=" + mDest + ", threadId=" + mThreadId + ", uri=" + mUri + ", msgs.count=" + messageCount); }
4、总结
这部分主要是分析了短息的发送的一个流程,从ui点击button开始到中间层执行发送的操作,当然这里还有很多不详的地方,我也在尝试不断的完善。
- 短信发送--短信发送流程--应用层
- 短信发送流程
- Android 短信发送流程
- Android 短信发送流程
- Android 短信发送流程
- 短信的发送流程
- 普通短信发送流程
- android应用-短信发送
- SMS短信发送应用
- Android短信----发送流程---框架层(Frameworks)
- 短信发送流程:系统短信(SMS)发送流程
- GPRS模块发送短信流程
- GPRS模块发送短信流程
- 简述Android短信发送流程
- AT指令发送短信流程
- AT指令发送短信流程
- AT指令发送短信流程
- AT 指令发送短信流程!
- javascript:浮动div,可拖拽div,遮罩层(div和iframe实现)
- POCO NotificationQueue Sample疑问
- 计算几何之凸包
- Android中获取正在运行的服务-------ActivityManager.RunningServiceInfo的使用
- C 语言Shell 排序
- 短信发送--短信发送流程--应用层
- 数据库笔记六——存储过程
- ipv6地址解读---子网掩码
- Android中获取应用程序(包)的信息-----PackageManager的使用(一)
- 【解决方案】ItemsControl删除元素,但仍然显示它们
- linux内核中符号地址的获取
- 股票的亏与赚
- android start up flow
- Linux下Android环境搭建(附ndk、cdt、mat等)