Android SMS(一) —— 读取短信
Android SMS Read
- package com.homer.sms;
- import java.sql.Date;
- import java.text.SimpleDateFormat;
- import android.app.Activity;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteException;
- import android.net.Uri;
- import android.os.Bundle;
- import android.util.Log;
- import android.widget.ScrollView;
- import android.widget.TableLayout;
- import android.widget.TextView;
- /**
- * 读取手机短信
- *
- * @author sunboy_2050
- * @since http://blog.csdn.net/sunboy_2050
- * @date 2012.03.06
- */
- public class smsRead extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- TextView tv = new TextView(this);
- tv.setText(getSmsInPhone());
- ScrollView sv = new ScrollView(this);
- sv.addView(tv);
- setContentView(sv);
- }
- public String getSmsInPhone() {
- final String SMS_URI_ALL = "content://sms/";
- final String SMS_URI_INBOX = "content://sms/inbox";
- final String SMS_URI_SEND = "content://sms/sent";
- final String SMS_URI_DRAFT = "content://sms/draft";
- final String SMS_URI_OUTBOX = "content://sms/outbox";
- final String SMS_URI_FAILED = "content://sms/failed";
- final String SMS_URI_QUEUED = "content://sms/queued";
- StringBuilder smsBuilder = new StringBuilder();
- try {
- Uri uri = Uri.parse(SMS_URI_ALL);
- String[] projection = new String[] { "_id", "address", "person", "body", "date", "type" };
- Cursor cur = getContentResolver().query(uri, projection, null, null, "date desc"); // 获取手机内部短信
- if (cur.moveToFirst()) {
- int index_Address = cur.getColumnIndex("address");
- int index_Person = cur.getColumnIndex("person");
- int index_Body = cur.getColumnIndex("body");
- int index_Date = cur.getColumnIndex("date");
- int index_Type = cur.getColumnIndex("type");
- do {
- String strAddress = cur.getString(index_Address);
- int intPerson = cur.getInt(index_Person);
- String strbody = cur.getString(index_Body);
- long longDate = cur.getLong(index_Date);
- int intType = cur.getInt(index_Type);
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
- Date d = new Date(longDate);
- String strDate = dateFormat.format(d);
- String strType = "";
- if (intType == 1) {
- strType = "接收";
- } else if (intType == 2) {
- strType = "发送";
- } else {
- strType = "null";
- }
- smsBuilder.append("[ ");
- smsBuilder.append(strAddress + ", ");
- smsBuilder.append(intPerson + ", ");
- smsBuilder.append(strbody + ", ");
- smsBuilder.append(strDate + ", ");
- smsBuilder.append(strType);
- smsBuilder.append(" ]\n\n");
- } while (cur.moveToNext());
- if (!cur.isClosed()) {
- cur.close();
- cur = null;
- }
- } else {
- smsBuilder.append("no result!");
- } // end if
- smsBuilder.append("getSmsInPhone has executed!");
- } catch (SQLiteException ex) {
- Log.d("SQLiteException in getSmsInPhone", ex.getMessage());
- }
- return smsBuilder.toString();
- }
- }
AndroidManifest.xml 权限
记得在AndroidManifest.xml中加入android.permission.READ_SMS这个permission
<uses-permission android:name="android.permission.READ_SMS" />
运行结果:
代码示例
URI主要有:
content://sms/ 所有短信
content://sms/inbox 收件箱
content://sms/sent 已发送
content://sms/draft 草稿
content://sms/outbox 发件箱
content://sms/failed 发送失败
content://sms/queued 待发送列表
- _id => 短消息序号 如100
- thread_id => 对话的序号 如100
- address => 发件人地址,手机号.如+8613811810000
- person => 发件人,返回一个数字就是联系人列表里的序号,陌生人为null
- date => 日期 long型。如1256539465022
- protocol => 协议 0 SMS_RPOTO, 1 MMS_PROTO
- read => 是否阅读 0未读, 1已读
- status => 状态 -1接收,0 complete, 64 pending, 128 failed
- type => 类型 1是接收到的,2是已发出
- body => 短消息内容
- service_center => 短信服务中心号码编号。如+8613800755500
Cursor cursor = getContentResolver().query(uri, projection, "where .." new String[]{"", ""}, "order by ..")
Android短信存储数据库
偶然发现了Android源码中的一个类MmsSmsDatabaseHelper.java,原来android将所有的短信信息都存入了mmssms.db中。
公开的SDK中没有这个类,不能直接使用。于是自己写了一个SQLiteOpenHelper,但是查询的时候发生SQL异常。看来不能为所欲为了,不过据网上资料介绍可以拷贝db文件来实现短信数据备份。
MmsSmsDatabaseHelper.java在Android源码中的路径:
packages/providers/TelephonyProvider/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
sms数据库中的字段如下:
_id 一个自增字段,从1开始
thread_id 序号,同一发信人的id相同
address 发件人手机号码
person 联系人列表里的序号,陌生人为null
date 发件日期
protocol 协议,分为: 0 SMS_RPOTO, 1 MMS_PROTO
read 是否阅读 0未读, 1已读
status 状态 -1接收,0 complete, 64 pending, 128 failed
type
ALL = 0;
INBOX = 1;
SENT = 2;
DRAFT = 3;
OUTBOX = 4;
FAILED = 5;
QUEUED = 6;
body 短信内容
service_center 短信服务中心号码编号
subject 短信的主题
reply_path_present TP-Reply-Path
locked
sms数据库表字段类型的源码:
- private void createSmsTables(SQLiteDatabase db) {
- // N.B.: Whenever the columns here are changed, the columns in
- // {@ref MmsSmsProvider} must be changed to match.
- db.execSQL("CREATE TABLE sms (" +
- "_id INTEGER PRIMARY KEY," +
- "thread_id INTEGER," +
- "address TEXT," +
- "person INTEGER," +
- "date INTEGER," +
- "date_sent INTEGER DEFAULT 0," +
- "protocol INTEGER," +
- "read INTEGER DEFAULT 0," +
- "status INTEGER DEFAULT -1," + // a TP-Status value
- // or -1 if it
- // status hasn't
- // been received
- "type INTEGER," +
- "reply_path_present INTEGER," +
- "subject TEXT," +
- "body TEXT," +
- "service_center TEXT," +
- "locked INTEGER DEFAULT 0," +
- "error_code INTEGER DEFAULT 0," +
- "seen INTEGER DEFAULT 0" +
- ");");
- ....
- }
packages/providers/TelephonyProvider/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
联系人为空
短信数据库里面如果你是先受到陌生短信之后再把陌生人添加到联系人列表的话,短信数据库里面的person字段就为null,如果你是先添加联系人再发短信的话,短信数据库里面的person字段就不为空了,所以你要是想通过短信数据库里的字段取得联系人的其他信息的话,只能通过地址来取。
参考推荐:
Android SMS Messaging
Android SMS(二)—— 读取短信保存到 SQLite
Android 之 SMS 短信在Android系统中是保存在SQLite数据库中的,但不让其它程序访问(Android系统的安全机制)
现在我们在读取手机内的SMS短信,先保存在我们自己定义的SQLite数据库中,然后读取SQLite数据库提取短信,并显示
SMS短信SQLite存取代码:
- package com.homer.sms;
- import java.sql.Date;
- import java.text.SimpleDateFormat;
- import org.loon.wsi.R;
- import android.app.Activity;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.graphics.Color;
- import android.net.Uri;
- import android.os.Bundle;
- import android.util.Log;
- import android.widget.TableLayout;
- import android.widget.TableRow;
- import android.widget.TableRow.LayoutParams;
- import android.widget.TextView;
- /**
- * 读取手机短信, 先保存到SQLite数据,然后再读取数据库显示
- *
- * @author sunboy_2050
- * @since http://blog.csdn.net/sunboy_2050
- * @date 2012.03.06
- */
- public class smsRead4 extends Activity {
- TableLayout tableLayout;
- int index = 0;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- tableLayout = (TableLayout) findViewById(R.id.tableLayout);
- showSMS();
- }
- private void showSMS() {
- SmsHander smsHander = new SmsHander(this);
- smsHander.createSMSDatabase(); // 创建SQLite数据库
- smsHander.insertSMSToDatabase(); // 读取手机短信,插入SQLite数据库
- Cursor cursor = smsHander.querySMSInDatabase(100); // 获取前100条短信(日期排序)
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- String strAddress = cursor.getString(cursor.getColumnIndex("address"));
- String strDate = cursor.getString(cursor.getColumnIndex("date"));
- String strBody = cursor.getString(cursor.getColumnIndex("body"));
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date = new Date(Long.parseLong(strDate));
- strDate = dateFormat.format(date);
- String smsTitle = strAddress + "\t\t" + strDate;
- String smsBody = strBody + "\n";
- Log.i("tableRow", smsTitle + smsBody);
- // title Row
- TableRow trTitle = new TableRow(this);
- trTitle.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- TextView tvTitle = new TextView(this);
- tvTitle.setText(smsTitle);
- tvTitle.getPaint().setFakeBoldText(true); // 加粗字体
- tvTitle.setTextColor(Color.RED);
- tvTitle.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- trTitle.addView(tvTitle);
- tableLayout.addView(trTitle, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
- // body Row
- TableRow trBody = new TableRow(this);
- trBody.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- TextView tvBody = new TextView(this);
- tvBody.setText(smsBody);
- tvBody.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- trBody.addView(tvBody);
- tableLayout.addView(trBody, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
- }
- if (!cursor.isClosed()) {
- cursor.close();
- cursor = null;
- }
- smsHander.closeSMSDatabase();
- index = 0;
- }
- public class SmsHander {
- SQLiteDatabase db;
- Context context;
- public SmsHander(Context context) {
- this.context = context;
- }
- public void createSMSDatabase() {
- String sql = "create table if not exists sms("
- + "_id integer primary key autoincrement,"
- + "address varchar(255)," + "person varchar(255),"
- + "body varchar(1024)," + "date varchar(255),"
- + "type integer)";
- db = SQLiteDatabase.openOrCreateDatabase(context.getFilesDir().toString() + "/data.db3", null); // 创建数据库
- db.execSQL(sql);
- }
- // 获取手机短信
- private Cursor getSMSInPhone() {
- Uri SMS_CONTENT = Uri.parse("content://sms/");
- String[] projection = new String[] { "_id", "address", "person", "body", "date", "type" };
- Cursor cursor = context.getContentResolver().query(SMS_CONTENT, projection, null, null, "date desc"); // 获取手机短信
- while (cursor.moveToNext()) {
- System.out.println("--sms-- : " + cursor.getString(cursor.getColumnIndex("body")));
- }
- return cursor;
- }
- // 保存手机短信到 SQLite 数据库
- public void insertSMSToDatabase() {
- Long lastTime;
- Cursor dbCount = db.rawQuery("select count(*) from sms", null);
- dbCount.moveToFirst();
- if (dbCount.getInt(0) > 0) {
- Cursor dbcur = db.rawQuery("select * from sms order by date desc limit 1", null);
- dbcur.moveToFirst();
- lastTime = Long.parseLong(dbcur.getString(dbcur.getColumnIndex("date")));
- } else {
- lastTime = new Long(0);
- }
- dbCount.close();
- dbCount = null;
- Cursor cur = getSMSInPhone(); // 获取短信(游标)
- db.beginTransaction(); // 开始事务处理
- if (cur.moveToFirst()) {
- String address;
- String person;
- String body;
- String date;
- int type;
- int iAddress = cur.getColumnIndex("address");
- int iPerson = cur.getColumnIndex("person");
- int iBody = cur.getColumnIndex("body");
- int iDate = cur.getColumnIndex("date");
- int iType = cur.getColumnIndex("type");
- do {
- address = cur.getString(iAddress);
- person = cur.getString(iPerson);
- body = cur.getString(iBody);
- date = cur.getString(iDate);
- type = cur.getInt(iType);
- if (Long.parseLong(date) > lastTime) {
- String sql = "insert into sms values(null, ?, ?, ?, ?, ?)";
- Object[] bindArgs = new Object[] { address, person, body, date, type };
- db.execSQL(sql, bindArgs);
- } else {
- break;
- }
- } while (cur.moveToNext());
- cur.close();
- cur = null;
- db.setTransactionSuccessful(); // 设置事务处理成功,不设置会自动回滚不提交
- db.endTransaction(); // 结束事务处理
- }
- }
- // 获取 SQLite 数据库中的全部短信
- public Cursor querySMSFromDatabase() {
- String sql = "select * from sms order by date desc";
- return db.rawQuery(sql, null);
- }
- // 获取 SQLite 数据库中的最新 size 条短信
- public Cursor querySMSInDatabase(int size) {
- String sql;
- Cursor dbCount = db.rawQuery("select count(*) from sms", null);
- dbCount.moveToFirst();
- if (size < dbCount.getInt(0)) { // 不足 size 条短信,则取前 size 条
- sql = "select * from sms order by date desc limit " + size;
- } else {
- sql = "select * from sms order by date desc";
- }
- dbCount.close();
- dbCount = null;
- return db.rawQuery(sql, null);
- }
- // 获取 SQLite数据库的前 second秒短信
- public Cursor getSMSInDatabaseFrom(long second) {
- long time = System.currentTimeMillis() / 1000 - second;
- String sql = "select * from sms order by date desc where date > " + time;
- return db.rawQuery(sql, null);
- }
- // 关闭数据库
- public void closeSMSDatabase() {
- if (db != null && db.isOpen()) {
- db.close();
- db = null;
- }
- }
- }
- }
代码示例
Android Contacts(一)—— 读取联系人
Introduction To Android Contacts
Learn to work with the Android contacts database. Basic knowledge of accessing SQLite in Android along with using Cursors is expected. See the Android SQLite and Cursor Article for more information. Google changed the contacts database moving from 1.x to 2.0 versions of Android. This tutorial will be broken into 3 sections. First covering accessing contacts in Android 2.0. The second page will deal with accessing the contacts in Android 1.6 and before. Third we'll glue it all together with a class that abstracts specific classes for each version and a set of classes to manage the data from the contact records.
Contacts 读取代码:
- package com.homer.phone;
- import java.util.ArrayList;
- import java.util.HashMap;
- import android.app.Activity;
- import android.database.Cursor;
- import android.os.Bundle;
- import android.provider.ContactsContract;
- import android.provider.ContactsContract.CommonDataKinds.Phone;
- import android.widget.ListView;
- import android.widget.SimpleAdapter;
- public class phoneRead extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- showListView();
- }
- private void showListView(){
- ListView listView = new ListView(this);
- ArrayList<HashMap<String, String>> list = getPeopleInPhone2();
- SimpleAdapter adapter = new SimpleAdapter(
- this,
- list,
- android.R.layout.simple_list_item_2,
- new String[] {"peopleName", "phoneNum"},
- new int[]{android.R.id.text1, android.R.id.text2}
- );
- listView.setAdapter(adapter);
- setContentView(listView);
- }
- private ArrayList<HashMap<String, String>> getPeopleInPhone2(){
- ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
- Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); // 获取手机联系人
- while (cursor.moveToNext()) {
- HashMap<String, String> map = new HashMap<String, String>();
- int indexPeopleName = cursor.getColumnIndex(Phone.DISPLAY_NAME); // people name
- int indexPhoneNum = cursor.getColumnIndex(Phone.NUMBER); // phone number
- String strPeopleName = cursor.getString(indexPeopleName);
- String strPhoneNum = cursor.getString(indexPhoneNum);
- map.put("peopleName", strPeopleName);
- map.put("phoneNum", strPhoneNum);
- list.add(map);
- }
- if(!cursor.isClosed()){
- cursor.close();
- cursor = null;
- }
- return list;
- }
- }
AndroidManifest.xml 权限
记得在AndroidManifest.xml中加入android.permission.READ_CONTACTS这个permission
<uses-permission android:name="android.permission.READ_CONTACTS" />
运行结果:
代码示例
Android Contacts(二)—— SMS 短信 与 Contacts 联系人关联
Android 的SMS读取短信,可以获取发信人/收信人的手机号码(address),Contacts的联系人,可以过滤手机号码(address),因此SMS可以通过手机号码(address)关联到Contacts联系人
SMS - Contacts 关联代码
- // 通过address手机号关联Contacts联系人的显示名字
- private String getPeopleNameFromPerson(String address){
- if(address == null || address == ""){
- return "( no address )\n";
- }
- String strPerson = "null";
- String[] projection = new String[] {Phone.DISPLAY_NAME, Phone.NUMBER};
- Uri uri_Person = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, address); // address 手机号过滤
- Cursor cursor = getContentResolver().query(uri_Person, projection, null, null, null);
- if(cursor.moveToFirst()){
- int index_PeopleName = cursor.getColumnIndex(Phone.DISPLAY_NAME);
- String strPeopleName = cursor.getString(index_PeopleName);
- strPerson = strPeopleName;
- }
- cursor.close();
- return strPerson;
- }
- package com.homer.phone;
- import java.sql.Date;
- import java.text.SimpleDateFormat;
- import android.app.Activity;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteException;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.ContactsContract;
- import android.provider.ContactsContract.CommonDataKinds.Phone;
- import android.util.Log;
- import android.widget.ScrollView;
- import android.widget.TextView;
- public class phoneRead2 extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- TextView tv = new TextView(this);
- tv.setText(getSmsInPhone());
- ScrollView sv = new ScrollView(this);
- sv.addView(tv);
- setContentView(sv);
- }
- public String getSmsInPhone() {
- final String SMS_URI_ALL = "content://sms/";
- final String SMS_URI_INBOX = "content://sms/inbox";
- final String SMS_URI_SEND = "content://sms/sent";
- final String SMS_URI_DRAFT = "content://sms/draft";
- final String SMS_URI_OUTBOX = "content://sms/outbox";
- final String SMS_URI_FAILED = "content://sms/failed";
- final String SMS_URI_QUEUED = "content://sms/queued";
- StringBuilder smsBuilder = new StringBuilder();
- try {
- Uri uri = Uri.parse(SMS_URI_ALL);
- String[] projection = new String[] { "_id", "address", "person", "body", "date", "type" };
- Cursor cur = getContentResolver().query(uri, projection, null, null, "date desc"); // 获取手机内部短信
- if (cur.moveToFirst()) {
- int index_Address = cur.getColumnIndex("address");
- int index_Person = cur.getColumnIndex("person");
- int index_Body = cur.getColumnIndex("body");
- int index_Date = cur.getColumnIndex("date");
- int index_Type = cur.getColumnIndex("type");
- do {
- String strAddress = cur.getString(index_Address);
- int intPerson = cur.getInt(index_Person);
- String strbody = cur.getString(index_Body);
- long longDate = cur.getLong(index_Date);
- int intType = cur.getInt(index_Type);
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
- Date d = new Date(longDate);
- String strDate = dateFormat.format(d);
- String strType = "";
- if (intType == 1) {
- strType = "接收";
- } else if (intType == 2) {
- strType = "发送";
- } else {
- strType = "null";
- }
- String strAddress2 = getPeopleNameFromPerson(strAddress);
- smsBuilder.append("[ ");
- // smsBuilder.append(strAddress + ", ");
- smsBuilder.append(strAddress + " : " + strAddress2 + ", ");
- smsBuilder.append(intPerson + ", ");
- smsBuilder.append(strbody + ", ");
- smsBuilder.append(strDate + ", ");
- smsBuilder.append(strType);
- smsBuilder.append(" ]\n\n");
- } while (cur.moveToNext());
- if (!cur.isClosed()) {
- cur.close();
- cur = null;
- }
- } else {
- smsBuilder.append("no result!");
- } // end if
- smsBuilder.append("getSmsInPhone has executed!");
- } catch (SQLiteException ex) {
- Log.d("SQLiteException in getSmsInPhone", ex.getMessage());
- }
- return smsBuilder.toString();
- }
- // 通过address手机号关联Contacts联系人的显示名字
- private String getPeopleNameFromPerson(String address){
- if(address == null || address == ""){
- return "( no address )\n";
- }
- String strPerson = "null";
- String[] projection = new String[] {Phone.DISPLAY_NAME, Phone.NUMBER};
- Uri uri_Person = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, address); // address 手机号过滤
- Cursor cursor = getContentResolver().query(uri_Person, projection, null, null, null);
- if(cursor.moveToFirst()){
- int index_PeopleName = cursor.getColumnIndex(Phone.DISPLAY_NAME);
- String strPeopleName = cursor.getString(index_PeopleName);
- strPerson = strPeopleName;
- }
- cursor.close();
- return strPerson;
- }
- }
AndroidManifest.xml 权限
记得在AndroidManifest.xml中加入android.permission.READ_SMS和android.permission.READ_CONTACTS这两个permission
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
示例代码
参考推荐:
Android 之 Contacts 联系人读取