系統中的廣播
在Android系統中,內建了很多Action產量,在觸發這些Action的時候,均會發布相應的Broadcast。一般而言,查看Android的API文檔中,關於Intent的說明即可找到對應Action的Broadcast,但是列舉的還不是很全,最好還是下載Android的原始碼,通過查看原始碼的方式查看需要攔截的Broadcast。
下面列舉一些常用的廣播:
- android.intent.action.TIME_SET:系統時間被修改。
- android.intent.action.DATE_CHANGED:系統日期被修改。
- android.intent.action.BOOT_COMPLETED:系統啟動完成。
- android.intent.action.BATTERY_CHANGED:裝置電量改變。
- android.intent.action.BATTERY_LOW:裝置電量低。
- android.intent.action.ACTION_POWER_CONNECTED:裝置串連電源。
- android.intent.action.ACTION_POWER_DISCONNECTED:裝置斷開電源。
- android.provider.Telephony.SMS_RECEIVED:系統收到簡訊。
- android.intent.action.NEW_OUTGOING_CALL:撥打到電話。
下面通過兩個例子,來講解如何在Android下,攔截系統Broadcast並對其進行處理。
通過關鍵字攔截簡訊
從上面列舉的一些動作會發布的Broadcast,可以找到,當系統接收到一條簡訊的時候,會發布一個“android.provider.Telephony.SMS_RECEIVED”的Broadcast,之前已經介紹過了,一般系統Broadcast都是有序廣播,如果不被高優先順序的BroadcastReceiver停止傳遞,會按照優先順序順序傳遞下去。
而在這個樣本中,通過監聽接收簡訊的廣播,當其內容有黑名單中的關鍵字的話,則阻止Broadcast繼續傳播,並使用Toast提示,否則正常提示簡訊資訊。
通過上一篇部落格瞭解到,onReceive方法的Intent參數包含了這條廣播傳遞的參數,對於簡訊資訊而言,需要擷取key為"pdus"的數組,取出數組中每一項,它的每一項代表了一個byte[]格式的簡訊,需要使用SmsMessage類解析簡訊內容。
當然,攔截簡訊的Broadcast侵犯了隱私,需要註冊接收簡訊的許可權:
1 <uses-permission android:name="android.permission.RECEIVE_SMS"/>
下面直接展示原始碼了,關鍵注釋已經寫的很清楚了,這裡不再累述:
MessageBroadcast.java:
1 package cn.bgxt.Broadcastdemo.MessageWarn; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import android.content.BroadcastReceiver; 6 import android.content.Context; 7 import android.content.Intent; 8 import android.os.Bundle; 9 import android.telephony.SmsMessage;10 import android.widget.Toast;11 12 public class MessageBroadcast extends BroadcastReceiver {13 // 在模擬器上,通過DDMS傳送簡訊會產生亂碼,所以使用拼音代替14 //在真機上不存在亂碼的問題15 private final String[] blackKeyWord = new String[] { "baoxian", "chuxiao",16 "jiangjia" };17 18 @Override19 public void onReceive(Context context, Intent intent) {20 // 判斷當前接收到的Broadcast是否是收到簡訊的action21 if (intent.getAction()22 .equals("android.provider.Telephony.SMS_RECEIVED")) {23 StringBuilder sb = new StringBuilder();24 // 擷取Broadcast傳遞的資料25 Bundle bundle = intent.getExtras();26 if (bundle != null) {27 Object[] pdus = (Object[]) bundle.get("pdus");28 for (Object p : pdus) {29 byte[] pud = (byte[]) p;30 // 聲明一個SmsMessage,用於解析簡訊的byte[]數組31 SmsMessage message = SmsMessage.createFromPdu(pud);32 boolean flag = false;33 for (String str : blackKeyWord) {34 if (message.getMessageBody().contains(str) ) {35 // 發現黑名單關鍵字,則標記為true36 flag = true;37 break;38 }39 }40 if (flag) {41 sb.append("寄件者:n");42 sb.append(message.getOriginatingAddress());43 sb.append("n發送時間:n");44 Date date = new Date(message.getTimestampMillis());45 SimpleDateFormat format = new SimpleDateFormat(46 "yyyy-MM-dd HH:mm:ss");47 sb.append(format.format(date));48 sb.append("n簡訊內容:n");49 sb.append(message.getMessageBody());50 51 Toast.makeText(context, sb.toString(),52 Toast.LENGTH_SHORT).show();53 // 如果存在黑名單關鍵字內容,停止Broadcast傳播54 abortBroadcast();55 }56 57 }58 }59 }60 61 }62 63 }
在AndroidManifest.xml中配置Receiver。
1 <receiver android:name="cn.bgxt.Broadcastdemo.MessageWarn.MessageBroadcast">2 <!-- 設定優先權,簡訊優先順序為0,大於0即可 -->3 <intent-filter android:priority="200">4 <action android:name="android.provider.Telephony.SMS_RECEIVED"/>5 </intent-filter> 6 </receiver>
效果展示,先發送一個包含黑名單中關鍵字的簡訊,再發送一個正常的簡訊。
IP撥號
再來看看IP撥號的樣本,在Android中,如果觸發撥打到電話的Action,則會發布一個"android.intent.action.NEW_OUTGOING_CALL"的Broadcast出來,只需要針對它進行攔截即可,然後在加上IP首碼,把處理過的號碼添加到資料傳遞給下一個Receiver。
處理接收撥打到電話的Broadcast,需要對Android增加許可權:
1 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
下面直接上代碼了,注釋寫的很清楚,這裡不再累述了。
IpCallPhone.java:
1 package cn.bgxt.Broadcastdemo.IpCall; 2 3 import android.content.BroadcastReceiver; 4 import android.content.Context; 5 import android.content.Intent; 6 7 public class IpCallPhone extends BroadcastReceiver { 8 private final String STARTS="17951"; 9 @Override10 public void onReceive(Context context, Intent intent) {11 // 擷取當前撥號的號碼12 String number=getResultData();13 // 此號碼沒有被加IP撥號的首碼14 if(!number.startsWith(STARTS)){15 // 設定加了IP號碼的號碼16 String newnumber=STARTS+number;17 // 把新號碼增加到返回結果資料中,用於傳遞給後面的Receiver18 setResultData(newnumber);19 } 20 }21 }
AndroidManifest.xml配置Receiver:
1 <receiver android:name="cn.bgxt.Broadcastdemo.IpCall.IpCallPhone">2 <intent-filter android:priority="200">3 <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>4 </intent-filter>5 </receiver>
效果展示: