`
xjhssg
  • 浏览: 2276 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Android 如何复制短信到SIM卡中

阅读更多
在framework层下的SmsManager类中,封装好了一个copyMessageToIcc方法,只要正确地调用它便可以将短信存储到SIM卡中。
SmsManager smsManager = SmsManager.getDefault();    //用来获取一个SmsManager对象
现在我们来看一下copyMessageToIcc(byte[] smsc, byte[] pdu, int status)这个方法的三个参数:
1) byte[] smsc : 短信服务中心的地址,个人认为在复制到SIM卡过程中可以为空。
2) byte[] pdu : 中文翻译是协议数据单元,这个参数最为重要,一会我们会做详细地解释说明。
3) int status : 短信存储在Icc卡上的状态,有4种状态,1是已读,3是未读,5是已发送,7是未发送。
其实要想将将短信正确地存储到SIM卡上,pdu这个参数尤为重要,下面我们就来分析一下!
首先先看一下复制短信到SIM卡时log显示的正确pdu:

00  00  0d91683155724572f9  00  0b  11117091914323  0a4e0b73ed4e864e48ff1f

原本上面的pdu是完整连续,为了方便解释说明,特意加了空格区分开来。
00     SC Address    短信服务中心地址,通常我们发送短信时会发送一个pdu到短信服务中心,然后短信服务中心会对pdu进行一些处理再发送到目的手机,这其中就包括增加了这个SC Address和后面会介绍的时间戳。
00     PDUType     pdu的第一个八位位组,即一个八位的二进制数转变成十六进制而来,每一位代表什么意思呢?由高到低依次代表RP(应答路径)、UDHI(用户数据头标识)、SRR(状态请求报告)、VPF(有效期格式,2位)、RD(拒绝副本)、MTI(信息指示类型,2位),在这里我们其实只要全部将其设置为0就好,于是便显示为00。
0d91683155724572f9  这一段代表了目的手机的号码,0d代表后面的地址长度(二进制下为13),那么这十三个数是怎么算的呢?其实手机号为13552754279,而91代表短消息中心地址的类型(81&h表示国内,91&h表示国际)。所以0d表示的就是后面683155724572f9的长度(f9中的f是用来凑偶数位的)。
00    PID          协议标识,通常设为00就好。
0b    DCS         数据编码方案,含有中文字符的话一般默认都为0b,即00001011转化而来,具体每一位的含义暂时不做详细解释。
11117091914323     时间戳,代表的时间为11年11月07日19时19分34秒,后面的23表示时区(什么这么表示尚在研究中,可以写死,感觉意义不大)。
0a4e0b73ed4e864e48ff1f   短信的具体内容,其中0a表示信息的长度。

好了,关于pdu我们分析完了,现在要做的就是如何获取这个pdu并传进copyMessageToIcc方法中。观察源码会发现在framework/base/telephony/java/com/android/internal/telephony/gsm下的SmsMessage类中有一个getSubmitPdu方法,返回一个SubmitPdu对象,该对象有encodedScAddress和encodedMessage两个byte[]数组类型的属性,而且在多个地方被用到,和copyMessageToIcc中的参数十分相似,会不会就是我们要找的呢?经调用后发现,得到的pdu并不正确,但是没有关系,我们可以将其涉及到的方法重写,拼出我们想要的pdu!我改写的代码如下:
private SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message,
            boolean statusReportRequested, byte[] header, int encoding, long date) {

         // Perform null parameter checks.
        if (message == null || destinationAddress == null) {
            return null;
        }

        SubmitPdu ret = new SubmitPdu();
        // MTI = SMS-SUBMIT, UDHI = header != null
        //在这个方法中获得了数据编码方案(DCS,就是例子中的0b)前的所有字节。
        ByteArrayOutputStream bo = getSubmitPduHead(scAddress, destinationAddress,
                statusReportRequested, ret);
        // User Data (and length)
        byte[] userData;
        if (encoding == ENCODING_UNKNOWN) {
            // First, try encoding it with the GSM alphabet
            encoding = ENCODING_7BIT;
        }
        try {
            if (encoding == ENCODING_7BIT) {
                userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header);
            } else { // assume UCS-2
                try {
                    userData = encodeUCS2(message, header);
                } catch (UnsupportedEncodingException uex) {
                    Log.e("GSM", "Implausible UnsupportedEncodingException ", uex);
                    return null;
                }
            }
        } catch (EncodeException ex) {
            // Encoding to the 7-bit alphabet failed. Let's see if we can
            // send it as a UCS-2 encoded message
            try {
                userData = encodeUCS2(message, header);
                encoding = ENCODING_16BIT;
            } catch (UnsupportedEncodingException uex) {
                Log.e("GSM", "Implausible UnsupportedEncodingException ", uex);
                return null;
            }
        }

        if (encoding == ENCODING_7BIT) {
            if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
                // Message too long
                return null;
            }
            bo.write(0x00);
        } else { // assume UCS-2
            if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
                // Message too long
                return null;
            }
            // TP-Data-Coding-Scheme
            // Class 3, UCS-2 encoding, uncompressed
            bo.write(0x0b);     //DCS,数据编码方案
        }
        //获得所需的时间戳,否则会显示乱码
        byte[] timeStamp = getTimeStamp(date);
        for (int i=0; i<timeStamp.length; i++){
            bo.write(timeStamp[i]);
        }
        bo.write(0x23);
        //写入短信信息,含有中文时会自动捕获异常并改变其编码格式
        bo.write(userData, 0, userData.length);
        ret.encodedMessage = bo.toByteArray();
        return ret;
    }
   
    private static ByteArrayOutputStream getSubmitPduHead(
            String scAddress, String destinationAddress,
            boolean statusReportRequested, SubmitPdu ret) {
        ByteArrayOutputStream bo = new ByteArrayOutputStream(
                MAX_USER_DATA_BYTES + 40);
        // SMSC address with length octet, or 0
        if (scAddress == null) {
            ret.encodedScAddress = null;
        } else {
            ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
                    scAddress);
        }
        // TP-Message-Type-Indicator (and friends)
        if (statusReportRequested) {
            // Set TP-Status-Report-Request bit.
            mtiByte |= 0x20;
            if (Config.LOGD) Log.d("GSM", "SMS status report requested");
        }
       
        //bo.write(0);
        //bo.write(mtiByte);
       
        if(null != ret.encodedScAddress) {
            for (int i=0,len=ret.encodedScAddress.length;i<len;i++){
                bo.write(ret.encodedScAddress[i]);
            }
        }

        // space for TP-Message-Reference
        bo.write(0);

        byte[] daBytes;

        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 ? 1 : 0));

        // destination address
        bo.write(daBytes, 0, daBytes.length);

        // TP-Protocol-Identifier
        bo.write(0);
        return bo;
    }

    private byte[] encodeUCS2(String message, byte[] header)
            throws UnsupportedEncodingException {
        byte[] userData, textPart;
        textPart = message.getBytes("utf-16be");

        if (header != null) {
            // Need 1 byte for UDHL
            userData = new byte[header.length + textPart.length + 1];

            userData[0] = (byte) header.length;
            System.arraycopy(header, 0, userData, 1, header.length);
            System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
        } else {
            userData = textPart;
        }
        byte[] ret = new byte[userData.length + 1];
        ret[0] = (byte) (userData.length & 0xff);
        System.arraycopy(userData, 0, ret, 1, userData.length);
        return ret;
    }
   
    private byte[] getTimeStamp(long time){
        byte[] timeStamp=null;
        StringBuilder builder = new StringBuilder();
        SimpleDateFormat sdf=new SimpleDateFormat("yy-MM-dd-hh-mm-ss");
        String[] array = sdf.format(time).split("-");
        for(int i=0;i<array.length;i++){
            int p = Integer.parseInt(array[i]);
            int q = p/10 + 10*(p%10);
            builder = q<10 ? builder.append("0"+q) : builder.append(q);
        }
        timeStamp = IccUtils.hexStringToBytes(builder.toString());

        return timeStamp;
    }

调用上述方法后,就会得到我们想要的pdu了,但是会发现还是无法成功地将信息写入SIM卡上,究竟是为什么呢!分析log后才知道,原来pdu还少了一些东西!在将pdu传给底层的modem时,还要在其前面添加“00”,表示点对点发送,这就要更改hardware/ril/reference-ril/reference-sc8800s.c文件里的requestWriteSmsToSim了,具体代码如下:
RIL_SMS_WriteArgs *p_args;
        char *cmd;
       char *pdu;
        int length;
        int err;
        ATResponse *p_response = NULL;

        length = strlen(p_args->pdu)/2;
        asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
    asprintf(&pdu, "00%s", p_args->pdu);

       err = at_send_command_sms(cmd, pdu, "+CMGW:", &p_response);
     free(cmd); // add by lhhuang@ingenic.cn
   free(pdu);

    编译so后push到手机中,重启一下就大功告成了!
分享到:
评论

相关推荐

    android写sim卡短信

    可以对sim卡中的联系人和短信息,进行增删改查操作。可以查看sim卡的一些参数信息。

    SIM卡管家,可对sim卡中的联系人和短信进行增删改查

    采用反射来调用android 隐藏的API 实现对sim卡中的联系人和短信进行增删改查。 SIM卡管家主要功能如下:1、sim卡上的短信导出 2、sim卡联系人导出 3、sim卡上的短信导出 4、sim卡上的联系人导出 5、可以查看sim卡上...

    android 操作sim卡

    通过android平台访问sim卡的电话本和短信,可以读写电话本和读写短信

    Android例子源码GPS、GPRS、WIFI状态判断+SIM卡信息读取

    Android例子源码GPS、GPRS、WIFI状态判断+SIM卡信息读取Android例子源码GPS、GPRS、WIFI状态判断+SIM卡信息读取

    Android发短信、打电话、查询位置

    Android实现发短信、打电话和位置查询的代码

    android无法自动识别sim卡中短信中心号码(SMSC刷新error)的解决方法

    NULL 博文链接:https://dss16694.iteye.com/blog/1554298

    android获取短信并匹配姓名的几种方法

    获取短信,从本地数据库或SIM卡匹配发件人的姓名 android获取短信并匹配姓名 android获取短信并匹配姓名

    Android4.X读取SIM卡短信和联系人相关类实例分析

    主要介绍了Android 4.X读取SIM卡短信和联系人相关类,以实例形式分析了Android 4.X读取SIM卡短信和联系人的两个相关类的功能、用法与注意事项,具有一定参考借鉴价值,需要的朋友可以参考下

    安卓Android源码——获取手机通讯录的实战应用(含SIM卡中的联系人).rar

    安卓Android源码——获取手机通讯录的实战应用(含SIM卡中的联系人).rar

    android中添加AT+CMGL命令

    android中添加从SIM卡中读取短信AT+CMGL命令

    android stk

    adnroid stk框架,SIM卡应用开发工具...在android手机上,在众多图标中会有一个sim卡应用图标,点击后进入会看到一个主菜单中,有类似品牌信息,发短信,网上营业厅选项等等,菜单内容根据运营商的不同也不完全一样。 

    android 定时 短信应用(更新)

    内含两种应用,在 version 1功能(即时发送短信,定时发送短信,取消定时发送,拨号,自动搜索联系人)的基础之上,增加了接收短信,内置了通讯录,从SIM卡导入等功能,并修补回复、发送短信不显示等bug。...

    mobileweishi_sqllite_shouji_sleep14l_android_安全;android_

    一旦Android手机丢失,SIM卡变更,基于Android的手机安全卫士能够实现远程定位、报警、锁屏、销毁数据等操作。对于现实生活中日渐增多的骚扰电话和垃圾短信进行快速拦截,对生活中的重要短信进行备份和还原。查杀...

    Android项目手机卫士视频

    第一章项目简介:欢迎界面、主界面第二章手机防盗:手机sim卡绑定、GPS定位、远程锁屏、远程删除数据第三章通讯卫士:黑名单添加、电话拦截、短信拦截第四章软件管家:软件的快速启动、卸载、分享、设置第五章手机...

    Android开发应用实战详解源代码

    5.15.1 sim卡简介 5.15.2 实现原理 5.15.3 具体实现 5.16 触屏拨号 5.17 获取正在运行的程序 5.18 变换屏幕的方向 5.19 获取设备信息 5.20 小结 第6章 手机自动服务 6.1 实现短信提醒 6.2 剩余电量提醒 6.3 短信群发...

    Android MIUI通知类短信权限的坑

    比如说,MIUI手机不插SIM卡就不能USB调试安装应用,好,插,结果又让你先登录小米账号(无话可说)。MIUI权限申请也是坑! 就拿READ_SMS这个权限来说,按照安卓规范来动态申请,它不弹窗让用户允许,然后回调却是...

    双卡设置-上层UI代码分析

    详细描述了设置-SIM cards中的UI解析和SIM卡界面数据通道、电话通道和短信通道的切换与页面更新。同时描述了SIM cards中的监听与消息处理以及SIM卡启用禁用方法。

    《Google Android SDK开发范例大全(第3版)》.pdf

     全书共分11章,主要以范例集的方式来讲述android的知识点,详细介绍了开发android的人机交互界面、android常用的开发控件、android手机收发短信等通信服务、开发android手机的自动服务功能和娱乐多媒体功能以及...

    Google Android SDK开发范例大全(第3版) 1/5

    完整的手机数据存取功能:铃声模式设置、震动控制、WiFi服务、屏幕旋转、电池计量、温度测量、电信网络信息、SIM卡信息、拨打电话、短信解析、通讯录联系人、电子罗盘、屏幕手写等手机控制功能。 系统服务及研发的...

Global site tag (gtag.js) - Google Analytics