1. 基于Broadcast接受短信
1.1 原理
Android收到短信后系统会发送一个android.provider.Telephony.SMS_RECEIVED广播。把它放在Bundle(intent.Extras)中,Bundle可以理解为一个Map,短信采用"pdus"作为键,pdus应该是protocol description units的简写,也就是一组短信。Android不是一接收到短信就立刻发出广播的,他会有一定的延迟,所以就有可能会有多条短信,所以才会用数组来存放。
1.2 实现方法一
原理已经清楚,那么实现是通过重写BroadcastReceiver.onReceive(Context context, Intent intent)函数,关键代码如下:
Bundle bundle = intent.getExtras(); Object messages[] = (Object[]) bundle.get("pdus"); SmsMessage smsMessage[] = new SmsMessage[messages.length]; smsMessage[n] = SmsMessage.createFromPdu((byte[]) messages[n]); sender = smsMessage[n].getOriginatingAddress();// 获取短信的发送者 content = smsMessage[n].getMessageBody();// 获取短信的内容
完整实现为:
public class EventReceiver extends BroadcastReceiver { private Context mContext; private static final String TAG = "REC_TEST"; @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); SmsMessage[] smsMessages = null; Object[] pdus = null; if (bundle != null) { pdus = (Object[]) bundle.get("pdus"); } if (pdus !=null){ smsMessages = new SmsMessage[pdus.length]; String sender = null; String content = null; for (int i=0; i<pdus.length; i++){ smsMessages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]); sender = smsMessages[i].getOriginatingAddress(); content = smsMessages[i].getMessageBody(); Log.v(TAG, "SMS:"+sender+content); //ShowToast(sender + " 短信", R.drawable.ic_dialog_email); Toast.makeText(context, sender + "," + content, Toast.LENGTH_LONG).show(); }//for smsMessages }//if pdus } }
1.3 注册Receiver
1.3.1 静态注册
在AndroidManifest.xml的application里面定义receiver并设置要接收的action。
receiver需要放在application标签之中
<receiver android:name=".EventReceiver"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
1.3.2 动态注册
在activity里面调用函数来注册,和静态的内容差不多。一个形参是receiver,另一个是IntentFilter,其中里面是要接收的action。
private BroadcastReceiver receiver; @Override protected void onStart() { super.onStart(); receiver = new CallReceiver(); registerReceiver(receiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED")); } @Override protected void onStop() { unregisterReceiver(receiver); super.onStop(); }
2. 基于ContentObserver监听短信
2.1 原理
原理是通过监听短信数据库,操作短信内容。
下面是文献[3]对ContentObserver的介绍:
“ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。触发器分为表触发器、行触发器,相应地ContentObserver也分为“表“ContentObserver、“行”ContentObserver,当然这是与它所监听的Uri MIME Type有关的。”
先不深究更加底层的内容,从表面上我们可以知道ContentObserver可以获取Uri引起的数据库的变化,短信的Uri为:
发送短信:content://sms/outbox
接收短信:content://sms/inbox
知道Uri后我们就可以获取到短信的内容了。
2.2 实现
实现的方法就是重载ContentObserver.onChange()方法即可
具体代码如下:
private class SmsObserver extends ContentObserver { public SmsObserver(Handler handler) { super(handler); // TODO Auto-generated constructor stub } @Override public void onChange(boolean selfChange) { // TODO Auto-generated method stub //查询发送箱中的短信(正在发送中的短信放在发送箱中) Cursor cursor = getContentResolver().query( Uri.parse("content://sms/outbox"), null, null, null, null); while(cursor.moveToNext()){ StringBuilder sb = new StringBuilder(); sb.append("address="+cursor.getString(cursor.getColumnIndex("address"))); sb.append(", body="+cursor.getString(cursor.getColumnIndex("body"))); sb.append(", date="+cursor.getString(cursor.getColumnIndex("date"))); Log.i("Observer", sb.toString()); } cursor.close(); super.onChange(selfChange); } }
2.3 注册Listener
getContentResolver().registerContentObserver( Uri.parse("content://sms"), true, new SmsObserver(new Handler()));
3. 设置权限
要接收某些action,需要在AndroidManifest.xml里面添加相应的权限。
<uses-permission android:name="android.permission.RECEIVE_SMS" />
4. 参考文献
[1] BroadCastReceiver 简介 http://www.cnblogs.com/alwaysyouare/archive/2011/11/17/2252397.html
[2] Android电话、短信监听 http://blog.163.com/[email protected]/blog/static/1032422412013112343930567/
[3] Android中内容观察者的使用---- ContentObserver类详解 http://www.cnblogs.com/slider/archive/2012/02/14/2351702.html