今天我和同学们讨论一下Android平台下如何调用系统方法发送短信、接收短信、系统的短信库相关的问题。进入正题,我们先使用Eclipse工具模拟给自己的模拟器发送一条短信。在Eclipse下打开DDMS

Incoming number: 这里须要填写的是发件人的手机号码,这里只能输入数字否则会无法发送。 
Message: 这里为发送的内容
send: 上面两项都填写完毕点击发送键可以给模拟器发送短信。

点击发送后,模拟器中就可以看到自己收到了一条消息 发件人的号码为123456 发送内容为hello。收到短信后会将这条信息写入系统的短信库,下面我们分析分析Android系统的短信库的结构。

 
系统的短信库存在data/data/com.android.providers.telephony/databases/mmssms.db 下图蓝框中就是模拟器的短信库,我们将它打开看看里面存的是什么东东。

打开mmssms.db 在打开sms表 因为所有短信数据都储存在这张表上,下面分析一下这张表的字段。
_id 不用说了吧,标示它的唯一性
thread_id :这个字段很重要,同一个会话中他们的thread_id是一样的,也就是说通过thread_id就可以知道A与B在聊天 还是 A与C在聊天
date :这条消息发送或接收的时间
read: 0 表示未读 1表示已读
type : 1表示接收 2 表示发出
body 表示 消息的内容

我给12345回一条消息我们会看的更清楚这些节点的意义。
 

我们在看看thread_id指向的thread表
上图中可以清晰的看到 收到消息与回复消息的thread_id都为1 ,那么在thread_id这张表中

_id 不用说了吧,标示它的唯一性
date:表示最后接收或者发送消息的时间
message_count:表示发送消息的数量,这里我接收到了一条消息 也回复了一条消息那么它的数量就为2
recipient_ids:联系人ID,指向表 canonical_addresses 里的id。
snippet :最后收到或者发送的消息内容,就是上图body中存的东西

 
这么看来如果须要短信库中的数据就去访问数据库中的这两张表,sms表 uri 指向的是 "content://mms-sms/"
thread表 uri指向的是"content://mms-sms/threadID" 具体访问的方法请看Android游戏开发之数据库SQLite
详细介绍(十七)
 这里就不详细的说了。

下面进入本章代码部分的正题,调用系统方法给联系人号码发送消息

/**
* 参数说明
* destinationAddress:收信人的手机号码
* scAddress:发信人的手机号码 
* text:发送信息的内容 
* sentIntent:发送是否成功的回执,用于监听短信是否发送成功。
* DeliveryIntent:接收是否成功的回执,用于监听短信对方是否接收成功。
*/

这里我主要说一下最后两个参数, SentIntent 这个intent用于接收这条信息自己发送成功还是自己发送失败, DeliveryIntent这个intent用于对方是否接受成功。 发送成功和接受成功是不一样的,发送只是把消息发到手机移动或联通运行商那里叫发送成功,至于以后怎么处理它不关心,只管发送是否成功。 而接受成功表示接受者是否将这条消息收到。

  1. private void sendSMS(String phoneNumber, String message) {
  2. // ---sends an SMS message to another device---
  3. SmsManager sms = SmsManager.getDefault();
  4. // create the sentIntent parameter
  5. Intent sentIntent = new Intent(SENT_SMS_ACTION);
  6. PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, sentIntent,
  7. 0);
  8. // create the deilverIntent parameter
  9. Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION);
  10. PendingIntent deliverPI = PendingIntent.getBroadcast(this, 0,
  11. deliverIntent, 0);
  12. //如果短信内容超过70个字符 将这条短信拆成多条短信发送出去
  13. if (message.length() > 70) {
  14. ArrayList<String> msgs = sms.divideMessage(message);
  15. for (String msg : msgs) {
  16. sms.sendTextMessage(phoneNumber, null, msg, sentPI, deliverPI);
  17. }
  18. } else {
  19. sms.sendTextMessage(phoneNumber, null, message, sentPI, deliverPI);
  20. }
  21. }
注册 接收成功 或者发送成功的广播

  1. // 注册广播 发送消息
  2. registerReceiver(sendMessage, new IntentFilter(SENT_SMS_ACTION));
  3. registerReceiver(receiver, new IntentFilter(DELIVERED_SMS_ACTION));
注册后 在BroadcaseRecevice中可以接收到发送 接收相关的广播

  1. private BroadcastReceiver sendMessage = new BroadcastReceiver() {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. //判断短信是否发送成功
  5. switch (getResultCode()) {
  6. case Activity.RESULT_OK:
  7. Toast.makeText(context, "短信发送成功", Toast.LENGTH_SHORT).show();
  8. break;
  9. default:
  10. Toast.makeText(mContext, "发送失败", Toast.LENGTH_LONG).show();
  11. break;
  12. }
  13. }
  14. };
  15. private BroadcastReceiver receiver = new BroadcastReceiver() {
  16. @Override
  17. public void onReceive(Context context, Intent intent) {
  18. //表示对方成功收到短信
  19. Toast.makeText(mContext, "对方接收成功",Toast.LENGTH_LONG).show();
  20. }
  21. };
 
下面给出这个小例子的完整代码

  1. import java.util.ArrayList;
  2. import android.app.Activity;
  3. import android.app.PendingIntent;
  4. import android.content.BroadcastReceiver;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.IntentFilter;
  8. import android.os.Bundle;
  9. import android.telephony.SmsManager;
  10. import android.text.TextUtils;
  11. import android.view.View;
  12. import android.view.View.OnClickListener;
  13. import android.widget.Button;
  14. import android.widget.EditText;
  15. import android.widget.Toast;
  16. public class ContactsActivity extends Activity {
  17. /**发送按钮**/
  18. Button button = null;
  19. /**收件人电话**/
  20. EditText mNumber = null;
  21. /**编辑信息**/
  22. EditText mMessage = null;
  23. /**发送与接收的广播**/
  24. String SENT_SMS_ACTION = "SENT_SMS_ACTION";
  25. String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION";
  26. Context mContext = null;
  27. @Override
  28. public void onCreate(Bundle savedInstanceState) {
  29. super.onCreate(savedInstanceState);
  30. setContentView(R.layout.message);
  31. button = (Button) findViewById(R.id.button);
  32. mNumber = (EditText) findViewById(R.id.number);
  33. mMessage = (EditText) findViewById(R.id.message);
  34. mContext = this;
  35. button.setOnClickListener(new OnClickListener() {
  36. @Override
  37. public void onClick(View view) {
  38. /** 拿到输入的手机号码 **/
  39. String number = mNumber.getText().toString();
  40. /** 拿到输入的短信内容 **/
  41. String text = mMessage.getText().toString();
  42. /** 手机号码 与输入内容 必需不为空 **/
  43. if (!TextUtils.isEmpty(number) && !TextUtils.isEmpty(text)) {
  44. sendSMS(number, text);
  45. }
  46. }
  47. });
  48. // 注册广播 发送消息
  49. registerReceiver(sendMessage, new IntentFilter(SENT_SMS_ACTION));
  50. registerReceiver(receiver, new IntentFilter(DELIVERED_SMS_ACTION));
  51. }
  52. private BroadcastReceiver sendMessage = new BroadcastReceiver() {
  53. @Override
  54. public void onReceive(Context context, Intent intent) {
  55. //判断短信是否发送成功
  56. switch (getResultCode()) {
  57. case Activity.RESULT_OK:
  58. Toast.makeText(context, "短信发送成功", Toast.LENGTH_SHORT).show();
  59. break;
  60. default:
  61. Toast.makeText(mContext, "发送失败", Toast.LENGTH_LONG).show();
  62. break;
  63. }
  64. }
  65. };
  66. private BroadcastReceiver receiver = new BroadcastReceiver() {
  67. @Override
  68. public void onReceive(Context context, Intent intent) {
  69. //表示对方成功收到短信
  70. Toast.makeText(mContext, "对方接收成功",Toast.LENGTH_LONG).show();
  71. }
  72. };
  73. /**
  74. * 参数说明
  75. * destinationAddress:收信人的手机号码
  76. * scAddress:发信人的手机号码
  77. * text:发送信息的内容
  78. * sentIntent:发送是否成功的回执,用于监听短信是否发送成功。
  79. * DeliveryIntent:接收是否成功的回执,用于监听短信对方是否接收成功。
  80. */
  81. private void sendSMS(String phoneNumber, String message) {
  82. // ---sends an SMS message to another device---
  83. SmsManager sms = SmsManager.getDefault();
  84. // create the sentIntent parameter
  85. Intent sentIntent = new Intent(SENT_SMS_ACTION);
  86. PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, sentIntent,
  87. 0);
  88. // create the deilverIntent parameter
  89. Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION);
  90. PendingIntent deliverPI = PendingIntent.getBroadcast(this, 0,
  91. deliverIntent, 0);
  92. //如果短信内容超过70个字符 将这条短信拆成多条短信发送出去
  93. if (message.length() > 70) {
  94. ArrayList<String> msgs = sms.divideMessage(message);
  95. for (String msg : msgs) {
  96. sms.sendTextMessage(phoneNumber, null, msg, sentPI, deliverPI);
  97. }
  98. } else {
  99. sms.sendTextMessage(phoneNumber, null, message, sentPI, deliverPI);
  100. }
  101. }
  102. }
一定要在AndroidManifest.xml中添加发送短信的权限噢。

  1. <!--取得发短信的权限 -->
  2. <uses-permission android:name="android.permission.SEND_SMS" />
 

发送完消息后打开手机的发信箱发现没有看到刚才发的消息,这是为什么呢? 是这样的。调用sendTextMessage 确实是发送消息 ,但是系统的短信库中没有这条消息 所以就看不到了。如果想要在系统的短信库中看到消息就必需把这条消息插到系统的短信库。

下面这段代码在发短信的同时也将短信内容写入系统库,这样在发件箱中就可以看到我们发送的短信了。

  1. button.setOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View view) {
  4. /** 拿到输入的手机号码 **/
  5. String number = mNumber.getText().toString();
  6. /** 拿到输入的短信内容 **/
  7. String text = mMessage.getText().toString();
  8. /** 手机号码 与输入内容 必需不为空 **/
  9. if (!TextUtils.isEmpty(number) && !TextUtils.isEmpty(text)) {
  10. sendSMS(number, text);
  11. /**将发送的短信插入数据库**/
  12. ContentValues values = new ContentValues();
  13. //发送时间
  14. values.put("date", System.currentTimeMillis());
  15. //阅读状态
  16. values.put("read", 0);
  17. //1为收 2为发
  18. values.put("type", 2);
  19. //送达号码
  20. values.put("address", number);
  21. //送达内容
  22. values.put("body", text);
  23. //插入短信库
  24. getContentResolver().insert(Uri.parse("content://sms"),values);
  25. }
  26. }
  27. });

还是一定要在AndroidManifest.xml中添加相关的权限噢。

  1. <!--  发送消息-->
  2. <uses-permission android:name="android.permission.SEND_SMS"/>
  3. <!--  阅读消息-->
  4. <uses-permission android:name="android.permission.READ_SMS"/>
  5. <!--  写入消息-->
  6. <uses-permission android:name="android.permission.WRITE_SMS" />
  7. <!-- 接收消息 -->
  8. <uses-permission android:name="android.permission.RECEIVE_SMS" />