Android-垃圾短信拦截

垃圾短信拦截

在Android4.4之前,对于垃圾短信的拦截,可以通过自定义短信广播接收器,对系统的短信广播(属于有序广播)android.provider.Telephony.SMS_RECEIVED进行接听,并将其设置为最高接听优先级(1000),然后对在黑名单中的用户发送过来的短信进行拦截(利用 abortBroadcast()函数截断广播)。具体实现方式如下:

1、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">
      
    <!--声明读取短信的权限-->
    <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>

    <application 
       android:icon="@drawable/icon" 
       android:label="@string/app_name">

      <!--静态注册自定义的接收短信的广播接收器,并设置其接收系统短信广播的优先级为最高级-1000-->
      <receiver android:name=".smsReceiver">
          <intent-filter android:priority="1000">
              <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
          </intent-filter>
       </receiver>

 </application>
 
</manifest> 

2、smsReceiver的代码:

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();
            }
      }
  }
}

短信机制变更

在google查阅后得知:Android为了防止第三方软件拦截短信和偷发短信吸费,在android4.4之后,只有默认的短信应用才有权限操作短信数据库。

Android4.4 之前

  1. 新接收短信广播 SMS_RECEIVED_ACTION为有序广播。任意应用可接到该广播并中止其继续传播。中止后优先级低的短信应用和系统短信服务将不知道新短信到达,从而不写进数据库。这样就做到了拦截(其实很多恶意应用也这么干)。
  2. 任意应用都可以操作短信数据库,包括新建(含伪造收件箱和发件箱短信)、修改(含篡改历史短信)、删除。
  3. 任意应用都可以发送短信和彩信,但默认不写进短信数据库,除非应用手动存入,否则用户是看不到的(配合拦截就可以安静地吸费了)。

Android4.4 及之后

  1. 设立默认短信应用机制,成为默认短信后的应用将全面接管(替代)系统短信服务。与设置默认浏览器类似,成为默认短信应用需要向用户申请。

  2. 新接收短信广播 SMS_RECEIVED_ACTION 更改为无序广播,增加只有默认短信应用能够接收的广播SMS_DELIVER_ACTION和WAP_PUSH_DELIVER_ACTION 。二者的不同在于,当默认短信应用收到SMS_DELIVER_ACTION 时它要负责将其存入数据库。任意应用仍然可以接收到 SMS_RECEIVED_ACTION广播但不能将其中止。因此所有的应用和系统短信服务都可以接收到新短信,没有应用能够再用中止广播的方式拦截短信

  3. 只有默认短信应用可以操作短信数据库,包括新建(含伪造收件箱和发件箱短信)、修改(含篡改历史短信)和删除。其它应用只能读取短信数据库。默认短信应用需要在发送短信、收到新短信之后手动写入系统短信数据库,否则其它应用将读取不到该条短信。默认短信应用可以通过控制不写入数据库的方式拦截短信。

  4. 任意应用仍然都可以发送短信,但默认短信应用以外的应用发短信的接口底层改为调用系统短信服务,而不再直接调用驱动通信,因此其所发短信会被系统短信服务自动转存数据库。此外,只有默认短信应用可以发送彩信。

简单来说,第三方非默认短信应用

  1. 可以收短信、发短信并接收短信回执,但是不能删除短信
  2. 可以查询短信数据库,但是不能新增、删除、修改短信数据库
  3. 无法拦截短信

短信拦截的解决方案

提示用户设置自己的app为default SMS app!!!

为了使我们的应用出现在系统设置的Default SMS app中,我们需要在Manifest中做一些声明,获取对应的权限:

  1. 声明一个 broadcast receiver控件,对SMS_DELIVER_ACTION广播进行监听,当然这个receiver也要声明BROADCAST_SMS权限。
  2. 声明一个 broadcast receiver控件,对WAP_PUSH_DELIVER_ACTION广播进行监听,当然这个receiver也要声明BROADCAST_WAP_PUSH权限。
  3. 在短信发送界面,需要监听 ACTION_SENDTO,同时配置上sms:, smsto:, mms:, and mmsto这四个概要,这样别的应用如果想发送短信,你的这个activity就能知道。
  4. 需要有一个service,能够监听ACTION_RESPONSE_VIA_MESSAGE,同时也要配置上sms:, smsto:, mms:, and mmsto这四个概要,并且要声明SEND_RESPOND_VIA_MESSAGE权限。这样用户就能在来电的时候,用你的应用来发送拒绝短信。
<manifest>  
    ...  
    <application>  
        <!-- BroadcastReceiver that listens for incoming SMS messages -->  
        <receiver android:name=".SmsReceiver"  
                android:permission="android.permission.BROADCAST_SMS">  
            <intent-filter>  
                <action android:name="android.provider.Telephony.SMS_DELIVER" />  
            </intent-filter>  
        </receiver>  

        <!-- BroadcastReceiver that listens for incoming MMS messages -->  
        <receiver android:name=".MmsReceiver"  
            android:permission="android.permission.BROADCAST_WAP_PUSH">  
            <intent-filter>  
                <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />  
                <data android:mimeType="application/vnd.wap.mms-message" />  
            </intent-filter>  
        </receiver>  

        <!-- Activity that allows the user to send new SMS/MMS messages -->  
        <activity android:name=.MainActivity" >  
            <intent-filter>  
                <action android:name="android.intent.action.SEND" />                  
                <action android:name="android.intent.action.SENDTO" />  
                <category android:name="android.intent.category.DEFAULT" />  
                <category android:name="android.intent.category.BROWSABLE" />  
                <data android:scheme="sms" />  
                <data android:scheme="smsto" />  
                <data android:scheme="mms" />  
                <data android:scheme="mmsto" />  
            </intent-filter>  
        </activity>  

        <!-- Service that delivers messages from the phone "quick response" -->  
        <service android:name=".HeadlessSmsSendService"  
                 android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"  
                 android:exported="true" >  
            <intent-filter>  
                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />  
                <category android:name="android.intent.category.DEFAULT" />  
                <data android:scheme="sms" />  
                <data android:scheme="smsto" />  
                <data android:scheme="mms" />  
                <data android:scheme="mmsto" />  
            </intent-filter>  
        </service>  
    </application>  
</manifest>  

通过 Telephony.Sms.getDefaultSmsPackage()方法来判断自己的应用是否为Default SMS app。如果不是,可以通过startActivity() 方法启动类似如下的Dialog。

public class  MainActivity extends Activity {

    @Override
    protected void onResume() {
        super.onResume();
        final String myPackageName = getPackageName();
        if (!Telephony.Sms.getDefaultSmsPackage(this).equals(myPackageName)) {
            // App is not default.
            // Show the "not currently set as the default SMS app" interface
            View viewGroup = findViewById(R.id.ll_not_default_app);
            viewGroup.setVisibility(View.VISIBLE);

            // Set up a button that allows the user to change the default SMS app
            View button = findViewById(R.id.btn_change_default_app);
            button.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
                    intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, myPackageName);
                    startActivity(intent);
                }
            });
        } else {
            // App is the default.
            // Hide the "not currently set as the default SMS app" interface
            View viewGroup = findViewById(R.id.ll_not_default_app);
            viewGroup.setVisibility(View.GONE);
        }
    }

Android-垃圾短信拦截Android-垃圾短信拦截
以上源码下载地址:https://github.com/wenzhiming/520sms