今天我和同学们讨论一下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" />
 

Android软件开发之发送短信与系统短信库解析的更多相关文章

  1. 转: Android 软件开发之如何使用Eclipse Debug调试程序详解(七)

    转自: http://www.uml.org.cn/mobiledev/201110092.asp Android 软件开发之如何使用Eclipse Debug调试程序详解(七)   发布于2011- ...

  2. Android软件开发需要学什么

    首先,需要学习哪些Android开发技术? Android的开发技术很多,在开始学习的时候不可能一次性全部学会,也没有必要一开始都全部学会,但是有些技术是非常常用的,需要在开始时打好基础,这些技术时: ...

  3. Android黑科技,读取用户短信+修改系统短信数据库

    安卓系统比起ios系统最大的缺点,相信大家都知道,就是系统安全问题.这篇博客就秀一波“黑科技”. 读取用户短信 Android应用能读取用户手机上的短信,相信已经不是什么新鲜事,比如我们收到的短信验证 ...

  4. Android软件开发之盘点全部Dialog对话框大合集(一)

    对话框大合集 今天我用自己写的一个Demo和大家具体介绍一个Android中的对话框的使用技巧. 1.确定取消对话框 个button   通过调用setPositiveButton方法和 setNeg ...

  5. Android软件开发之获取通讯录联系人信息

    Android手机的通讯录联系人全部都存在系统的数据库中,如果须要获得通讯里联系人的信息就须要访问系统的数据库,才能将信息拿出来. 这一篇文章我主要带领同学们熟悉Android的通讯录机制. 图中选中 ...

  6. android软件开发基础

    1.android特性:开放性:开源的一个基础, 方便性: 平等性: 2.Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,Broadc ...

  7. Android 软件开发之如何使用Eclipse Debug调试程序详解及Eclipse常用快捷键(转)

    1.在程序中添加一个断点如果所示:在Eclipse中添加了一个程序断点 在Eclipse中一共有三种添加断点的方法 第一种: 在红框区域右键出现菜单后点击第一项 Toggle Breakpoint 将 ...

  8. 【Android 界面效果18】Android软件开发之常用系统控件界面整理

    [java] view plaincopyprint?   <span style="font-size:18px">1.文本框TextView TextView的作用 ...

  9. Android软件开发之常用系统控件界面整理

    1.文本框TextView TextView的作用是用来显示一个文本框,下面我用两种方式为大家呈现TextView, 第一种是通过xml布局文件呈现 ,第二种是通过代码来呈现,由此可见Android ...

随机推荐

  1. SinalR+WebSocket

    1.参考资料: http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-server http://signalr.ne ...

  2. pytest学习笔记(三)

    接着上一篇的内容,这里主要讲下参数化,pytest很好的支持了测试函数中变量的参数化 一.pytest的参数化 1.通过命令行来实现参数化 文档中给了一个简单的例子, test_compute.py ...

  3. 浏览器的visibilitychange 事件ie10以下不兼容

    方法1, <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  4. chrome和火狐获取资源

    获取网站数据: chrome下获取网站数据可以用如下方式去获取: 而火狐则可以按以下方式获取: 在该目录下找到你想要的数据. 获取本地的数据: chrome下获取本地的数据: firefox下获取本地 ...

  5. 2016 年开发者应该掌握的十个 Postgres 技巧

    [编者按]作为一款开源的对象-关系数据库,Postgres 一直得到许多开发者喜爱.近日,Postgres 正式发布了9.5版本,该版本进行了大量的修复和功能改进.而本文将分享10个 Postgres ...

  6. C++ 标准库之iomanip

    C++ 标准库之iomanip istream & istream::get(char *, int, char = '\n');istream & istream::getline( ...

  7. dos2unix(windows脚本文件放到unix下运行要注意)

    在windows下编写的shell脚本文件,直接放到linux下运行,是不行的. infiniDB的倒库脚本文件load.sh,将tbl文件导入infiniDB,怎么运行不成功,不建job.运来,是w ...

  8. 强大的数据库工具 dbForge Studio ForMySql

    优点: 1.可以将MySql数据库操作仿 sqlserver 的操作方式,便于操作 2.强大的比较拷贝能力.菜单栏上的 Comparison 的功能,可以比较两个数据库的差别,同时可以将数据库Copy ...

  9. javascript学习笔记二

    1.js的string对象 **创建 String对象 *** var str = "abc"; **方法 和 属性(文档) *** 属性 length : 字符串的长度 ***方 ...

  10. mongodb的几种启动方法

    1 mongodb的几种启动方法   启动Mongodb服务有两种方式,前台启动或者Daemon方式启动,前者启动会需要保持当前Session不能被关闭,后者可以作为系统的fork进程执行,下文中的p ...