IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    利用iPhone基带读写SIM卡联系人

    谌启亮 (shenqiliang@xcodev.com)发表于 2014-03-01 19:49:34
    love 0

    在《初识iPhone基带通讯》文章中,我们初步了解到了如何在iPhone中进行基带通讯,和基本的通讯方式(GSM网络AT指令),并介绍了一些比较简单AT指令。本文将进一步介绍如何利用iPhone基带读写手机SIM卡联系人。本文简要介绍一下SIM卡的一些常识,AT指令中中文字符的相关处理,并介绍如果读写SIM卡中的联系人数据。

    SIM卡存储

    SIM卡虽小,但每个SIM卡都有一定的存储空间。SIM也有容量,有32K,64K,甚至128K的都有。容量小的SIM卡一般可以存储200条联系人。SIM不仅可以存储联系人,也可以存储若干条短信,这取决于SIM卡的容量,这些容量信息在一些老式手机中可以看到。然而如今进入智能手机时代,SIM卡的容量已经显得太小了,比如在iPhone中,我们已经没法将联系人存储到SIM卡。iPhone OS 2.0开始,系统设置里加入一个将SIM卡的联系人全部导入到iPhone的功能。你可以在“设置” > “邮件、通讯录、日历”页面看到“导入SIM卡通讯录”。除此似乎再没有其他方式访问SIM卡数据。

    联系人数据

    SIM卡联系人数据结构很简单,只包括名字和电话号码这两个最基本字段。

    AT指令通讯设置

    为了方便进行我们的SIM存储,我们需要进行一些配置。包括存储位置的设定,中文的支持,回显的设定。下面一一介绍一下。

    存储位置设定

    首先我们要设定我们进行联系人操作存储单元为SIM卡:

    NSString *result = sendATCommand(baseband, @"AT+CPBS=\"SM\"\r");
    

    选择联系人存储单元的AT指令为:AT+CPBS,它的值可以为“ME”(手机)或“SM”(SIM卡)。旧式手机一般可以选择联系人保存位置是手机还是SIM卡,就是通过此命令进行设置。这里我们设置为“SM”(SIM卡)。

    AT指令中文处理

    由于AT指令中只能用ASCII码,中文的话是不支持的,这就需要我们对中文进行一些特殊的编码。目前大多数AT指令都支持UCS2编码,即Unicode两字节编码。AT指令中要把一个Unicode转换为一个4个字节的16进制表示来进行传输。比如“简体中文”要转换为“7B804F534E2D6587”。为了实现UCS2编码传输。我们需要对AT终端进行编码设置,即执行AT+CSCS="UCS2"指令:

    result = sendATCommand(baseband, @"AT+CSCS=\"UCS2\"\r");
    

    同时我也写了一个NSString的Catagory,来支持UCS2编码的转换:

    @implementation NSString(UCS2Encoding)
    
    - (NSString*)ucs2EncodingString{
        NSMutableString *result = [NSMutableString string];
        for (int i = 0; i < [self length]; i++) {
            unichar unic = [self characterAtIndex:i];
            [result appendFormat:@"%04hX",unic];
        }
        return [NSString stringWithString:result];
    }
    
    - (NSString*)ucs2DecodingString{
        NSUInteger length = [self length]/4;
        unichar *buf = malloc(sizeof(unichar)*length);
        const char *scanString = [self UTF8String];
        for (int i = 0; i < length; i++) {
            sscanf(scanString+i*4, "%04hX", buf+i);
        }
        return [[NSString alloc] initWithCharacters:buf length:length];
    }
    
    @end
    

    关闭回显

    每条AT指令执行的结果默认都会返回一遍所执行的AT指令,这个是AT指令终端的回显功能,为了减少不必要的处理,我们就把它关闭,执行ATE0:

    result = sendATCommand(baseband, @"ATE0\r");
    

    增加联系人

    增加联系人需要使用AT+CPBW指令,此命令格式为

    AT+CPBW=序号,号码,类型,名字
    

    序号是存储位置,不能超过手机存储容量。如果为空,则会在最低存储位存储。号码就是手机号码,类型一般设置为空即可。名字为联系人的姓名。如果只有序号,其他都是空,那么将删除序号下的联系人,如AT+CPBW=5将删除存储序号为5的联系人。

    我写了一个addNewSIMContact函数来插入一个联系人,相应的代码如下:

    BOOL addNewSIMContact(NSFileHandle *baseband, NSString *name, NSString *phone){
        NSString *result = sendATCommand(baseband, [NSString stringWithFormat:@"AT+CPBW=,\"%@\",,\"%@\"\r", phone, [name ucs2EncodingString]]);
        if ([result hasSuffix:@"OK\r\n"]) {
            return YES;
        }
        else{
            return NO;
        }
    }
    

    读取联系人

    读取联系人需要使用AT+CPBR指令。首先我们要查看系统能够存储多少个联系人,使用AT+CPBR=?可以返回存储容量信息。返回结果为:

    +CPBR:(起始序号-最大序号), 电话长度, 名字长度
    OK
    

    要读取联系人需要用下面指令

    AT+CPBR=起始序号,终止序号
    

    这样就会读取从起始序号到终止序号的所有联系人,返回的格式为:

    +CPBR: 序号1,电话,类型,名字
    +CPBR: 序号2,电话,类型,名字
    OK
    

    因此,先用AT+CPBR=?获取容量,然后用AT+CPBR=1,最大容量就能返回所有的联系人记录了。然后在进行一些必要的解析即可。相应的代码如下:

    NSArray *readAllSIMContacts(NSFileHandle *baseband){
        NSString *result = sendATCommand(baseband, @"AT+CPBR=?\r");
        if (![result hasSuffix:@"OK\r\n"]) {
            return nil;
        }
        int max = 0;
        sscanf([result UTF8String], "%*[^+]+CPBR: (%*d-%d)", &max;);
        result = sendATCommand(baseband, [NSString stringWithFormat:@"AT+CPBR=1,%d\r",max]);
        NSMutableArray *records = [NSMutableArray array];
        NSScanner *scanner = [NSScanner scannerWithString:result];
        [scanner scanUpToString:@"+CPBR:" intoString:NULL];
        while ([scanner scanString:@"+CPBR:" intoString:NULL]) {
            NSString *phone = nil;
            NSString *name = nil;
            [scanner scanInt:NULL];
            [scanner scanString:@",\"" intoString:NULL];
            [scanner scanUpToString:@"\"" intoString:☎];
            [scanner scanString:@"\"," intoString:NULL];
            [scanner scanInt:NULL];
            [scanner scanString:@",\"" intoString:NULL];
            [scanner scanUpToString:@"\"" intoString:&name;];
            [scanner scanUpToString:@"+CPBR:" intoString:NULL];
            if ([phone length] > 0 && [name length] > 0) {
                [records addObject:@{@"name":[name ucs2DecodingString], @"phone":phone}];
            }
        }
        return [NSArray arrayWithArray:records];
    }
    

    总结和其他

    • SIM卡有一定的容量存储联系人和短信。
    • 读写SIM卡联系人可以通过与基带通讯的AT指令进行。
    • AT指令中中文处理可以用UCS2编码方式来进行处理。
    • 对SIM卡读写前,务必要把操作的存储位置设置为SIM卡。
    • 读取联系人时可以先获取最大容量,然后根据最大容量列出所有联系人。
    • 如果需要一个完善的系统,可能还需要对联系人信息的长度进行判断和处理。可以用AT+CPBR=?获取这些信息,本文就不再详细介绍了。
    • 我已经将以上全部代码上传的gist,大家可以试试:https://gist.github.com/shenqiliang/9303513


沪ICP备19023445号-2号
友情链接