標籤:android 簡訊 broadcast contentobserver listener
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}@Overridepublic 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
Android 監聽簡訊2種方式:Broadcast和ContentObserver