SmsManager发短信的相关内容整理

来源:互联网 发布:若风淘宝店服装店网址 编辑:程序博客网 时间:2024/04/28 20:28

一、短信发送部分:    

  这两天在开发一个根据从服务器获取的任务发短信的android应用。其中用到SmsManager这个类。

1、获取对SMS Manager的引用:

  SmsManager smsManager = SmsManager.getDefault();

2、初始化设备信息:包括SIM卡状态,手机号,设备唯一码IMEI等

TelephonyManager telephonyManager=(TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);int simState=telephonyManager.getSimState();//确保sim处于就绪状态switch (simState){    case (TelephonyManager.SIM_STATE_ABSENT):        Toast.makeText(this,"请先插入SIM",Toast.LENGTH_SHORT).show();        new Handler().postDelayed(new Runnable() {            @Override            public void run() {                onDestroy();            }        }, SPLASH_DISPLAY_LENGHT);        break;    case (TelephonyManager.SIM_STATE_NETWORK_LOCKED):break;    case (TelephonyManager.SIM_STATE_PIN_REQUIRED):break;    case (TelephonyManager.SIM_STATE_PUK_REQUIRED):break;    case (TelephonyManager.SIM_STATE_UNKNOWN):break;    case (TelephonyManager.SIM_STATE_READY):{        //获取设备的IMEI和手机号    mDevice_ID=telephonyManager.getDeviceId();        phone_number = telephonyManager.getLine1Number();        break;}}

只有在SIM卡ready后,才能进行发短信的操作。上面代码中分别获取了设备IMEI码和手机号。

更多的SIM卡信息获取:(以下内容为转载

/** 获取SIM卡的IMSI码 * SIM卡唯一标识:IMSI 国际移动用户识别码(IMSI:International Mobile Subscriber Identification Number)是区别移动用户的标志, * 储存在SIM卡中,可用于区别移动用户的有效信息。

IMSI由MCC、MNC、MSIN组成,其中MCC为移动国家号码,由3位数字组成, * 唯一地识别移动客户所属的国家,我国为460;MNC为网络id,由2位数字组成, * 用于识别移动客户所归属的移动网络,中国移动为00,中国联通为01,中国电信为03;

MSIN为移动客户识别码,采用等长11位数字构成。 *

唯一地识别国内GSM移动通信网中移动客户。所以要区分是移动还是联通,只需取得SIM卡中的MNC字段即可 */

[java]view plaincopyprint?
  1. public String getNetworkOperatorName2() {  
  2.         String networkOperatorName = "";  
  3.         String imsi = getTelephonyManager().getSubscriberId();  
  4.         if (imsi != null) {  
  5.             if (imsi.startsWith("46000") || imsi.startsWith("46002")) {  
  6.                 // 因为移动网络编号46000下的IMSI已经用完,所以虚拟了一个46002编号,134/159号段使用了此编号 //中国移动  
  7.                 networkOperatorName = "中国移动";  
  8.             } else if (imsi.startsWith("46001")) {  
  9.                 // 中国联通  
  10.                 networkOperatorName = "中国联通";  
  11.             } else if (imsi.startsWith("46003")) {  
  12.                 // 中国电信  
  13.                 networkOperatorName = "中国电信";  
  14.             }  
  15.         }  
  16.         return networkOperatorName;  
  17.     }  

第二种方法 TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); String operator = telManager.getSimOperator();

if(operator!=null){ if(operator.equals(“46000″) || operator.equals(“46002″)|| operator.equals(“46007″)){

//中国移动

}else if(operator.equals(“46001″)){

//中国联通

}else if(operator.equals(“46003″)){

//中国电信

} }

在文件AndroidManifest.xml中添加权限 其他方法具体使用方法请查看API 文档TelephonyManager中方法说明。

在文件 AndroidManifest.xml 中添加权限 <uses-permission android:name="android.permission.READ_PHONE_STATE"/>


 

TelephonyManager tel = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE);

String simOperator = tel.getSimOperator();

IMSI共有15位,其结构如下: MCC+MNC+MIN MCC:Mobile Country Code,移动国家码,共3位,中国为460; MNC:Mobile Network Code,移动网络码,共2位,电信03,移动02,联通GSM 01,一个典型的IMSI号码为460030912121001; MIN共有10位,其结构如下: 09+M0M1M2M3+ABCD 其中的M0M1M2M3和MDN号码中的H0H1H2H3可存在对应关系,ABCD四位为自由分配。 可以看出IMSI在MIN号码前加了MCC,可以区别出每个用户的来自的国家,因此可以实现国际漫游。在同一个国家内,如果有多个CDMA运营商,可以通过MNC来进行区别.

功能 说明

getCellLocation() 返回的单元格位置的装置 ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION

getDeviceId() 返回的IMEI / MEID的设备。 如果该设备是GSM设备 然后IMEI号将被退回,如果该设备是一个CDMA设备然后MEID 将被退回 READ_PHONE_STATE

getLine1Number() 返回设备的电话号码(MSISDN号码) READ_PHONE_STATE

getNetworkOperatorName() 返回注册的网络运营商的名字

getNetworkOperator() 返回的MCC +跨国公司的注册网络运营商

getNetworkCountryIso() 返回注册的网络运营商的国家代码

getSimCountryIso() 返回SIM卡运营商的国家代码 READ_PHONE_STATE

getSimOperator() 返回SIM卡运营商的单个核细胞数+冶 READ_PHONE_STATE

getSimOperatorName() 返回SIM卡运营商的名字 READ_PHONE_STATE

getSimSerialNumber() 返回SIM卡的序列号 READ_PHONE_STATE

getNetworkType() 返回网络设备可用的类型。 这将是 下列其中一个值:

TelephonyManager.NETWORK_TYPE_UNKNOWN TelephonyManager.NETWORK_TYPE_GPRS TelephonyManager.NETWORK_TYPE_EDGE TelephonyManager.NETWORK_TYPE_UMTS READ_PHONE_STATE getPhoneType() 返回设备的类型。 这将是以下值之一: TelephonyManager.PHONE_TYPE_NONE TelephonyManager.PHONE_TYPE_GSM TelephonyManager.PHONE_TYPE_CDMA READ_PHONE_STATE getSubscriberId() 返回用户识别码(的IMSI)的设备 READ_PHONE_STATE

 

getNeighboringCellInfo() 返回NeighboringCellInfo类代表名单 相邻小区的信息,如果可用,否则将 返回null ACCESS_COARSE_UPDATES


下面是本人写的一下方法,便于以后快速开发...

有一部分摘自http://jingyan.baidu.com/article/ae97a646b04ab4bbfd461dfe.html,谢谢

[java]view plaincopyprint?
  1. /** 
  2.      * @return Returns the TelephonyManager. 
  3.      */  
  4.     public TelephonyManager getTelephonyManager() {  
  5.         if (mTelephonyManager == null) {  
  6.             mTelephonyManager = (TelephonyManager) getApplicationContext()  
  7.                     .getSystemService(Context.TELEPHONY_SERVICE);  
  8.         }  
  9.         return mTelephonyManager;  
  10.     }  
  11.   
  12.     /** 
  13.      * @return the iMEI 
  14.      */  
  15.     public String getIMEI() {  
  16.         return getTelephonyManager().getDeviceId();  
  17.     }  
  18.   
  19.     /** 
  20.      * @return the iMEI 
  21.      */  
  22.     public String getIMSI() {  
  23.         return getTelephonyManager().getSubscriberId();  
  24.     }  
  25.   
  26.     /** 
  27.      * @return the mDN 
  28.      */  
  29.     public String getMDN() {  
  30.         return getTelephonyManager().getLine1Number();  
  31.     }  
  32.   
  33.     public int getSIMState() {  
  34.         return getTelephonyManager().getSimState();  
  35.     }  
  36.   
  37.     /** 
  38.      * 获取当前设置的电话号码 
  39.      */  
  40.     public String getPhoneNumber() {  
  41.         return getTelephonyManager().getLine1Number();  
  42.     }  
  43.       
  44.     /** 
  45.      * sim卡是否可读  
  46.      * @return 
  47.      */  
  48.     public boolean isCanUseSim() {   
  49.         try {   
  50.             return TelephonyManager.SIM_STATE_READY == getTelephonyManager().getSimState();   
  51.         } catch (Exception e) {   
  52.             e.printStackTrace();   
  53.         }   
  54.         return false;   
  55.     }   
  56.   
  57.     /** 
  58.      * 获取SIM卡号 
  59.      *  
  60.      * @return 
  61.      */  
  62.     public String getLine1Number() {  
  63.         String line1Number = getTelephonyManager().getLine1Number() == null ? "未知"  
  64.                 : getTelephonyManager().getLine1Number().toString();  
  65.         return line1Number;  
  66.     }  
  67.   
  68.     /** 
  69.      * 获取设备当前位置 
  70.      *  
  71.      * @return 
  72.      */  
  73.     public String getCellLocation() {  
  74.         String location = getTelephonyManager().getCellLocation() == null ? "未知地区"  
  75.                 : getTelephonyManager().getCellLocation().toString();  
  76.         return location;  
  77.     }  
  78.   
  79.     /** 
  80.      * 获取SIM卡运营商名称 
  81.      *  
  82.      * @return 
  83.      */  
  84.     public String getNetworkOperatorName() {  
  85.         String networkOperatorName = getTelephonyManager()  
  86.                 .getNetworkOperatorName() == null ? "未知"  
  87.                 : getTelephonyManager().getNetworkOperatorName().toString();  
  88.         return networkOperatorName;  
  89.     }  
  90.   
  91.     /** 
  92.      *  
  93.      * @return 
  94.      */  
  95.     public String getNetworkOperatorName2() {  
  96.         String networkOperatorName = "";  
  97.         String imsi = getTelephonyManager().getSubscriberId();  
  98.         if (imsi != null) {  
  99.             if (imsi.startsWith("46000") || imsi.startsWith("46002")) {  
  100.                 // 因为移动网络编号46000下的IMSI已经用完,所以虚拟了一个46002编号,134/159号段使用了此编号 //中国移动  
  101.                 networkOperatorName = "中国移动";  
  102.             } else if (imsi.startsWith("46001")) {  
  103.                 // 中国联通  
  104.                 networkOperatorName = "中国联通";  
  105.             } else if (imsi.startsWith("46003")) {  
  106.                 // 中国电信  
  107.                 networkOperatorName = "中国电信";  
  108.             }  
  109.         }  
  110.         return networkOperatorName;  
  111.     }  
  112.   
  113.     /** 
  114.      * 获取手机制式 
  115.      *  
  116.      * @return 
  117.      */  
  118.     public String getSimOperatorName() {  
  119.         String simOperatorName = getTelephonyManager().getSimOperatorName()  
  120.                 .equals("") ? "未知" : getTelephonyManager().getSimOperatorName()  
  121.                 .toString();  
  122.         return simOperatorName;  
  123.     }  



-----------------------------------------------------------

如果只是想检测SIM卡是否就绪:

因为项目中,用到了监测SIM卡是否可用,所以在这里也写一下,如何判断SIM卡是否可用..

[java]view plaincopyprint?
  1. /** 
  2.      * sim卡是否可读  
  3.      * @return 
  4.      */  
  5.     public boolean isCanUseSim() {   
  6.         try {   
  7.             return TelephonyManager.SIM_STATE_READY == getTelephonyManager().getSimState();   
  8.         } catch (Exception e) {   
  9.             e.printStackTrace();   
  10.         }   
  11.         return false;   
  12.     }   


3、发送短信:

Intent i=new Intent("com.bignerdranch.android.finishtest.SENT_SMS_ACTION");i.putExtra("task_key", task_key);//把服务器端对应的短信任务的id号传递给接收器if (pendingIntentcount>2147483646){    pendingIntentcount=-2147483648;}sentIntent = PendingIntent.getBroadcast(        MainActivity.this,  pendingIntentcount++, i,PendingIntent.FLAG_UPDATE_CURRENT);
receiverIntent = PendingIntent.getBroadcast(        MainActivity.this, 0, new Intent("com.bignerdranch.android.finishtest.DELIVERED_SMS_ACTION"),PendingIntent.FLAG_UPDATE_CURRENT);
String sendTo = jsonObject.getString("sms_target");String MessageBody = jsonObject.getString("sms_content");smsManager.sendTextMessage( sendTo, null, MessageBody+"\nid is:"+task_key, sentIntent, receiverIntent);


这段代码的重点在sendTextMessage()这个函数。它有五个参数:

第一个参数:接受方的手机号码

第二个参数:用于指定所使用的SMS服务中心,填null则表示使用默认的服务中心。

第三个参数:短信的内容

第四个参数和第五个参数:是两个PendingIntent。其中sentIntent用于跟踪短信是否发出,receiverIntent 则用于跟踪短信是否送达接收方。( 其中用到的PendingIntent会在后文中介绍。)


对于短信发送成功与否(sendIntent),需要我们注册广播接收器来进行处理。我的代码如下:

public class SendReceiver extends BroadcastReceiver {    private boolean isRegisterReceiver = false;    private String mResult;    private TaskResult taskResult;    private String id;    private View mView;    @Override    public void onReceive(Context context, Intent intent) {        // TODO Auto-generated method stub        if (intent.getAction().equals("com.bignerdranch.android.finishtest.SENT_SMS_ACTION")) {            id= intent.getStringExtra("task_key");//这里的id是从服务器获取的,对应每条短信发送任务        switch(getResultCode()){            case Activity.RESULT_OK:                taskResult=new TaskResult(MyApplication.device_id,MyApplication.phone_number,id,"OK");                Toast.makeText(MyApplication.getContext(),                        "SMS sent success actions",                        Toast.LENGTH_SHORT).show();                new Thread(new Runnable() {                    @Override                    public void run() {                       HttpUtil.postJSONtoInternet(taskResult.getTaskResult(), MyApplication.last_app_entry);//这是我自己写的一个静态方法,连接服务器,发送短信发送结果            Intent i=new Intent("com.bignerdranch.android.finishtest.RESULT_OK");                        i.putExtra("resultJsonObject",taskResult.getTaskResult().toString());                        i.putExtra("result_result",mResult);                        MyApplication.getContext().sendBroadcast(i);                    }                }).start();                break;           default:               taskResult=new TaskResult(MyApplication.device_id,MyApplication.phone_number,id,"KO");               Toast.makeText(MyApplication.getContext(),                       "SMS sent success actions",                       Toast.LENGTH_SHORT).show();               new Thread(new Runnable() {                   @Override                   public void run() {                       HttpUtil.postJSONtoInternet(taskResult.getTaskResult(), MyApplication.last_app_entry);                       Intent i=new Intent("com.bignerdranch.android.finishtest.RESULT_KO");                       i.putExtra("resultJsonObject", taskResult.getTaskResult().toString());                       i.putExtra("result_result", mResult);                       MyApplication.getContext().sendBroadcast(i);                   }               }).start();                break;        }        }    }    public void registerSendReceiver(Context mContext) {//用于注册接收器        if (!isRegisterReceiver) {            isRegisterReceiver = true;            IntentFilter filter = new IntentFilter();            filter.addAction("com.bignerdranch.android.finishtest.SENT_SMS_ACTION");            mContext.registerReceiver(SendReceiver.this, filter);        }    }    public void unRegisterSendReceiver(Context mContext) {        if (isRegisterReceiver) {            isRegisterReceiver = false;            mContext.unregisterReceiver(SendReceiver.this);        }    }}
在这个接收器中,我简单处理了短信发送情况的反馈,因为服务器只接受OK或KO。实际上,反馈结果有多种:

1)、Activity.RESULT_OK:表示一次成功的传输

2)、SmsManager.RESULT_ERROR_GENERIC_FAILURE:表示普通的传输失败

3)、SmsManager.RESULT_ERROR_RADIO_OFF:表示电话无线信号被关闭

4)、SmsManager.RESULT_ERROR_NULL_PDU:表示一次PDU(协议数据单元)错误

5)、SmsManager.RESULT_ERROR_NO_SERVICE:表示没有可以使用的手机服务

代码中的这一部分:

 Intent i=new Intent("com.bignerdranch.android.finishtest.RESULT_KO");                       i.putExtra("resultJsonObject", taskResult.getTaskResult().toString());                       i.putExtra("result_result", mResult);                       MyApplication.getContext().sendBroadcast(i);
是在发送一个广播,对应了我自己注册的另外一个接收器,用于在SendReceiver中动态修改主Activity中的控件状态。(见 我的上一篇文章)


对于短信接收成功与否(receiverIntent),也需要我们注册广播接收器来进行处理。接收到了广播也就是已经发送到目标手机号,这里只有 是否发送到 这一种状态,代码相对简单,就不贴出来了。



4、遵守短信的最大消息尺寸

运营商一般会限制一条消息的最大尺寸为160个字符,SMS Manager的divideessage方法可以接收一个字符串作为输入,并将其分成一个消息数组列表。其中每条消息都不超过最大允许的尺寸。然后,可以使用sendMultipartTextMessage方法发送消息数组。

if (MessageBody.length() > 140) {    List<String> msgs = smsManager.divideMessage(MessageBody);    sentIntent = PendingIntent.getBroadcast(            MainActivity.this,  pendingIntentcount, i,PendingIntent.FLAG_UPDATE_CURRENT);    for (String msg : msgs) {        smsManager.sendTextMessage(sendTo, null, msg, sentIntent, null);    }    pendingIntentcount++;} else {    sentIntent = PendingIntent.getBroadcast(        MainActivity.this,  pendingIntentcount++, i,PendingIntent.FLAG_UPDATE_CURRENT);    smsManager.sendTextMessage(sendTo, null, MessageBody, sentIntent, null);}

当然,也可以这么处理:

如果你只想发送一条短信,超过最大容量后的内容舍弃。可以自己截取字符串后发送。截取的方法如下:

private static String subStringByByte(String str, int len) {//截取字符串的前。。。个字节    String result = null;    if (str != null) {        byte[] a = str.getBytes();        if (a.length <= len) {            result = str;        } else if (len > 0) {            result = new String(a, 0, len);        }    }    return result;}
这个没有考虑汉字是问题。。。


最后,别忘记权限设置:

<uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.SEND_SMS" />


(关于PendingIntent的部分在下一篇文章整理)




0 0
原创粉丝点击