• 【Android】短信应用——短信截获


    之前写过一篇关于短信截获的文章,通过注册 BroadcastReceive 来获取短信信息。
    但是我发现,当装了飞信,360手机安全卫士等同样有截获短信功能的程序后,我自己的程序就截获不到短信了;而且我还发现,当安装了飞信以后,Android 系统 的Notification 中就不会再有短信提示了。


    在 BroadcastReveive 中,有 abortBroadcast() 方法。该方法的作用是将短信拦截,并且阻止其继续传递。
    我们都知道,Android 广播,是组件之前传播数据的一种机制。(详情可参考:《Android系统中的广播(Broadcast)机制简要介绍和学习计划》)
    而短信就是一种广播,当有短信到来时,系统会发出广播,随后各接收器就会按照优先级一次接受,一级接收完,传给下一级;而当优先级高的接收器调用了 abortBroadcast() 方法后,广播就被阻拦了,那么优先级低于该级的接收器,则不会再收到信息。
    (当我第一次了解该方法时,忍不住对移动做出微微的鄙视 0.0)


    截获问题解决了,剩下的就是优先级的问题了。根据 Google 官方发布的文档,在 Manifest.xml 中修改 android:priority 参数可更改优先级,参数为-1000~1000,数值越高,优先级越高。但是当我把优先级设置到1000后,还是无法先于飞信、360,好奇怪……究竟是为什么呢?
    于是我开始针对剩下问题着手研究。


    开始的时候,我还怀疑过是否和程序安装的先后顺序有关,现在想想真的很好笑。翻阅网上的资料,代码内容和我这个版本都差不多,也许是别人没发现,或者没需求,没有人调研为什么飞信和360会先截获到短信。


    后来在偶然的机会,我听说 android:priority 属性的最大值不是1000,而是2147483647,这个数字怎么来的呢?熟悉数据结构的童鞋都知道,Integer 的最大值。针对这种说法,我保持怀疑的态度,因为人家官方文档说是1000最大啊~怀着试试看的心情,我将重新编译了工程源码,很遗憾,失败了。但是自己同时写两个程序并分别以 Integer 最大值和1000设置优先级,这次倒是成功了,验证了优先级最高为 Integer  最大值的说法。


    然后心想是不是和 Android 的广播机制有关,于是改变了研究方向。
    经过对广播机制的学习,对源码的研究,我发现动态注册要比静态注册的优先级高。于是我将短信截获做成了动态注册,果然成功了!


    最后,我将动态注册短信截获和开机自启动相结合,并把优先级设置为了 Integer最大值,成功制作出了优先级高于飞信、360的短信截获程序。


    遗憾的是,又有两个问题产生了。
    1.如果用“自启动管家”将短信截获程序的开机自启动禁止,那么咱们就截获不到短信了。现在就需要看看源码的写法,如何阻止别的软件对咱们程序的自启动屏蔽。
    2.移动和奇虎两个大厂家,做程序不应该会出现对代码理解不够透彻的情况。那么为什么我轻易就越过他们的优先级,因为没法查看源码, 所以原因不得而知。是因为程序安装的先后顺序?还是说他们把优先级设置成了Integer的最大值减1或1000?是为了方便别的程序去运用短信截获(这么无私?)?还是说真的是对 Android 系统理解不够?迷糊……




    好了,言归正传,吐槽了这么多,该看代码了。
    其实很简单,就是一个短信截获、Service 动态注册和开机自启动 Service 的结合体。
    本文中不会对代码做太为详细的介绍,想了解的同学可以分别看三篇文章。
    【Android】短信应用——短信信息实时获取
    【Android】动态注册广播接收器
    【Android】开机自启动Service



    创建一个 Service 类,在该类的 onCreate() 方法中动态注册一个内部类,该类继承 BroadcastReceive。

    1. IntentFilter filter = new IntentFilter();  
    2. filter.addAction("android.provider.Telephony.SMS_RECEIVED");  
    3. filter.setPriority(Integer.MAX_VALUE);  
    4. registerReceiver(new SmsReceiver(), filter);  
    addAction() 定义广播接收器类别——短信接收器。
    setPriority() 方法设置该广播接收器优先级,Integer 最大值为最高优先级。


    在 Service 中添加一个继承 BroadcastReceive 的内部类,在该类中添加短信截获方法。

    1. Bundle bundle = intent.getExtras();  
    2.         if (bundle != null) {  
    3.                     Object[] pdusObjects = (Object[]) bundle.get("pdus");  
    4.                     SmsMessage[] messages = new SmsMessage[pdusObjects.length];  
    5.                     for (int i = 0; i < pdusObjects.length; i++) {  
    6.                         messages[i] = SmsMessage  
    7.                                 .createFromPdu((byte[]) pdusObjects[i]);  
    8.                     }  
    9.                     for (SmsMessage message : messages) {  
    10.                         SMSAddress.append(message  
    11.                                 .getDisplayOriginatingAddress());  
    12.                         SMSContent.append(message.getDisplayMessageBody());  
    13.                         System.out.println("来信号码:" + SMSAddress + " 短信内容:"  
    14.                                 + SMSContent);  
    15.                     }  
    16.                 }  

    这样我们就能在 Logcat 中看到截获的内容了。


    Service 同 Activity,需要在 Manifest.xml 中声明。

    1. <service android:name="cn.etzmico.smsreceived.SMSReceivedService" >  
    2.          <intent-filter >  
    3.              <action android:name="cn.etzmico.service.SMSReceived" />  
    4.   
    5.              <category android:name="android.intent.category.default" />  
    6.          </intent-filter>  
    7.      </service>  
    "cn.etzmico.service.SMSReceived"为 Service 的“标签”。


    同时需要添加权限。

    1. <uses-permission android:name="android.permission.RECEIVE_SMS" />  


    我们另外需要新建一个继承于 BroadcastReceiver 的类,区别于之前的,这个 Reveiver 是静态注册的,用于开机自启动。
    在 onReceive() 中调用 Service。

    1. ctx.startService(new Intent("cn.etzmico.SMSReceived"));  
    intent中的参数为要启动的 Service 的“标签”。

    由于是静态注册,因此自启动类也需要在 Manifest.xml 中声明。

    1. <receiver android:name=".BootReceiver" >  
    2.            <intent-filter android:priority="2147483647" >  
    3.                <action android:name="android.intent.action.BOOT_COMPLETED" />  
    4.   
    5.                <category android:name="android.intent.category.HOME" />  
    6.            </intent-filter>  
    7.        </receiver>  
    我们在这里也设置下优先级,方便短信截获。值同样为 Integer 最大值,不过需要用具体数值去表示。

    最后别忘了权限。

    1. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />  


    好了,全部内容就是这些。
    只要不被组织开机自启动,我们的程序是一定会截获到短信的。

    至于文章中提到的疑惑,我还是想知道原因。希望了解的童鞋们留言给我~谢谢!


    转自:http://blog.csdn.net/Etzmico/article/details/7317892


    ----------------------------------------------------------------

    adb shell发送短信

    1. adb shell am start -a android.intent.action.SENDTO -d sms:10086(发送目的号码) --es sms_body "hello"(短信内容) --ez exit_on_sent true  
    2.   
    3. adb shell input keyevent 22   // 发送按键  获取焦点
    4. adb shell input keyevent 66   // 点击按键

  • 相关阅读:
    212-@Slf4j注解起到了什么作用?
    212-如何实现定时器扫描?
    211-redis单线程问题?
    211-Feign中的@RequestParm与@RequestBody注解的使用
    210-java加载类的时候,发生了什么了呢?
    209-thymeleaf简单使用
    JS自定义 Map
    java Main方法 获取 maven 的resource 下的xml文件
    springboot+thymeleaf 访问静态资源解决(static)
    两个list 合并后去除掉重复removeAll()的,然后再随机获取最后list中的 几个值
  • 原文地址:https://www.cnblogs.com/xieyuan/p/3787264.html
Copyright © 2020-2023  润新知