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

   首先申明,此文非原创,我是在看了花花大神的《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的文件名有所关系.由于某些原因我没有测试

还有关于更多详细解释广播优先级问题,有兴趣的朋友可以自己看看这篇博客,讲解的很清楚


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值