Android手机上监听短信有两种方式:
1、 接受系统的短信广播,操作短信内容。
优点:操作方便,适合简单的短信应用。
缺点:来信会在状态栏显示通知信息。
AndroidManifest.xml:
2、 应用观察者模式,监听短信数据库,操作短信内容。
优点:可以拦截来信在状态栏的显示通知,适合作短信拦截。
缺点:可以发展成MU,在后台悄悄的收/发短信。
实例如下:
SystemEventReceiver:收到开机启动OK的广播后,启动BootService服务;收到应用发送短信的INTENT后,调用系统接口发送短信
BootService:开启服务后,打开短信监听器
SMSObserver:数据观察者,监听短信数据库
SMSHandler:短信处理器
AndroidManifest.xml:
<
uses-permission
android:name
="android.permission.READ_SMS"
></
uses-permission
>
< uses-permission android:name ="android.permission.WRITE_SMS" ></ uses-permission >
<!-- Service -->
< service android:name =".BootService"
android:label ="@string/app_name" >
< intent-filter >
< action android:name ="org.anymobile.test.service.IMICHAT" />
< category android:name ="android.intent.category.DEFAULT" />
</ intent-filter >
</ service >
<!-- Receiver -->
< receiver android:name =".SystemEventReceiver" >
< intent-filter >
< action android:name ="android.intent.action.BOOT_COMPLETED" />
</ intent-filter >
</ receiver >
< uses-permission android:name ="android.permission.WRITE_SMS" ></ uses-permission >
<!-- Service -->
< service android:name =".BootService"
android:label ="@string/app_name" >
< intent-filter >
< action android:name ="org.anymobile.test.service.IMICHAT" />
< category android:name ="android.intent.category.DEFAULT" />
</ intent-filter >
</ service >
<!-- Receiver -->
< receiver android:name =".SystemEventReceiver" >
< intent-filter >
< action android:name ="android.intent.action.BOOT_COMPLETED" />
</ intent-filter >
</ receiver >
package
org.anymobile.demo.sms;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class SMSHandler extends Handler
{
public static final String TAG = " SMSHandler " ;
private Context mContext;
public SMSHandler(Context context)
{
super ();
this .mContext = context;
}
public void handleMessage(Message message)
{
Log.i(TAG, " handleMessage: " + message);
MessageItem item = (MessageItem) message.obj;
// delete the sms
Uri uri = ContentUris.withAppendedId(SMS.CONTENT_URI, item.getId());
mContext.getContentResolver().delete(uri, null , null );
Log.i(TAG, " delete sms item: " + item);
}
}
package org.anymobile.demo.sms;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class SMSObserver extends ContentObserver
{
public static final String TAG = " SMSObserver " ;
private static final String[] PROJECTION = new String[]
{
SMS._ID, // 0
SMS.TYPE, // 1
SMS.ADDRESS, // 2
SMS.BODY, // 3
SMS.DATE, // 4
SMS.THREAD_ID, // 5
SMS.READ, // 6
SMS.PROTOCOL // 7
};
private static final String SELECTION =
SMS._ID + " > %s " +
// " and " + SMS.PROTOCOL + " = null" +
// " or " + SMS.PROTOCOL + " = " + SMS.PROTOCOL_SMS + ")" +
" and ( " + SMS.TYPE + " = " + SMS.MESSAGE_TYPE_INBOX +
" or " + SMS.TYPE + " = " + SMS.MESSAGE_TYPE_SENT + " ) " ;
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_PROTOCOL = 7 ;
private static final int MAX_NUMS = 10 ;
private static int MAX_ID = 0 ;
private ContentResolver mResolver;
private Handler mHandler;
public SMSObserver(ContentResolver contentResolver, Handler handler)
{
super (handler);
this .mResolver = contentResolver;
this .mHandler = handler;
}
@Override
public void onChange( boolean selfChange)
{
Log.i(TAG, " onChange : " + selfChange + " ; " + MAX_ID + " ; " + SELECTION);
super .onChange(selfChange);
Cursor cursor = mResolver.query(SMS.CONTENT_URI, PROJECTION,
String.format(SELECTION, MAX_ID), null , null );
int id, type, protocol;
String phone, body;
Message message;
MessageItem item;
int iter = 0 ;
boolean hasDone = false ;
while (cursor.moveToNext())
{
id = cursor.getInt(COLUMN_INDEX_ID);
type = cursor.getInt(COLUMN_INDEX_TYPE);
phone = cursor.getString(COLUMN_INDEX_PHONE);
body = cursor.getString(COLUMN_INDEX_BODY);
protocol = cursor.getInt(COLUMN_INDEX_PROTOCOL);
if (hasDone)
{
MAX_ID = id;
break ;
}
if (protocol == SMS.PROTOCOL_SMS && body != null && body.startsWith(SMS.FILTER))
{
hasDone = true ;
item = new MessageItem();
item.setId(id);
item.setType(type);
item.setPhone(phone);
item.setBody(body);
item.setProtocol(protocol);
message = new Message();
message.obj = item;
mHandler.sendMessage(message);
}
else
{
if (id > MAX_ID) MAX_ID = id;
}
if (iter > MAX_NUMS) break ;
iter ++ ;
}
}
}
package org.anymobile.demo.sms;
import android.net.Uri;
import android.provider.BaseColumns;
public interface SMS extends BaseColumns
{
public static final Uri CONTENT_URI = Uri.parse( " content://sms " );
public static final String FILTER = " !imichat " ;
public static final String TYPE = " type " ;
public static final String THREAD_ID = " thread_id " ;
public static final String ADDRESS = " address " ;
public static final String PERSON_ID = " person " ;
public static final String DATE = " date " ;
public static final String READ = " read " ;
public static final String BODY = " body " ;
public static final String PROTOCOL = " protocol " ;
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
}
package org.anymobile.demo.sms;
public class MessageItem implements java.io.Serializable
{
private static final long serialVersionUID = 1L ;
private int id;
private int type;
private int protocol;
private String phone;
private String body;
public MessageItem()
{}
public int getId()
{
return id;
}
public void setId( int id)
{
this .id = id;
}
public int getType()
{
return type;
}
public void setType( int type)
{
this .type = type;
}
public int getProtocol()
{
return protocol;
}
public void setProtocol( int protocol)
{
this .protocol = protocol;
}
public String getPhone()
{
return phone;
}
public void setPhone(String phone)
{
this .phone = phone;
}
public String getBody()
{
return body;
}
public void setBody(String body)
{
this .body = body;
}
public String toString()
{
return
" id = " + id + " ; " +
" type = " + type + " ; " +
" protocol = " + protocol + " ; " +
" phone = " + phone + " ; " +
" body = " + body;
}
}
package org.anymobile.demo;
import android.app.Service;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;
import org.anymobile.demo.sms.SMS;
import org.anymobile.demo.sms.SMSHandler;
import org.anymobile.demo.sms.SMSObserver;
public class BootService extends Service
{
public static final String TAG = " BootService " ;
private ContentObserver mObserver;
private Handler mHandler = new Handler();
@Override
public void onCreate()
{
Log.i(TAG, " onCreate(). " );
super .onCreate();
addSMSObserver();
}
public void addSMSObserver()
{
Log.i(TAG, " add a SMS observer. " );
ContentResolver resolver = getContentResolver();
Handler handler = new SMSHandler( this );
mObserver = new SMSObserver(resolver, handler);
resolver.registerContentObserver(SMS.CONTENT_URI, true , mObserver);
}
@Override
public IBinder onBind(Intent intent)
{
return null ;
}
@Override
public void onDestroy()
{
Log.i(TAG, " onDestroy(). " );
this .getContentResolver().unregisterContentObserver(mObserver);
super .onDestroy();
Process.killProcess(Process.myPid());
System.exit( 0 );
}
}
package org.anymobile.demo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
// import android.os.Handler;
// import android.os.Message;
import android.telephony.gsm.SmsManager;
import org.anymobile.demo.sms.MessageItem;
public class SystemEventReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
{
context.startService( new Intent(Globals.IMICHAT_SERVICE));
}
else if (intent.getAction().equals(Globals.ACTION_SEND_SMS))
{
MessageItem mItem =
(MessageItem) intent.getSerializableExtra(Globals.EXTRA_SMS_DATA);
if (mItem != null && mItem.getPhone() != null && mItem.getBody() != null )
{
SmsManager.getDefault()
.sendTextMessage(mItem.getPhone(), null ,
mItem.getBody(), null , null );
// new Thread(mTasks).start();
}
}
}
}
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class SMSHandler extends Handler
{
public static final String TAG = " SMSHandler " ;
private Context mContext;
public SMSHandler(Context context)
{
super ();
this .mContext = context;
}
public void handleMessage(Message message)
{
Log.i(TAG, " handleMessage: " + message);
MessageItem item = (MessageItem) message.obj;
// delete the sms
Uri uri = ContentUris.withAppendedId(SMS.CONTENT_URI, item.getId());
mContext.getContentResolver().delete(uri, null , null );
Log.i(TAG, " delete sms item: " + item);
}
}
package org.anymobile.demo.sms;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class SMSObserver extends ContentObserver
{
public static final String TAG = " SMSObserver " ;
private static final String[] PROJECTION = new String[]
{
SMS._ID, // 0
SMS.TYPE, // 1
SMS.ADDRESS, // 2
SMS.BODY, // 3
SMS.DATE, // 4
SMS.THREAD_ID, // 5
SMS.READ, // 6
SMS.PROTOCOL // 7
};
private static final String SELECTION =
SMS._ID + " > %s " +
// " and " + SMS.PROTOCOL + " = null" +
// " or " + SMS.PROTOCOL + " = " + SMS.PROTOCOL_SMS + ")" +
" and ( " + SMS.TYPE + " = " + SMS.MESSAGE_TYPE_INBOX +
" or " + SMS.TYPE + " = " + SMS.MESSAGE_TYPE_SENT + " ) " ;
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_PROTOCOL = 7 ;
private static final int MAX_NUMS = 10 ;
private static int MAX_ID = 0 ;
private ContentResolver mResolver;
private Handler mHandler;
public SMSObserver(ContentResolver contentResolver, Handler handler)
{
super (handler);
this .mResolver = contentResolver;
this .mHandler = handler;
}
@Override
public void onChange( boolean selfChange)
{
Log.i(TAG, " onChange : " + selfChange + " ; " + MAX_ID + " ; " + SELECTION);
super .onChange(selfChange);
Cursor cursor = mResolver.query(SMS.CONTENT_URI, PROJECTION,
String.format(SELECTION, MAX_ID), null , null );
int id, type, protocol;
String phone, body;
Message message;
MessageItem item;
int iter = 0 ;
boolean hasDone = false ;
while (cursor.moveToNext())
{
id = cursor.getInt(COLUMN_INDEX_ID);
type = cursor.getInt(COLUMN_INDEX_TYPE);
phone = cursor.getString(COLUMN_INDEX_PHONE);
body = cursor.getString(COLUMN_INDEX_BODY);
protocol = cursor.getInt(COLUMN_INDEX_PROTOCOL);
if (hasDone)
{
MAX_ID = id;
break ;
}
if (protocol == SMS.PROTOCOL_SMS && body != null && body.startsWith(SMS.FILTER))
{
hasDone = true ;
item = new MessageItem();
item.setId(id);
item.setType(type);
item.setPhone(phone);
item.setBody(body);
item.setProtocol(protocol);
message = new Message();
message.obj = item;
mHandler.sendMessage(message);
}
else
{
if (id > MAX_ID) MAX_ID = id;
}
if (iter > MAX_NUMS) break ;
iter ++ ;
}
}
}
package org.anymobile.demo.sms;
import android.net.Uri;
import android.provider.BaseColumns;
public interface SMS extends BaseColumns
{
public static final Uri CONTENT_URI = Uri.parse( " content://sms " );
public static final String FILTER = " !imichat " ;
public static final String TYPE = " type " ;
public static final String THREAD_ID = " thread_id " ;
public static final String ADDRESS = " address " ;
public static final String PERSON_ID = " person " ;
public static final String DATE = " date " ;
public static final String READ = " read " ;
public static final String BODY = " body " ;
public static final String PROTOCOL = " protocol " ;
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
}
package org.anymobile.demo.sms;
public class MessageItem implements java.io.Serializable
{
private static final long serialVersionUID = 1L ;
private int id;
private int type;
private int protocol;
private String phone;
private String body;
public MessageItem()
{}
public int getId()
{
return id;
}
public void setId( int id)
{
this .id = id;
}
public int getType()
{
return type;
}
public void setType( int type)
{
this .type = type;
}
public int getProtocol()
{
return protocol;
}
public void setProtocol( int protocol)
{
this .protocol = protocol;
}
public String getPhone()
{
return phone;
}
public void setPhone(String phone)
{
this .phone = phone;
}
public String getBody()
{
return body;
}
public void setBody(String body)
{
this .body = body;
}
public String toString()
{
return
" id = " + id + " ; " +
" type = " + type + " ; " +
" protocol = " + protocol + " ; " +
" phone = " + phone + " ; " +
" body = " + body;
}
}
package org.anymobile.demo;
import android.app.Service;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;
import org.anymobile.demo.sms.SMS;
import org.anymobile.demo.sms.SMSHandler;
import org.anymobile.demo.sms.SMSObserver;
public class BootService extends Service
{
public static final String TAG = " BootService " ;
private ContentObserver mObserver;
private Handler mHandler = new Handler();
@Override
public void onCreate()
{
Log.i(TAG, " onCreate(). " );
super .onCreate();
addSMSObserver();
}
public void addSMSObserver()
{
Log.i(TAG, " add a SMS observer. " );
ContentResolver resolver = getContentResolver();
Handler handler = new SMSHandler( this );
mObserver = new SMSObserver(resolver, handler);
resolver.registerContentObserver(SMS.CONTENT_URI, true , mObserver);
}
@Override
public IBinder onBind(Intent intent)
{
return null ;
}
@Override
public void onDestroy()
{
Log.i(TAG, " onDestroy(). " );
this .getContentResolver().unregisterContentObserver(mObserver);
super .onDestroy();
Process.killProcess(Process.myPid());
System.exit( 0 );
}
}
package org.anymobile.demo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
// import android.os.Handler;
// import android.os.Message;
import android.telephony.gsm.SmsManager;
import org.anymobile.demo.sms.MessageItem;
public class SystemEventReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
{
context.startService( new Intent(Globals.IMICHAT_SERVICE));
}
else if (intent.getAction().equals(Globals.ACTION_SEND_SMS))
{
MessageItem mItem =
(MessageItem) intent.getSerializableExtra(Globals.EXTRA_SMS_DATA);
if (mItem != null && mItem.getPhone() != null && mItem.getBody() != null )
{
SmsManager.getDefault()
.sendTextMessage(mItem.getPhone(), null ,
mItem.getBody(), null , null );
// new Thread(mTasks).start();
}
}
}
}
<
uses-permission
android:name
="android.permission.SEND_SMS"
></
uses-permission
>
< uses-permission android:name ="android.permission.RECEIVE_SMS" ></ uses-permission >
<!-- Receiver -->
< receiver android:name =".sms.SMSReceiver" >
< intent-filter >
< action android:name ="android.provider.Telephony.SMS_RECEIVED" />
</ intent-filter >
</ receiver >
< uses-permission android:name ="android.permission.RECEIVE_SMS" ></ uses-permission >
<!-- Receiver -->
< receiver android:name =".sms.SMSReceiver" >
< intent-filter >
< action android:name ="android.provider.Telephony.SMS_RECEIVED" />
</ intent-filter >
</ receiver >
代码:
package
org.anymobile.demo.sms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.gsm.SmsMessage;
import android.util.Log;
public class SMSReceiver extends BroadcastReceiver
{
public static final String TAG = " ImiChatSMSReceiver " ;
// android.provider.Telephony.Sms.Intents
public static final String SMS_RECEIVED_ACTION = " android.provider.Telephony.SMS_RECEIVED " ;
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(SMS_RECEIVED_ACTION))
{
SmsMessage[] messages = getMessagesFromIntent(intent);
for (SmsMessage message : messages)
{
Log.i(TAG, message.getOriginatingAddress() + " : " +
message.getDisplayOriginatingAddress() + " : " +
message.getDisplayMessageBody() + " : " +
message.getTimestampMillis());
}
}
}
public final SmsMessage[] getMessagesFromIntent(Intent intent)
{
Object[] messages = (Object[]) intent.getSerializableExtra( " pdus " );
byte [][] pduObjs = new byte [messages.length][];
for ( int i = 0 ; i < messages.length; i ++ )
{
pduObjs[i] = ( byte []) messages[i];
}
byte [][] pdus = new byte [pduObjs.length][];
int pduCount = pdus.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
for ( int i = 0 ; i < pduCount; i ++ )
{
pdus[i] = pduObjs[i];
msgs[i] = SmsMessage.createFromPdu(pdus[i]);
}
return msgs;
}
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.gsm.SmsMessage;
import android.util.Log;
public class SMSReceiver extends BroadcastReceiver
{
public static final String TAG = " ImiChatSMSReceiver " ;
// android.provider.Telephony.Sms.Intents
public static final String SMS_RECEIVED_ACTION = " android.provider.Telephony.SMS_RECEIVED " ;
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(SMS_RECEIVED_ACTION))
{
SmsMessage[] messages = getMessagesFromIntent(intent);
for (SmsMessage message : messages)
{
Log.i(TAG, message.getOriginatingAddress() + " : " +
message.getDisplayOriginatingAddress() + " : " +
message.getDisplayMessageBody() + " : " +
message.getTimestampMillis());
}
}
}
public final SmsMessage[] getMessagesFromIntent(Intent intent)
{
Object[] messages = (Object[]) intent.getSerializableExtra( " pdus " );
byte [][] pduObjs = new byte [messages.length][];
for ( int i = 0 ; i < messages.length; i ++ )
{
pduObjs[i] = ( byte []) messages[i];
}
byte [][] pdus = new byte [pduObjs.length][];
int pduCount = pdus.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
for ( int i = 0 ; i < pduCount; i ++ )
{
pdus[i] = pduObjs[i];
msgs[i] = SmsMessage.createFromPdu(pdus[i]);
}
return msgs;
}
}
作者:
月亮#