之前在写通讯录应用时,将整体的代码写完后,自测时发现非常非常多的问题,其中一个非常重要严重的就是可以发出短信,但收不到任何的短信息,这搞的我好捉鸡啊!后来调试发现是由于没有收到短信的消息导致的,然后将自己手机中的QQ通讯录尝试着卸载掉,这时就可以收到了.
后来有时间了在网上查找相关资料,并且按照网上的理论编写了代码测试,解决了这个问题,在这里通过博客把解决的方法记录下来.
首先要知道广播分为无序,有序,sticky三种广播
无序广播应该最常用的,就是普通的广播,任何BroadcastReceiver都可以收到的广播,但是多个BroadcastReceiver在接受无序广播时也是有顺序前后之分的,也就是说每个BroadcastReceiver都会排队来接受无序广播,至于前后的顺序是怎么样的可以通过优先级等来设置.
有序广播也就是说最先收到有序广播的BroadcastReceiver在截获到这个广播后,可以选择继续下发此广播,或者中断此广播的发送,如果中断此有序广播的话,那么后面排队等待的BroadcastReceiver将接受不到此广播了,比如android系统在接受到短信息时所发送的广播"android.provider.Telephony.SMS_RECEIVED"就是有序广播
sticky广播由于暂时没有使用到,所以还不了解,等需要的时候再做研究
BroadcastReceiver广播接收器可以分为静态和动态的两种
静态接收器就是在AndroidManifest.xml注册的
动态接收器则是在代码中注册的
要了解很重要的一点:在相同优先级的情况下,动态接收器接受到广播的优先级会比静态接收器接受到广播的优先级高!
在了解上面的理论知识后,就开始实践下如何最先截获短信
首先在测试程序中静态注册广播接收器,并且将接受短信广播消息优先级设置为最高(一般第三方程序都会设置成最高)
AndroidManifest.xml
package huahua.interceptsms;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Vibrator;
import android.util.Log;
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
Intent i =new Intent(context, MyService.class);
context.startService(i);
}
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Log.v("huahua", "MyReceiver收到短信发来的消息");
}
}
}
这样就可以了很简单.然后给10086发短信, 10086回复短信后发现QQ通讯录收到短信了,但是"MyReceiver收到短信发来的消息"Log消息却没有打印,说明没收到.
这时我们就要采用动态注册的方法了
MainActivity.java
package huahua.interceptsms;
import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
public class MainActivity extends Activity {
private SmsReceiver smsReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册接受短信消息
IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//设置优先级
localIntentFilter.setPriority(Integer.MAX_VALUE);
smsReceiver = new SmsReceiver();
registerReceiver(smsReceiver, localIntentFilter);
}
private class SmsReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Log.v("huahua", "MainActivity收到短信发来的消息");
}
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(smsReceiver);
}
}
在主Activity中,将广播的优先级同样设置为最高,然后启动程序,继续刚才的操作.发现还是被QQ通讯录收到短信了,Log信息"MainActivity收到短信发来的消息"也没打印出来
这是因为在相同优先级,同样都是动态注册的BroadcastReceiver在接受有序广播时,哪个BroadcastReceiver先注册,则哪个BroadcastReceiver可以先截获有序广播!
package huahua.interceptsms;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.Vibrator;
import android.util.Log;
import android.widget.Toast;
public class MyService extends Service{
private SmsReceiver smsReceiver;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
//动态注册接受短信消息
IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//设置优先级
localIntentFilter.setPriority(Integer.MAX_VALUE);
smsReceiver = new SmsReceiver();
registerReceiver(smsReceiver, localIntentFilter);
//这里震动一秒钟,用来感受下刚开机是否马上收到开机消息,并启动Service
Vibrator vib = (Vibrator)MyService.this.getSystemService(Service.VIBRATOR_SERVICE);
vib.vibrate(1000);
Log.v("huahua", "MyService启动"+ System.currentTimeMillis());
Toast.makeText(MyService.this, "MyService启动", Toast.LENGTH_SHORT).show();
}
private class SmsReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Log.v("huahua", "MyService收到短信发来的消息");
Vibrator vib = (Vibrator)MyService.this.getSystemService(Service.VIBRATOR_SERVICE);
vib.vibrate(1000);
//不将此短信消息下发给其他程序,如QQ通讯录等应用将收不到信息了
abortBroadcast();
}
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(smsReceiver);
}
}
好了,现在将测试程序安装到手机中再重启机器.会发现刚开机就会震动1秒钟并且有打印信息,表示已经动态注册了
BroadcastReceiver,然后接受短信.这时终于可以看到Log信息"MyService收到短信发来的消息"打印出来了,并且QQ通讯录收不到任何短信了
记得还要在AndroidManifest.xml加入相应的权限
也许还有疑问:如果都把自己程序的"android.intent.action.BOOT_COMPLETED"开机消息设置为优先级最高,那谁会最先收到开机消息呢?
我这里做了个小实验,在自己的通讯录程序中和测试程序中都同样的设置最高优先级开机广播,然后打印信息发现
通讯录中的Serivce先启动,测试程序的Service后启动,那么很显然通讯录程序是先接受到开机广播的,那么也将会优先接收到有序广播
"android.provider.Telephony.SMS_RECEIVED"
关于哪个应用先收到这个开机消息,网上有大牛说跟apk的文件名有所关系.由于某些原因我没有测试
还有关于更多详细解释广播优先级问题,有兴趣的朋友可以自己看看这篇博客,讲解的很清楚
android安全问题(四) 抢先开机启动 - 结果篇
之前有听说别人投诉10086说自己智能机收不到短信了,很有可能一个原因就是自己手机下载了病毒或者不友善软件,其软件使用此方法来让其他程序都收不到短信消息
建议大家也自己写代码测试一下,这样更能加深体会
源码下载地址
点击打开链接