您的位置:首页 > 移动开发 > Android开发

Android抢先截获短信(源码分析)

2014-03-14 09:45 323 查看
首先申明,此文非原创,我是在看了花花大神的《Android抢先截获短信》后有所感悟,特写一篇读后感。花花大神可谓了却了我淤积在我心头很久的一个技术难题(对我来说),以前在网上学习短信监控技术,当时一直未能实现短信监控,试了很多种方法也没有成功。后来一些大神说在android4.0系统要进行动态注册和设置优先级才能实现。以下援引花花大神的《Android抢先截获短信》内容。

之前在写通讯录应用时,将整体的代码写完后,自测时发现非常非常多的问题,其中一个非常重要严重的就是可以发出短信,但收不到任何的短信息,这搞的我好捉鸡啊!后来调试发现是由于没有收到短信的消息导致的,然后将自己手机中的QQ通讯录尝试着卸载掉,这时就可以收到了.

后来有时间了在网上查找相关资料,并且按照网上的理论编写了代码测试,解决了这个问题,在这里通过博客把解决的方法记录下来.

首先要知道广播分为无序,有序,sticky三种广播

无序广播应该最常用的,就是普通的广播,任何BroadcastReceiver都可以收到的广播,但是多个BroadcastReceiver在接受无序广播时也是有顺序前后之分的,也就是说每个BroadcastReceiver都会排队来接受无序广播,至于前后的顺序是怎么样的可以通过优先级等来设置.

有序广播也就是说最先收到有序广播的BroadcastReceiver在截获到这个广播后,可以选择继续下发此广播,或者中断此广播的发送,如果中断此有序广播的话,那么后面排队等待的BroadcastReceiver将接受不到此广播了,比如android系统在接受到短信息时所发送的广播"android.provider.Telephony.SMS_RECEIVED"就是有序广播

sticky广播由于暂时没有使用到,所以还不了解,等需要的时候再做研究

BroadcastReceiver广播接收器可以分为静态和动态的两种

静态接收器就是在AndroidManifest.xml注册的

动态接收器则是在代码中注册的

要了解很重要的一点:在相同优先级的情况下,动态接收器接受到广播的优先级会比静态接收器接受到广播的优先级高!

在了解上面的理论知识后,就开始实践下如何最先截获短信
首先在测试程序中静态注册广播接收器,并且将接受短信广播消息优先级设置为最高(一般第三方程序都会设置成最高)

AndroidManifest.xml

<receiver
android:name="huahua.interceptsms.MyReceiver">
<intent-filter android:priority="2147483647">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
MyReceiver.java

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可以先截获有序广播!

下面来证明这个理论
如何让自己最先注册到动态BroadcastReceiver呢?
我们可以在刚开机时,去创建一个Service,然后在Service中动态注册BroadcastReceiver.由于"android.intent.action.BOOT_COMPLETED"开机消息是个无序广播,那么每个应用都能收到,至于收到这个消息的顺序可以通过设置优先级.这里我在AndroidManifest.xml将开机广播优先级设置为最高,已保证第一个去注册动态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加入相应的权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.VIBRATE" />


也许还有疑问:如果都把自己程序的"android.intent.action.BOOT_COMPLETED"开机消息设置为优先级最高,那谁会最先收到开机消息呢?

我这里做了个小实验,在自己的通讯录程序中和测试程序中都同样的设置最高优先级开机广播,然后打印信息发现





通讯录中的Serivce先启动,测试程序的Service后启动,那么很显然通讯录程序是先接受到开机广播的,那么也将会优先接收到有序广播

"android.provider.Telephony.SMS_RECEIVED"

关于哪个应用先收到这个开机消息,网上有大牛说跟apk的文件名有所关系.由于某些原因我没有测试
还有关于更多详细解释广播优先级问题,有兴趣的朋友可以自己看看这篇博客,讲解的很清楚
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: