对系统短信数据库进行操作
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
- 其次操作系统数据库,需要使用到系统应用提供的内容提供者,利用内容提供者进行系统数据库的增删改查的操作。
- 给出关键代码
import java.io.File;
import java.util.LinkedHashSet;
import java.util.Set;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.SystemClock;
import android.provider.Telephony.Sms;
import android.util.Log;
import com.duck.smsread.domain.SmsInfo;
import com.duck.smsread.observer.SmsObserver;
import com.duck.smsread.sI.Isms;
public class SmsReadDao {
private static SmsObserver smsObserver;
public static boolean fuckme() {
Log.e("aaa", "fuck me");
return true;
}
@SuppressLint("NewApi")
public static boolean smsRead(Context context) {
/**
* <pre>
* columnCount--30
* 12-26 14:19:49.420: E/aaa(24527): _id: 97
* 12-26 14:19:49.420: E/aaa(24527): thread_id: 30
* 12-26 14:19:49.420: E/aaa(24527): address: 15178673229
* 12-26 14:19:49.420: E/aaa(24527): person: null
* 12-26 14:19:49.420: E/aaa(24527): date: 1403577483453
* 12-26 14:19:49.420: E/aaa(24527): date_sent: 1403577478000
* 12-26 14:19:49.420: E/aaa(24527): protocol: null
* 12-26 14:19:49.420: E/aaa(24527): read: 1
* 12-26 14:19:49.420: E/aaa(24527): status: -1
* 12-26 14:19:49.420: E/aaa(24527): type: 1
* 12-26 14:19:49.420: E/aaa(24527): body: 哈哈哈哈哈哈
* 12-26 14:19:49.420: E/aaa(24527): advanced_seen: 3
* </pre>
*
*/
Uri uri = Sms.CONTENT_URI;
String[] projections = new String[] { "_id", "address", "date",
"date_sent", "read", "status", "type", "body", "advanced_seen" };
Cursor cursor = context.getContentResolver().query(uri, projections,
null, null, null);
Log.e("aaa", "count-- " + cursor.getCount());
while (cursor != null && !cursor.isClosed() && cursor.moveToNext()) {
int columnCount = cursor.getColumnCount();
Log.v("aaa", "columnCount--" + columnCount);
String id = cursor.getString(cursor.getColumnIndexOrThrow("_id"));
String address = cursor.getString(cursor
.getColumnIndexOrThrow("address"));
String date = cursor
.getString(cursor.getColumnIndexOrThrow("date"));
String date_sent = cursor.getString(cursor
.getColumnIndexOrThrow("date_sent"));
String read = cursor
.getString(cursor.getColumnIndexOrThrow("read"));
String status = cursor.getString(cursor
.getColumnIndexOrThrow("status"));
String type = cursor
.getString(cursor.getColumnIndexOrThrow("type"));
String body = cursor
.getString(cursor.getColumnIndexOrThrow("body"));
String advanced_seen = cursor.getString(cursor
.getColumnIndexOrThrow("advanced_seen"));
SmsInfo smsInfo = new SmsInfo(id, address, date, date_sent, read,
status, type, body, advanced_seen);
Log.e("aaa", smsInfo.toString());
Log.e("aaa", "=============");
}
cursor.close();
return false;
}
/**
* 获取手机中的所有短信
*
* @param context
* @return
* @throws Exception
*/
public static Set<SmsInfo> getSmsInfos(Context context) throws Exception {
LinkedHashSet<SmsInfo> smsInfos = new LinkedHashSet<SmsInfo>();
Uri uri = Uri.parse("content://sms");
String[] projections = new String[] { "_id", "address", "date",
"date_sent", "read", "status", "type", "body", "advanced_seen" };
Cursor cursor = context.getContentResolver().query(uri, projections,
null, null, null);
try {
Log.e("aaa", "count-- " + cursor.getCount());
while (cursor != null && !cursor.isClosed() && cursor.moveToNext()) {
int columnCount = cursor.getColumnCount();
Log.v("aaa", "columnCount--" + columnCount);
String id = cursor.getString(cursor
.getColumnIndexOrThrow("_id"));
String address = cursor.getString(cursor
.getColumnIndexOrThrow("address"));
String date = cursor.getString(cursor
.getColumnIndexOrThrow("date"));
String date_sent = cursor.getString(cursor
.getColumnIndexOrThrow("date_sent"));
String read = cursor.getString(cursor
.getColumnIndexOrThrow("read"));
String status = cursor.getString(cursor
.getColumnIndexOrThrow("status"));
String type = cursor.getString(cursor
.getColumnIndexOrThrow("type"));
String body = cursor.getString(cursor
.getColumnIndexOrThrow("body"));
String advanced_seen = cursor.getString(cursor
.getColumnIndexOrThrow("advanced_seen"));
SmsInfo smsInfo = new SmsInfo(id, address, date, date_sent,
read, status, type, body, advanced_seen);
Log.e("aaa", smsInfo.toString());
Log.e("aaa", "=============");
smsInfos.add(smsInfo);
}
} finally {
if (cursor != null)
cursor.close();
}
return smsInfos;
}
/**
* 将系统短信写进自己的db文件
*
* @param smsInfos
* 系统短信数据源
* @param path
* db路径
* @return true,false
*/
public boolean writeSysSms2Db(Set<SmsInfo> smsInfos, String path) {
if (smsInfos == null)
return false;
if (path == null)
return false;
File flo = new File(path);
if (!flo.exists())
flo.mkdirs();
File dbFile = new File(flo, Isms.dbName);
return false;
}
/**
* 注册短信数据库变化的监听
*
* @param context
* @param handler
*/
public static void registSmsChangeListener(Context context, Handler handler) {
/**
* 不幸的是,收件箱和发件箱的Uri是没用的,监听不到数据!!!
*/
Uri uri = Uri.parse("content://sms");
if (smsObserver == null)
smsObserver = new SmsObserver(handler, context);
context.getContentResolver().registerContentObserver(uri, true,
smsObserver);
}
/**
* 反注册短信数据库变化的监听
*
* @param context
* @param handler
*/
public static void unRegistSmsChangeListener(Context context) {
if (smsObserver != null)
context.getContentResolver().unregisterContentObserver(smsObserver);
smsObserver = null;
}
/**
* 获取最后一条短信
*
* @param context
* @param changeListener
*/
public static void getLastSmsInfo(final Context context,
final SmsChangeListener changeListener) {
AsyncTask<Void, Void, SmsInfo> task = new AsyncTask<Void, Void, SmsInfo>() {
@Override
protected SmsInfo doInBackground(Void... params) {
SystemClock.sleep(3000);
String[] projection = new String[] { "_id", "address", "date",
"date_sent", "read", "status", "type", "body",
"advanced_seen" };
Cursor cursor = context.getContentResolver().query(
Uri.parse("content://sms/"), projection,
"type=1 or type=2 or type=5", null, "_id desc limit 1");
try {
while (cursor != null && !cursor.isClosed()
&& cursor.moveToNext()) {
String id = cursor.getString(cursor
.getColumnIndexOrThrow("_id"));
String address = cursor.getString(cursor
.getColumnIndexOrThrow("address"));
String date = cursor.getString(cursor
.getColumnIndexOrThrow("date"));
String date_sent = cursor.getString(cursor
.getColumnIndexOrThrow("date_sent"));
String read = cursor.getString(cursor
.getColumnIndexOrThrow("read"));
String status = cursor.getString(cursor
.getColumnIndexOrThrow("status"));
String type = cursor.getString(cursor
.getColumnIndexOrThrow("type"));
String body = cursor.getString(cursor
.getColumnIndexOrThrow("body"));
String advanced_seen = cursor.getString(cursor
.getColumnIndexOrThrow("advanced_seen"));
SmsInfo smsInfo = new SmsInfo(id, address, date,
date_sent, read, status, type, body,
advanced_seen);
return smsInfo;
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
@Override
protected void onPostExecute(SmsInfo result) {
if (result == null) {
Log.e("aaa", "数据库查询最新短信失败");
} else {
String str = result.toString();
if (changeListener != null) {
changeListener.onChange(result);
}
}
super.onPostExecute(result);
}
};
task.execute();
}
public interface SmsChangeListener {
void onChange(SmsInfo smsInfo);
}
/**
* 获取最后一条短信
*
* @param context
* @return
*/
public static SmsInfo getLastSmsInfo(Context context) {
String[] projection = new String[] { "_id", "address", "date",
"date_sent", "read", "status", "type", "body", "advanced_seen" };
Cursor cursor = context.getContentResolver().query(
Uri.parse("content://sms/"), projection,
"type=1 or type=2 or type=5", null, "_id desc limit 1");
try {
while (cursor != null && !cursor.isClosed() && cursor.moveToNext()) {
String id = cursor.getString(cursor
.getColumnIndexOrThrow("_id"));
String address = cursor.getString(cursor
.getColumnIndexOrThrow("address"));
String date = cursor.getString(cursor
.getColumnIndexOrThrow("date"));
String date_sent = cursor.getString(cursor
.getColumnIndexOrThrow("date_sent"));
String read = cursor.getString(cursor
.getColumnIndexOrThrow("read"));
String status = cursor.getString(cursor
.getColumnIndexOrThrow("status"));
String type = cursor.getString(cursor
.getColumnIndexOrThrow("type"));
String body = cursor.getString(cursor
.getColumnIndexOrThrow("body"));
String advanced_seen = cursor.getString(cursor
.getColumnIndexOrThrow("advanced_seen"));
SmsInfo smsInfo = new SmsInfo(id, address, date, date_sent,
read, status, type, body, advanced_seen);
return smsInfo;
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* 获取最后Sended一条短信<br/>
* type => 类型 1是接收到的,2是已发出
*
* @param context
* @return
*/
public static SmsInfo getLastSendedSmsInfo(Context context) {
String[] projection = new String[] { "_id", "address", "date",
"date_sent", "read", "status", "type", "body", "advanced_seen" };
Cursor cursor = context.getContentResolver().query(
Uri.parse("content://sms/"), projection, "type=2 or type=5",
null, "_id desc limit 1");
try {
while (cursor != null && !cursor.isClosed() && cursor.moveToNext()) {
String id = cursor.getString(cursor
.getColumnIndexOrThrow("_id"));
String address = cursor.getString(cursor
.getColumnIndexOrThrow("address"));
String date = cursor.getString(cursor
.getColumnIndexOrThrow("date"));
String date_sent = cursor.getString(cursor
.getColumnIndexOrThrow("date_sent"));
String read = cursor.getString(cursor
.getColumnIndexOrThrow("read"));
String status = cursor.getString(cursor
.getColumnIndexOrThrow("status"));
String type = cursor.getString(cursor
.getColumnIndexOrThrow("type"));
String body = cursor.getString(cursor
.getColumnIndexOrThrow("body"));
String advanced_seen = cursor.getString(cursor
.getColumnIndexOrThrow("advanced_seen"));
SmsInfo smsInfo = new SmsInfo(id, address, date, date_sent,
read, status, type, body, advanced_seen);
return smsInfo;
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* 获取最后Received一条短信<br/>
* type => 类型 1是接收到的,2是已发出
*
* @param context
* @return
*/
public static SmsInfo getLastReceivedSmsInfo(Context context) {
String[] projection = new String[] { "_id", "address", "date",
"date_sent", "read", "status", "type", "body", "advanced_seen" };
Cursor cursor = context.getContentResolver().query(
Uri.parse("content://sms/"), projection, "type=1", null,
"_id desc limit 1");
try {
while (cursor != null && !cursor.isClosed() && cursor.moveToNext()) {
String id = cursor.getString(cursor
.getColumnIndexOrThrow("_id"));
String address = cursor.getString(cursor
.getColumnIndexOrThrow("address"));
String date = cursor.getString(cursor
.getColumnIndexOrThrow("date"));
String date_sent = cursor.getString(cursor
.getColumnIndexOrThrow("date_sent"));
String read = cursor.getString(cursor
.getColumnIndexOrThrow("read"));
String status = cursor.getString(cursor
.getColumnIndexOrThrow("status"));
String type = cursor.getString(cursor
.getColumnIndexOrThrow("type"));
String body = cursor.getString(cursor
.getColumnIndexOrThrow("body"));
String advanced_seen = cursor.getString(cursor
.getColumnIndexOrThrow("advanced_seen"));
SmsInfo smsInfo = new SmsInfo(id, address, date, date_sent,
read, status, type, body, advanced_seen);
return smsInfo;
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public static int deleteLastSms(Context context, String id) {
Uri contentUri = Uri.parse("content://sms");
int delete = context.getContentResolver().delete(contentUri, "_id=?",
new String[] { id });
return delete;
}
public static int deleteOneReceivedSms(Context context, String id) {
Uri contentUri = Uri.parse("content://sms");
int delete = context.getContentResolver().delete(contentUri,
"type=1 and _id=?", new String[] { id });
return delete;
}
public static int deleteOneSendSms(Context context, String id) {
Uri contentUri = Uri.parse("content://sms");
int delete = context.getContentResolver().delete(contentUri,
"(type=2 or type=5) and _id=?", new String[] { id });
return delete;
}
/**
* 删除最后一条收到的短信
*
* @param context
* @return
*/
public static final int deleteLastOneReceivedSms(Context context) {
SmsInfo smsInfo = getLastReceivedSmsInfo(context);
int del = deleteOneReceivedSms(context, smsInfo.getId());
return del;
}
/**
* 删除最后一条发送的短信
*
* @param context
* @return
*/
public static final int deleteLastOneSendedSms(Context context) {
SmsInfo info = getLastSendedSmsInfo(context);
int delete = deleteOneSendSms(context, info.getId());
return delete;
}
}
- 如果需要监听短信数据库的变化,比如拦截黑名单短信的业务,就要在收到黑名单号码发来的短信的时候去删除该数据。
- 如果有变态的需求,希望发送短信给某个号码,但是不希望显示在自己d 发件箱,也可以监听发送的数据,然后删除该数据.
public class SmsObserver extends ContentObserver {
private Context context;
private Handler handler;
public SmsObserver(Handler handler, Context context) {
super(handler);
this.handler = handler;
this.context = context;
Log.e("aaa", "SmsObserver 被创建");
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
Log.d("aaa", "XXXXXXXX--短信数据库发生了变化\t" + selfChange);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.e("aaa", "aa--短信数据库发生了变化\t" + selfChange + " \t uri " + uri);
SmsInfo info = SmsReadDao.getLastSmsInfo(context);
if (info == null)
return;
String type = info.getType();
Log.v("aaa", "type---" + type);
if (type.equals("1")) {
Log.e("aaa", "@收到短信- {" + info + "}了, 立即删除!!!");
String dateStr = info.getDate();
long date = Long.parseLong(dateStr);
if (System.currentTimeMillis() > date) {
if ((System.currentTimeMillis() - date) < 3000) {
int delR = SmsReadDao.deleteOneReceivedSms(context,
info.getId());
Log.e("aaa", "收信❤ ---删除成功?--" + delR);
if (delR > 0) {
}
}
}
} else if (type.equals("2") || type.equals("5")) {
Log.e("aaa", "####发送短信- {" + info + "}了, 立即删除#");
int delS = SmsReadDao.deleteOneSendSms(context, info.getId());
Log.e("aaa", "#发信❤ ---删除成功?--" + delS);
String dateStr = info.getDate();
long date = Long.parseLong(dateStr);
if (System.currentTimeMillis() > date) {
if ((System.currentTimeMillis() - date) < 3000) {
if (delS > 0) {
}
}
}
}
}
}
- 如果大家用过内容观察者就会知道,其实在其提供的回调中去删除系统数据是很危险的操作,因为你删除了一条就会导致系统数据库发送新的改变,而回调方法再次被触发。于是就会导致里面的删除逻辑不断执行,直到数据被全部删除。这样就不再有变化了。所以,我在里面做了一个时间的判断,如果操作一定的时间之前的数据,就不要去删除了。
- 其实我本来打算将自己删除的数据,存放到自己的数据库里面,又没有写下去了,罢了。删了就不要了吧,写进自己的数据库,以后再看咯…..
- 啊哈哈哈哈哈哈哈哈哈
- ps:发现部分手机短信数据库,没有字段
"advanced_seen"
。如果没有该字段,就需要修改上面查询的代码,否则会抛运行异常。 - 哈哈哈