以前剛開始接觸android時對諸如短信攔截之類的功能很感興趣,網上很多文章都介紹了使用廣播接收android.provider.Telephony.SMS_RECEIVED的動作,從而接收到SMS信息,不過當時也不知道怎麼樣把這個廣播刪掉,從而實現一個類似短信黑名單的功能。後來在網上看到可以使用abortBroadcast來屏蔽廣播,我測試了一下,可行。
先上源碼:
AndroidManifest.xml的代碼:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.study.sms"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<receiver android:name=".smsReceiver">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.RECEIVE_SMS">
</uses-permission>
</manifest>
smsReceiver的代碼:
package com.study.sms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
public class smsReceiver extends BroadcastReceiver {
public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (SMS_RECEIVED_ACTION.equals(action)){
Bundle bundle = intent.getExtras();
if (bundle != null){
Object[] pdus = (Object[])bundle.get("pdus");
for (Object pdu : pdus){
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu);
String sender = message.getOriginatingAddress();
if ("5556".equals(sender)){
//屏蔽手機號爲5556的短信,這裏還可以時行一些處理,如把這個信息發送到第三人的手機等等。
abortBroadcast();
}
}
}
}
}
}
測試的效果圖:
使用5556給5554發送短信,5554無法收到。同時再起一個5558的avd給5554發送短信,一切正常。
之所以這個程序能實現屏蔽系統短信的功能,是因爲廣播有兩種不同的類型:普通廣播(normal broadcasts)和有序廣播(ordered broadcasts)。普通廣播是完全異步的,可以被所有的接收者接收到,並且接收者無法終止廣播的傳播。然而有序廣播是按照接收者聲明的優先級別,被接收者依次接收到。優先級別聲明在 intent-filter 元素的android:priority 屬性中,數越大優先級別越高,取值範圍:-1000到1000,優先級別也可以調用IntentFilter對象的setPriority()進行設置。有序廣播的接收者可以終止廣播Intent的傳播,廣播Intent的傳播一旦終止,後面的接收者就無法接收到廣播。上面的實例就是將smsReceiver的優先級設爲1000。
Context.sendBroadcast()
發送的是普通廣播,所有訂閱者都有機會獲得並進行處理。
Context.sendOrderedBroadcast()
發送的是有序廣播,系統會根據接收者聲明的優先級別按順序逐個執行接收者。
我查看了一下系統發送android.provider.Telephony.SMS_RECEIVED廣播的源碼SMSDispatcher.java(frameworks/base/telephony/java/com/android/internal/telephony),證實其發送的是有序廣播。
protected void dispatchPdus(byte[][] pdus) {
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
dispatch(intent, "android.permission.RECEIVE_SMS");
}
public void dispatch(Intent intent, String permission) { // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any // receivers time to take their own wake locks. mWakeLock.acquire(WAKE_LOCK_TIMEOUT); mContext.sendOrderedBroadcast(intent, permission, mResultReceiver, this, Activity.RESULT_OK, null, null); }