正规短信群发平台发送流程

> Android平台 短信发送流程辨析(含编码)
Android平台 短信发送流程辨析(含编码)
littleran1231 & &
发布时间: & &
浏览:38 & &
回复:0 & &
悬赏:0.0希赛币
Android平台 短信发送流程剖析(含编码)
  Android平台 短信发送流程剖析(含编码)
  本文对Android平台短信发送流程进行了走读和剖析,特别是编码部分,今天将流程整理出来,以便平时参考,也希望对大家有用!!!
  先上图,下面2个图是用PPT画的,这里截图附上来:
  流程图1:
  流程图2: 
  发送流程编码解析:
  从上图中的GsmSMSDispatcher的sendText开始分析
  //GsmSMSDispatcher.java
/** {@inheritDoc} */
protected void sendText(String destAddr, String scAddr, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu (
//转②分析
scAddr, destAddr, text, (deliveryIntent != null));
HashMap map =
SmsTrackerMapFactory(destAddr, scAddr, text, pdu);
SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent,
RadioTechnologyFamily.RADIO_TECH_3GPP);
sendRawPdu(tracker); //转I分析
//SmsMessage.java
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested) {
return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); //转③分析
//SmsMessage.java
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested, byte[] header) {
return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,ENCODING_UNKNOWN/*默认编码方式*/); //转④分析
④分析 编码核心函数
//SmsMessage.java
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding) {
// Perform null parameter checks.
if (message == null || destinationAddress == null) {
SubmitPdu ret = new SubmitPdu();
// MTI = SMS-SUBMIT, UDHI = header != null
byte mtiByte = (byte)(0x01 | (header != null
0x40 : 0x00));
//MTI :bit 0 和 bit1
UDHI:bit6
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, mtiByte,
statusReportRequested, ret); //转⑤分析
// User Data (and length)
//TP-DCS 和TP-UDL
byte[] userD
if (encoding == ENCODING_UNKNOWN) {
// First, try encoding it with the GSM alphabet
encoding = ENCODING_7BIT; //默认先采用ENCODING_7BIT编码模式
if (encoding == ENCODING_7BIT) {
userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header);
//采用ENCODING_7BIT进行编码,若出现编码异常,函数会抛出异常:EncodeException,转至⑥处。编码成功转至⑦。stringToGsm7BitPackedWithHeader分析转⑧处
} else { //assume UCS-2
userData = encodeUCS2(message, header);
} catch(UnsupportedEncodingException uex) {
Log.e(LOG_TAG,
"Implausible UnsupportedEncodingException ",
} catch (EncodeException ex) { //⑥ 7bit编码模式失败后,就采用UCS-2进行编码
// Encoding to the 7-bit alphabet failed. Let's see if we can
// send it as a UCS-2 encoded message
userData = encodeUCS2(message, header);
encoding = ENCODING_16BIT;
} catch(UnsupportedEncodingException uex) {
Log.e(LOG_TAG,
"Implausible UnsupportedEncodingException ",
if (encoding == ENCODING_7BIT) {
//⑦ 7bit编码成功
if ((0xff & userData[0]) & MAX_USER_DATA_SEPTETS) {
// Message too long
// TP-Data-Coding-Scheme
// Default encoding, uncompressed
// To test writing messages to the SIM card, change this value 0x00
// to 0x12, which means "bits 1 and 0 contain message class, and the
// class is 2". Note that this takes effect for the sender. In other
// words, messages sent by the phone with this change will end up on
// the receiver's SIM card. You can then send messages to yourself
// (on a phone with this change) and they'll end up on the SIM card.
未压缩,class2,存储到SIM卡
未压缩,class0,GSM7bit编码
bo.write(0x00);
} else { // assume UCS-2
if ((0xff & userData[0]) & MAX_USER_DATA_BYTES) {
// Message too long
// TP-Data-Coding-Scheme
// Class 3, UCS-2 encoding, uncompressed
bo.write(0x0b);
未压缩,class3,UCS-2编码
// (no TP-Validity-Period)
bo.write(userData, 0, userData.length);
ret.encodedMessage = bo.toByteArray();
//SmsMessage.java
private static ByteArrayOutputStream getSubmitPduHead(
String scAddress, String destinationAddress, byte mtiByte,
boolean statusReportRequested, SubmitPdu ret)
//scAddress为短信中心号码,destinationAddress为目标地址号码
//mtiByte为MTI和UDHI 编码数据,见上面分析,statusReportRequested为状态报告 //ret 下面会写入数据到ret
ByteArrayOutputStream bo = new ByteArrayOutputStream(
MAX_USER_DATA_BYTES + 40);
// SMSC address with length octet, or 0
if (scAddress == null) {
ret.encodedScAddress =
ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
scAddress);
// TP-Message-Type-Indicator (and friends)
if (statusReportRequested) {
// Set TP-Status-Report-Request bit.
//TP-SRR bit 5 ,0x20 =
mtiByte |= 0x20;
if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested");
bo.write(mtiByte);
// space for TP-Message-Reference
bo.write(0);
byte[] daB
daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress);
// destination address length in BCD digits, ignoring TON byte and pad
// TODO Should be better.
bo.write((daBytes.length - 1) * 2
- ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0
// destination address
bo.write(daBytes, 0, daBytes.length);
// TP-Protocol-Identifier
bo.write(0);
//GsmAlphabet.java
public static byte[] stringToGsm7BitPackedWithHeader(String data, byte[] header)
throws EncodeException { //这里传进来的head为null
if (header == null || header.length == 0) {
return stringToGsm7BitPacked(data);
//转⑨分析
int headerBits = (header.length + 1) * 8;
int headerSeptets = (headerBits + 6) / 7;
byte[] ret = stringToGsm7BitPacked(data, headerSeptets, true);
// Paste in the header
ret[1] = (byte)header.
System.arraycopy(header, 0, ret, 2, header.length);
//GsmAlphabet.java
public static byte[] stringToGsm7BitPacked(String data)
throws EncodeException {
return stringToGsm7BitPacked(data, 0, true);
//转⑩分析
//GsmAlphabet.java
public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset,
boolean throwException) throws EncodeException {
int dataLen = data.length();
int septetCount = countGsmSeptets(data, throwException) + startingSeptetO
// 当传入的字符串data中含有charToGsm, charToGsmExtended中没有的字符时(例如汉字),该函数会抛出异常,这样在调用处⑥会捕获该异常。然后会采用UCS-2方式进行编码。
if (septetCount & 255) {
throw new EncodeException("Payload cannot exceed 255 septets");
int byteCount = ((septetCount * 7) + 7) / 8;
byte[] ret = new byte[byteCount + 1];
// Include space for one byte length prefix.
for (int i = 0, septets = startingSeptetOffset, bitOffset = startingSeptetOffset * 7;
i & dataLen && septets & septetC
i++, bitOffset += 7) {
char c = data.charAt(i);
int v = GsmAlphabet.charToGsm(c, throwException);
if (v == GSM_EXTENDED_ESCAPE) {
v = GsmAlphabet.charToGsmExtended(c);
// Lookup the extended char.
packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE);
bitOffset += 7;
septets++;
packSmsChar(ret, bitOffset, v);
septets++;
ret[0] = (byte) (septetCount);
// Validated by check above.
//SMSDispatcher.java
protected void sendRawPdu(SmsTracker tracker) {
HashMap map = tracker.mD
byte pdu[] = (byte[]) map.get("pdu");
PendingIntent sentIntent = tracker.mSentI
if (mSmsSendDisabled) {
if (sentIntent != null) {
sentIntent.send(RESULT_ERROR_NO_SERVICE);
} catch (CanceledException ex) {}
Log.d(TAG, "Device does not support sending sms.");
if (pdu == null) {
if (sentIntent != null) {
sentIntent.send(RESULT_ERROR_NULL_PDU);
} catch (CanceledException ex) {}
int ss = mPhone.getServiceState().getState();
// if IMS not registered on data and voice is not available...
if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
handleNotInService(ss, tracker);
String appName = getAppNameByIntent(sentIntent);
if (mCounter.check(appName, SINGLE_PART_SMS)) {
sendSms(tracker); // 转II分析
sendMessage(obtainMessage(EVENT_POST_ALERT, tracker));
//GsmSMSDispatcher.java
/** {@inheritDoc} */
protected void sendSms(SmsTracker tracker) {
HashMap&String, Object& map = tracker.mD
byte smsc[] = (byte[]) map.get("smsc");
byte pdu[] = (byte[]) map.get("pdu");
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
if (tracker.mRetryCount & 0 || !isIms()) {
// this is retry, use old method
mCm.sendSMS(IccUtils.bytesToHexString(smsc),
IccUtils.bytesToHexString(pdu), reply);
mCm.sendImsGsmSms(IccUtils.bytesToHexString(smsc),
IccUtils.bytesToHexString(pdu), reply);
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&短信发送操作流程_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
短信发送操作流程
上传于||暂无简介
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩12页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢[Android][KK][SMS]Frameworks学习——发送短信流程分析
[Android][KK][SMS]Frameworks学习——发送短信流程分析
Description
Creator&Online
二、短信数据结构
三、发送短信流程分析
四、接收短信流程分析
三、发送短信流程分析
1.Application层的短信发送流程
Application层中短信发送的流程,其逻辑的实现代码在包路径下,流程如下图。
1.1 Application层短信数据流向跟踪
a.图中省略了短信UI界面的相关操作,将WorkingMessage对象的send方法调用作为短信发送流程的开始。在该方法里做了如下操作:创建Conversation容器保存短信数据;判断彩信or短信;创建新线程,并执行preSendSmsWorker调用。
b.在第3步WorkingMessage.sendSmsWorker中,以短信的dests(发送地址,string), msgText(短信内容,string), threadId(线程ID,long)三个数据为参数构造了SmsMessageSender对象,并且调用该对象的sendMessage方法。
c.第6步和第7步是在SmsMessageSender对象的queueMessage方法中同步调用的。第6步调用Telephony Framework层中的Sms类的静态方法,把即将发送的短信相关信息保存到数据库中。第7步则发起请求发送短信的广播。
d.第7步SmsReceiver接收请求发送短信的广播,启动SmsReceiverService服务(第11步)。
e.第16步,最终该服务中的sendFirstQueueMessage方法(synchronized同步锁保证线程安全)继续响应短信发送请求:首先,读取数据库中等待发送的短信数据,以短信数据(address, msgText, threadId, status,msgUri)构造SmsSingleRecipientSender对象。然后,通过SmsSingleRecipientSender对象的sendMessage方法,继续发起短信发送的请求。
1.2 SmsSingleRecipientSender与framework层的交互
SmsSingleRecipientSender类作为app层传递短信发送请求到framework层的最后一关,它的功能只有一个sendMessage()。有必要分析其内部逻辑实现。
SmsSingleRecipientSender对象被调用sendMessage()时, 有如下逻辑处理:
a.调用SmsManager对象divideMessage方法分拆短信内容(若没有超过长度则不拆)。
b.将保存的短信转移至outbox中。
c.创建PendingIntent对象deliveryIntents和sentIntents(个数由分拆的短信数决定),用以回调广播短信发送状态报告和短信发送结果报告。
d.这里出现了分支:判断是否多sim卡。如果是,则调用MSimSmsManager对象的sendMultipartTextMessage方法。如果不是,调用SmsManager对象的sendMultipartTextMessage方法。前者获取的是isms_msim服务,后者获取的是isms服务,其余的逻辑实现是一致的。
至此,发送短信的请求被传递到framework层。
1.3 SmsManager提供给app层调用的对短信操作的接口
由于SmsManager和MSimSmsManager中提供的接口除了获取的服务不同,其他的逻辑实现基本一致,所以只分析SmsManager的接口。isms服务和isms_msim服务下节学习。
该类提供了短信拆分、短信发送、将短信复制到SIM卡、从SIM卡删除短信和小区广播等接口,接口中不做处理,直接调用其他类的方法完成。
getDefault():获得默认的SmsManager对象。
divideMessage():短信拆分。不做处理,直接调用SmsMessage.fragmentText()来完成实机的拆分操作。
sendMultipartTextMessage():短信发送。若传入的短信内容是分段的,则调用isms服务的sendMultipartText();若传入的是单短信,则通过sendTextMessage()调用isms服务的 sendText()。
sendDataMessage():发送短信至指定应用端口。不做处理,直接调用isms服务的sendData()。
copyMessageToIcc(): 将短信复制到SIM卡。不做处理,直接调用isms服务的copyMessageToIccEf()。
deleteMessageFromIcc():从SIM卡删除短信。不做处理,直接调用isms服务的updateMessageOnIccEf()。
2.Framework层的短信发送流程
发送短信的请求,从层通过对象的方法调用,已经传递到了层中,层与层交互,最终完成短信的发送请求,转换成请求,其处理流程详情如下图所示。
本图是继续上节的调用,在的中出现了分支:若传入的短信内容是分段的,则调用服务的;若传入的是单短信,则通过调用服务的&sendText()。
2.1&Framework层短信数据流向跟踪
a.第步中,方法有个入参:
String&destinationAddress //收信人的电话
String&scAddress //短信中心号码
ArrayList&String&&parts //短信内容
ArrayList&PendingIntent&&sentIntents //短信发送状态报告的回调
ArrayList&PendingIntent&&deliveryIntents //短信发送结果的回调
由此可见,由层调用层接口时,传入了短信数据:收信人电话、短信中心号码、短信内容,以及两个状态回调。该方法启动服务,并以这个参数为入参调用它的方法。
b.第步服务将这个参数传递到了两个子类或者的该方法将短信数据收信人电话、短信中心号码、短信内容构造成的对象,然后将和两个回调一起封装进对象中。
在服务中,创建的是&ImsSMSDispatcher对象(在构造函数中会两个对象:对象和对象),并且调用方法。在该方法中会根据,来调用对象的方法来具体实现。
c.第步,对象被传入两个子类或者重写的方法中。该方法中又调用(),并传入个参数:,(均从对象中取出)以及一个带参数的消息用以回调。是构造方法中获得的对象。
d.第步,在中,传入的个参数(,,消息)被封装进了对象中,并且调用。
e.第步,中又会将请求,封装成一个指定的消息,并把它放到队列中,由对象来执行。
f.第步,在中,处理收到的消息,将消息中的数据写入到的输出流,即通过将短信数据传递到层。
至此,短信的发送已经跟踪到层了。短信发送请求从层分多个步骤传递到层,在层拆分短信、创建对象等操作,然后调用到对象中发送短信的方法,将短信请求转换为对应的请求调用。
2.2&IccSmsInterfaceManager类分析()
IccSmsInterfaceManager的构造函数中有将自己注册成为服务,因此在等方法中获得的服务就是它。
ServiceManager.addService(&isms&,&this);
ISms&iccISms&=&Isms.Stub.asInterface(ServiceManager.getService(&isms&));
IccSmsInterfaceManager类,实现了ISms.stub接口,它的作用就像类注释说的那样:to&provide&an&inter-process&communication&to&access&Sms&in&Icc,为短信接入SIM卡提供内部进程通信。
IccSmsInterfaceManager的构造函数中还构造了一个ImsSMSDispatcher对象,SmsManager的sendMultipartTextMessage/sendText方法,是通过IccSmsInterfaceManager服务调用ImsSMSDispatcher对象的方法。
而SmsManager的copyMessageToIccEf/updateMessageOnIccEf/enableCellBroadcast等方法,也是通过IccSmsInterfaceManager服务,调用RIL对象的方法来完成。
2.3&SMSDispatcher与的交互
SMSDispatcher类是通过方法与交互的,方法又是由子类或者具体实现的。现在分析一下类中该方法的逻辑实现。
a.从入参对象中取出和
b.创建一个消息,并将对象封装进该消息。
c.出现分支:如果是,那么调用方法;如果不是,那么调用方法,传入的参数为、以及消息。
d.RIL.sendSMS方法做的事情就是将传入的消息和构造成的请求。最终将请求通过发送给。
由此可见,&SMSDispatcher与的交互的目的是为了把层发送短信的请求转换为请求,以便交给进行处理。
2.4&短信发送状态相关处理机制
短信能否成功发送到对方手机,主要有两个因素:手机将短信成功发送到短信中心和短信中心成功发送短信到对方手机。
2.4.1如何判断短信发送至短信中心
Modem作为发送短信的最终执行者,所以当它将短信发送给短信中心时,是知道短信发送到短信中心的结果是成功还是失败的。会将该结果反馈给层。RILReceiver会接收到消息,交给方法来处理:提交这个消息。
2.3节有讲到中创建了消息。
Message&reply&=&obtainMessage(EVENT_SEND_SMS_COMPLETE,&tracker);
这是一个回调的消息对象。对象被保存在该消息对象中,传递给了对象。而对象是在上图第步被创建的,用于构造它的三个参数分别是:
map:保存和。
sentIntent:在小节中有讲到,&SmsSingleRecipientSender.sendMessage方法中创建的对象,类型为&SmsReceiverService.MESSAGE_SENT_ACTION。使用此对象发出广播时,会进入类中的方法接收广播。此外,构造参数还包括。
deliveryIntent:方法中创建的对象,类型为&MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION。使用此对象发出广播时,会进入类中的方法接收广播。
SMSDispatcher在与对象交互时,将消息对象作为入参传递给。所以当对象收到反馈的结果后,将使用对应的消息对象发出消息通知进行回调操作。
SMSDispatcher接收到发起的消息通知,在方法中处理消息类型为。类型的消息会在方法中具体处理,逻辑实现如下:
a.获取对象以及
b.如果返回的结果无异常,那么使用发出广播,并且如果此短信需要知道是否对方已接收到,将对象保存到。
c.如果返回的结果有异常,那么构造封装有的消息,重新发送短信,最多次。
sentIntent发出广播后,类中的方法会接收到,并且通过服务,调用其方法,根据反馈的结果来更新短信发送状态及相关提示。
2.4.2如何判断对方以及成功接收到短信
如果开启短信发送的状态报告,那么短信中心将短信成功发给对方时,会将结果发送给短信发送方。接收到短信中心反馈的短信成功发送至对方的消息,交给层处理类型的消息。
RIL通过方法找到的处理方法:通过对象发出短信状态报告的消息通知。
由得知,对象是在的构造方法中获取到的。而在其子类的构造方法中对对象做了如下操作:
mCm.setOnSmsStatus(this,&EVENT_NEW_SMS_STATUS_REPORT,&null);
该方法完成了对象的消息注册。
因此,通过对象发出的消息通知,会在的中接收,并交给方法处理:
a.从中取出对象
b.从对象中获取&deliveryIntent
c.使用发出广播
上文中有讲到是由方法创建的类型为&MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION的对象。
使用此对象发出广播时,类中的方法会接收到,并且通过服务,调用其方法更新短信发送状态。
感谢关注 Ithao123精品文库频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
Swift是Apple在WWDC2014所发布的一门编程语言,用来撰写OS X和iOS应用程序[1]。在设计Swift时.就有意和Objective-C共存,Objective-C是Apple操作系统在导入Swift前使用的编程语言
Swift是供iOS和OS X应用编程的新编程语言,基于C和Objective-C,而却没有C的一些兼容约束。Swift采用了安全的编程模式和添加现代的功能来使得编程更加简单、灵活和有趣。界面则基于广受人民群众爱戴的Cocoa和Cocoa Touch框架,展示了软件开发的新方向。
PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。PHP 独特的语法混合了C、Java、Perl以及PHP自创的语法。它可以比CGI或者Perl更快速地执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。
IThao123周刊怎么用英语描述手机发短信的过程啊从编写到发送,每一个步骤,要详细一些,150字左右.
显卡吧kjDM
First,press the key to Messages,select "Write New" and enter,then you reach a blank interface for editing.Second,select an input method to edit the message.After finishing editing,press "send" key,enter the phone number that you are going to send to or select a name of whom you will send to from the phone book in your mobile,then press "OK"or "send",the message is sent to the recipient.
为您推荐:
其他类似问题
扫描下载二维码

我要回帖

更多关于 手机老收到短信验证码 的文章

 

随机推荐