在我的文章《初识iPhone基带通讯》中简单的介绍了如何利用iPhone基带进行通讯,接着我又写了《利用iPhone基带读写SIM卡联系人》,介绍了SIM卡数据读写的一些基带功能。下面我将进行关于iPhone基带的最后一篇介绍:《利用iPhone基带发送短信息》。阅读本文前,请先阅读一下之前的那两篇关于基带的介绍。
AT+CMGF
进行短信发送前,我们要设置短信发送的模式。短信发送模式分两种:文本模式和PDU(Protocol Data Unit)模式。文本模式中短信字符串可以直接放到AT指令中,但它不可以发中文等非ASCII字符。PDU模式是移动设备的基本短信模式,它同时可以支持中文的发送。
AT+CMGF命令用来设置短信的发送模式:
1
| result = sendATCommand(baseband, @"AT+CMGF=0\r");
|
可以通过AT+CMGF=0
指令设置发送模式为PDU模式,而AT+CMGF=1
则为文本模式。本例将主要以PDU模式进行介绍,PDU模式也更加复杂一些,但它能支持中文。
AT+CMGS
AT+CMGS指令用于发送短信,文本模式下发送流程比较简单,比如向“10010”
发送“1”。
1 2 3
| AT+CMGS="10010" > 1 <Ctrl+Z> OK
|
而PDU模式就比较复杂了,具体流程如下:
1 2 3
| AT+CMGS=[length] > [PDU] <Ctrl+Z> OK
|
其中length
是PDU除消息中心设置部分的长度,PDU
就是PDU串内容,它是一个十六进制的字符串。
PDU(Protocol Data Unit)
PDU是对短消息中心、发送目的手机号码以及短信内容等进行的一些特殊编码,它是十六进制的字符串,具体格式为:
1
| [短信息中心地址长度][短信息中心号码类型][短信息中心号码][文件头字节][信息类型][发送目的手机号码长度][发送目的手机号码类型][发送目的手机号码][协议标识][数据编码方案][有效期][用户数据长度][用户数据]
|
可以看出这个结构是蛮复杂的,一共由13项数据组成,如果是超过70个字符的长短信还需要更多字段。
手机号码的编码
从上面的编码格式可以看出,无论是短消息中心,还是发送目的手机号码,他们的编码都为:长度+类型+号码。长度就是手机号的实际长度,类型可以为91
或81
,91
表示带国际区号号码,比如前面+86
的,81
表示号码不带国际区号。由于PDU编码中规定十六进制的数据字符都是一对一对的,单数的号码位数末尾将补一个字符“F”,如10010
只有5位数字,将表示为6位的10010F
。同时手机号码中奇数和偶数的位数还要翻转。我写的翻转方法如下(NSString+Catagory):
1 2 3 4 5 6 7 8 9 10 11 12 13
| - (NSString*)hexSwipString{ unichar *oldBuf = malloc([self length]*sizeof(unichar)); unichar *newBuf = malloc([self length]*sizeof(unichar)); [self getCharacters:oldBuf range:NSMakeRange(0, [self length])]; for (int i = 0; i < [self length]; i+=2) { newBuf[i] = oldBuf[i+1]; newBuf[i+1] = oldBuf[i]; } NSString *result = [NSString stringWithCharacters:newBuf length:[self length]]; free(oldBuf); free(newBuf); return result; }
|
那么10010
的最终编码为:810110F
。
整体编码
发送短信时,可以将短消息中心长度设置为00
,那么就可以不用填写短消息中心了,它会自动采用手机默认设置,数据编码方案字段用08,即“UCS2”编码方式,为了可以支持中文。过期时间一般为“AA”,表示过期时间为一天,其实这个感觉好像没效果。其他一些字段可以直接采用默认的即可。整体编码函数如下。
1 2 3 4 5 6 7 8 9 10 11 12
| NSString *PDUEncodeSendingSMS(NSString *phone, NSString *text){ NSMutableString *string = [NSMutableString stringWithString:@"001100"]; [string appendFormat:@"%02X", (int)[phone length]]; if ([phone length]%2 != 0) { phone = [phone stringByAppendingString:@"F"]; } [string appendFormat:@"81%@",[phone hexSwipString]]; [string appendString:@"0008AA"];//数据编码方案08,过期AA NSString *ucs2Text = [text ucs2EncodingString]; [string appendFormat:@"%02x%@", (int)[ucs2Text length]/2, ucs2Text]; return [NSString stringWithString:string]; }
|
短信发送过程
上面介绍了短信发送相关的一些编码问题,下面来说下短信发送流程和相关代码。
短信AT指令发送流程函数:
1 2 3 4 5 6 7 8 9 10 11
| BOOL sendSMSWithPDUMode(NSFileHandle *baseband, NSString *phone, NSString *text){ NSString *pduString = PDUEncodeSendingSMS(phone, text); NSString *result = sendATCommand(baseband, [NSString stringWithFormat:@"AT+CMGS=%d\r", (int)[pduString length]/2-1]); result = sendATCommand(baseband, [NSString stringWithFormat:@"%@\x1A", pduString]); if ([result hasSuffix:@"OK\r\n"]) { return YES; } else{ return NO; } }
|
发送短信前,需要进行一些必要的设置
1 2 3
| NSString *result = sendATCommand(baseband, @"AT+CSCS=\"UCS2\"\r"); result = sendATCommand(baseband, @"ATE0\r"); result = sendATCommand(baseband, @"AT+CMGF=0\r");
|
OK,我们就可以向10010发送一个“测试”了。
1
| sendSMSWithPDUMode(baseband, @"10010", @"测试");
|
试试把10010换成你自己的号码,看看能否收到自己发的短信。
源码地址:https://gist.github.com/shenqiliang/9415355