SMS业务实现机制分析

SMS业务包括:短信呼入、短信发出、SMS投递报告,以及本地存储等几个方面,以下我们将对应源代码,全面剖析各个业务的处理过程和实现方法:

  • 呼入:有短信呼入时系统会发出android.provider.Telephony.SMS_RECEIVED广播,这最会调用到PrivilegedSmsReceiver的onReceiveWithPrivilege方法,在该方法内启动了处理呼入业务的SmsReceiverService类,该类持有一个后台工作线程并在ServiceHandler处理句柄中调用handleSmsReceived()方法来处理SMS呼入事件,具体代码如下:
Java代码
  1. private void handleSmsReceived(Intent intent) {
  2. SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
  3. Uri messageUri = insertMessage(this, msgs);
  4. //省略......
  5. if (messageUri != null) {
  6. MessagingNotification.updateNewMessageIndicator(this, true);
  7. }
  8. }
  1. private void handleSmsReceived(Intent intent) {
  2. SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
  3. Uri messageUri = insertMessage(this, msgs);
  4. //省略......
  5. if (messageUri != null) {
  6. MessagingNotification.updateNewMessageIndicator(this, true);
  7. }
  8. }
private void handleSmsReceived(Intent intent) {
	SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
	Uri messageUri = insertMessage(this, msgs); 
        //省略......
	if (messageUri != null) {
	    MessagingNotification.updateNewMessageIndicator(this, true);
	}
} 

可以看出基本流程是:从intent中读取消息数据,调用insertMessage进行本地存储,然后再调用MessagingNotification的updateNewMessageIndicator()方法来通知用户。

仔细探究insertMessage()方法的实现,会发现它并非名副其实,它首先处理class zero类型的短信——直接显示,然后再判断是否 "replace short message" 若是则进行替换更新(update),否则才执行真正的insert将数据存储到数据库中。

  • 发出:发送消息的触发点在“消息创建页面”的mSendButton按钮和选项菜单MENU_SEND上,它们调用了isPreparedForSending, confirmSendMessageIfNeeded两个方法,前者为发送前进行预检查,后者在条件成立的情况下发送消息。首先看预检查的基本逻辑:
Java代码
  1. private boolean isPreparedForSending() {
  2. int recipientCount = recipientCount();
  3. return recipientCount > 0 && recipientCount <= MmsConfig.getRecipientLimit() && (mWorkingMessage.hasAttachment() || mWorkingMessage.hasText());
  4. }
  1. private boolean isPreparedForSending() {
  2. int recipientCount = recipientCount();
  3. return recipientCount > 0 && recipientCount <= MmsConfig.getRecipientLimit() && (mWorkingMessage.hasAttachment() || mWorkingMessage.hasText());
  4. }
private boolean isPreparedForSending() {
    int recipientCount = recipientCount();
    return recipientCount > 0 && recipientCount <= MmsConfig.getRecipientLimit() && (mWorkingMessage.hasAttachment() || mWorkingMessage.hasText());
}

逻辑很简单,首先要有接收者并且接收者的个数不能超过限制,然后是必须要有文本内容或者必须要有附件内容(针对彩信而言)。

接下来是confirmSendMessageIfNeeded方法了:它首先检查了“接收者输入框mRecipientsEditor是否可见”(当‘回复’信息时不可见,因为已有潜在接收者),不可见则直接调用sendMessage方法,否则会调用mRecipientsEditor的相关方法验证接收者的有效性:首先会检查是否有无效的接收者地址,如果有再检查是否所有接收者都是无效的,如果全是无效的则告知用户不能发送,否则弹出提示框——允许用户选择忽略无效地址,而向其它有效的接收者地址发送,这些检查都通过后,就来到了重要的sendMessage方法,sendMessage方法首先检查当前系统是否是在紧急呼叫模式(emergency callback mode),如果是则显示提示界面并终止发送。否则直接调用WorkingMessage.send方法进行发送。

WorkingMessage.send方法首先调用prepareForSave()进行预处理——确认接收者列表、处理彩信相关的:syncTextToSlideshow、removeSubjectIfEmpty等等问题;然后取得所属会话对象mConversation,取得信息文本内容、再判断是否是SMS类型,若是则直接在一个新线程运行sendSmsWorker()方法,紧接着就是调用接收者缓存系统的相关更新方法——RecipientIdCache.updateNumbers()。

sendSmsWorker是发送SMS类型短信的核心方法,它在开始和结束分别调用了消息发送前-onPreMessageSent和消息发送后-onMessageSent两个生命周期方法。它直接取得会话id、目标地址,然后将实际发送任务交给业务实体类SmsMessageSender。

SmsMessageSender类是负责发送SMS信息的关键业务类,它首先在构建器中取得消息文本、目标地址、时间戳、服务中心号码等重要信息,然后在sendMessage方法中执行实际的发送操作:核心工具类依然是SmsManager.getDefault(),然后由divideMessage方法将消息文本分割成若干符合规范长度的片段,再取得投递报告的设置状态,然后通过工具类将消息写入Sms.Outbox(短消息发件箱)位置,最后是针对每个目标接收者调用sendMultipartTextMessage方法完成消息发送,而对于消息发送结果进行响应的关键在sentIntent列表中,请看如下的关键代码:

Java代码
  1. sentIntents.add(PendingIntent.getBroadcast(mContext, 0,
  2. new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,uri,mContext,SmsReceiver.class),
  3. 0));
  1. sentIntents.add(PendingIntent.getBroadcast(mContext, 0,
  2. new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,uri,mContext,SmsReceiver.class),
  3. 0));
sentIntents.add(PendingIntent.getBroadcast(mContext, 0,
  new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,uri,mContext,SmsReceiver.class),
  0));

消息发送完成后会发出Intent.action=SmsReceiverService.MESSAGE_SENT_ACTION的广播信息,并强制接收者为SmsReceiver,而该接收者最终会委托给SmsReceiverService类的handleSmsSent方法进行处理。

  • 投递报告:发送消息方法的sendMultipartTextMessage专门有一个系统广播的参数用于报告投递情况的状态,关键代码如下:
Java代码
  1. deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0,
  2. new Intent(MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
  3. uri,
  4. mContext,
  5. MessageStatusReceiver.class)
  6. ,0));
  1. deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0,
  2. new Intent(MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
  3. uri,
  4. mContext,
  5. MessageStatusReceiver.class)
  6. ,0));
deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0,
	new Intent(MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
	  uri,
	  mContext,
	  MessageStatusReceiver.class)
,0));

关键在于Intent.action=MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION的广播信息,并且显式指定了处理该广播的目标类MessageStatusReceiver,该类首先取得回应广播(Intent)中的PDU,然后更新了数据库中的消息状态

  • 本地存储:将SMS数据存储到本地数据库中的几个关键在SmsReceiverService类的storeMessage、replaceMessage方法中,下面我们就来详细分析这两个方法的实现:…………待续…………待续………………待续……。。。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值