随笔-1  评论-68  文章-98  trackbacks-0

作者:徐建祥(netpirate@gmail.com)
日期:2010/08/10
网址:http://www.anymobile.org

 

Android手机上监听短信有两种方式:

 

1、 接受系统的短信广播,操作短信内容。

 

优点:操作方便,适合简单的短信应用。

缺点:来信会在状态栏显示通知信息。

 

AndroidManifest.xml

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

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

 

<!-- Receiver -->

<receiver android:name=".sms.SMSReceiver">

<intent-filter>

    <action android:name="android.provider.Telephony.SMS_RECEIVED" />

</intent-filter>

</receiver>

 

code

package org.anymobile.demo.sms;

 

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.telephony.gsm.SmsMessage;

import android.util.Log;

 

public class SMSReceiver extends BroadcastReceiver

{

    public static final String TAG = "ImiChatSMSReceiver";

    //android.provider.Telephony.Sms.Intents

    public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";

   

    @Override

    public void onReceive(Context context, Intent intent)

    {

       if (intent.getAction().equals(SMS_RECEIVED_ACTION))

       {

           SmsMessage[] messages = getMessagesFromIntent(intent);

           for (SmsMessage message : messages)

           {

              Log.i(TAG, message.getOriginatingAddress() + " : " +

                  message.getDisplayOriginatingAddress() + " : " +

                  message.getDisplayMessageBody() + " : " +

                  message.getTimestampMillis());

           }

       }

    }

   

    public final SmsMessage[] getMessagesFromIntent(Intent intent)

    {

        Object[] messages = (Object[]) intent.getSerializableExtra("pdus");

        byte[][] pduObjs = new byte[messages.length][];

 

        for (int i = 0; i < messages.length; i++)

        {

            pduObjs[i] = (byte[]) messages[i];

        }

        byte[][] pdus = new byte[pduObjs.length][];

        int pduCount = pdus.length;

        SmsMessage[] msgs = new SmsMessage[pduCount];

        for (int i = 0; i < pduCount; i++)

        {

            pdus[i] = pduObjs[i];

            msgs[i] = SmsMessage.createFromPdu(pdus[i]);

        }

        return msgs;

    }

 

}

 

2、 应用观察者模式,监听短信数据库,操作短信内容。

 

优点:可以拦截来信在状态栏的显示通知,适合作短信拦截。

缺点:可以发展成MU,在后台悄悄的收/发短信。

 

实例如下:

SystemEventReceiver:收到开机启动OK的广播后,启动BootService服务;收到应用发送短信的INTENT后,调用系统接口发送短信

BootService:开启服务后,打开短信监听器

SMSObserver:数据观察者,监听短信数据库

SMSHandler:短信处理器

 

AndroidManifest.xml

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

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

<!-- Service -->

<service android:name=".BootService"

        android:label="@string/app_name">

    <intent-filter>

                <action android:name="org.anymobile.test.service.IMICHAT" />

    <category android:name="android.intent.category.DEFAULT" />

</intent-filter>

</service>

<!-- Receiver -->

<receiver android:name=".SystemEventReceiver">

<intent-filter>

    <action android:name="android.intent.action.BOOT_COMPLETED" />

</intent-filter>

</receiver>

 

code

package org.anymobile.demo.sms;

 

import android.content.ContentUris;

import android.content.Context;

import android.content.Intent;

import android.net.Uri;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

 

public class SMSHandler extends Handler

{

    public static final String TAG = "SMSHandler";

 

    private Context mContext;

   

    public SMSHandler(Context context)

    {

       super();

       this.mContext = context;

    }

   

    public void handleMessage(Message message)

    {

       Log.i(TAG,  "handleMessage: " + message);

      

       MessageItem item = (MessageItem) message.obj;

       //delete the sms

       Uri uri = ContentUris.withAppendedId(SMS.CONTENT_URI, item.getId());

       mContext.getContentResolver().delete(uri, null, null);

       Log.i(TAG,  "delete sms item: " + item);

    }

}

package org.anymobile.demo.sms;

 

import android.content.ContentResolver;

import android.database.ContentObserver;

import android.database.Cursor;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

 

public class SMSObserver extends ContentObserver

{

    public static final String TAG = "SMSObserver";

   

    private static final String[] PROJECTION = new String[]

    {

    SMS._ID,//0

        SMS.TYPE,//1

        SMS.ADDRESS,//2

        SMS.BODY,//3

        SMS.DATE,//4

        SMS.THREAD_ID,//5

        SMS.READ,//6

        SMS.PROTOCOL//7

    };

    private static final String SELECTION =

    SMS._ID  + " > %s" +

//      " and " + SMS.PROTOCOL + " = null" +

//      " or " + SMS.PROTOCOL + " = " + SMS.PROTOCOL_SMS + ")" +

    " and (" + SMS.TYPE + " = " + SMS.MESSAGE_TYPE_INBOX +

    " or " + SMS.TYPE + " = " + SMS.MESSAGE_TYPE_SENT + ")";

   

    private static final int COLUMN_INDEX_ID    = 0;

    private static final int COLUMN_INDEX_TYPE  = 1;

    private static final int COLUMN_INDEX_PHONE = 2;

    private static final int COLUMN_INDEX_BODY  = 3;

    private static final int COLUMN_INDEX_PROTOCOL = 7;

 

    private static final int MAX_NUMS = 10;

    private static int MAX_ID = 0;

 

    private ContentResolver mResolver;

    private Handler mHandler;

   

    public SMSObserver(ContentResolver contentResolver, Handler handler)

    {

       super(handler);

      

       this.mResolver = contentResolver;

       this.mHandler = handler;

    }

 

    @Override

    public void onChange(boolean selfChange)

    {

       Log.i(TAG, "onChange : " + selfChange + "; " + MAX_ID + "; " + SELECTION);

       super.onChange(selfChange);

       

        Cursor cursor = mResolver.query(SMS.CONTENT_URI, PROJECTION,

        String.format(SELECTION, MAX_ID), null, null);

       

        int id, type, protocol;

        String phone, body;

        Message message;

        MessageItem item;

       

        int iter = 0;

        boolean hasDone = false;

       

        while (cursor.moveToNext())

        {

        id = cursor.getInt(COLUMN_INDEX_ID);

        type = cursor.getInt(COLUMN_INDEX_TYPE);

        phone = cursor.getString(COLUMN_INDEX_PHONE);

        body = cursor.getString(COLUMN_INDEX_BODY);

        protocol = cursor.getInt(COLUMN_INDEX_PROTOCOL);

          

        if (hasDone)

        {

             MAX_ID = id;

             break;

        }

        if (protocol == SMS.PROTOCOL_SMS && body != null && body.startsWith(SMS.FILTER))

        {

             hasDone = true;

            

            item = new MessageItem();

            item.setId(id);

            item.setType(type);

            item.setPhone(phone);

            item.setBody(body);

            item.setProtocol(protocol);

           

            message = new Message();

               message.obj = item;

               mHandler.sendMessage(message);

        }

        else

        {

              if (id > MAX_ID) MAX_ID = id;

        }

        if (iter > MAX_NUMS) break;

        iter ++;

        }

    }

}

 

package org.anymobile.demo.sms;

 

import android.net.Uri;

import android.provider.BaseColumns;

 

public interface SMS extends BaseColumns

{

    public static final Uri CONTENT_URI = Uri.parse("content://sms");

    public static final String FILTER  = "!imichat";

   

    public static final String TYPE = "type";

    public static final String THREAD_ID = "thread_id";

    public static final String ADDRESS = "address";

    public static final String PERSON_ID = "person";

    public static final String DATE = "date";

    public static final String READ = "read";

    public static final String BODY = "body";

    public static final String PROTOCOL = "protocol";

 

    public static final int MESSAGE_TYPE_ALL    = 0;

    public static final int MESSAGE_TYPE_INBOX  = 1;

    public static final int MESSAGE_TYPE_SENT   = 2;

    public static final int MESSAGE_TYPE_DRAFT  = 3;

    public static final int MESSAGE_TYPE_OUTBOX = 4;

    public static final int MESSAGE_TYPE_FAILED = 5; // for failed outgoing messages

    public static final int MESSAGE_TYPE_QUEUED = 6; // for messages to send later

   

    public static final int PROTOCOL_SMS = 0;//SMS_PROTO

    public static final int PROTOCOL_MMS = 1;//MMS_PROTO

}

 

package org.anymobile.demo.sms;

 

public class MessageItem implements java.io.Serializable

{

    private static final long serialVersionUID = 1L;

   

    private int id;

    private int type;

    private int protocol;

    private String phone;

    private String body;

   

    public MessageItem()

    {}

 

    public int getId()

    {

       return id;

    }

 

    public void setId(int id)

    {

       this.id = id;

    }

 

    public int getType()

    {

       return type;

    }

 

    public void setType(int type)

    {

       this.type = type;

    }

 

    public int getProtocol()

    {

       return protocol;

    }

 

    public void setProtocol(int protocol)

    {

       this.protocol = protocol;

    }

 

    public String getPhone()

    {

       return phone;

    }

 

    public void setPhone(String phone)

    {

       this.phone = phone;

    }

 

    public String getBody()

    {

       return body;

    }

 

    public void setBody(String body)

    {

       this.body = body;

    }

   

    public String toString()

    {

       return

           "id = " + id + ";" +

           "type = " + type + ";" +

           "protocol = " + protocol + ";" +

           "phone = " + phone + ";" +

           "body = " + body;

    }

}

package org.anymobile.demo;

 

import android.app.Service;

import android.content.ContentResolver;

import android.content.Intent;

import android.database.ContentObserver;

import android.os.Handler;

import android.os.IBinder;

import android.os.Process;

import android.util.Log;

 

import org.anymobile.demo.sms.SMS;

import org.anymobile.demo.sms.SMSHandler;

import org.anymobile.demo.sms.SMSObserver;

 

public class BootService extends Service

{

    public static final String TAG = "BootService";

   

    private ContentObserver mObserver;

 

    private Handler mHandler = new Handler();

   

    @Override

    public void onCreate()

    {

       Log.i(TAG, "onCreate().");

       super.onCreate();

      

       addSMSObserver();

    }

   

    public void addSMSObserver()

    {

       Log.i(TAG, "add a SMS observer. ");

      

       ContentResolver resolver = getContentResolver();

      

       Handler handler = new SMSHandler(this);

       mObserver = new SMSObserver(resolver, handler);

       resolver.registerContentObserver(SMS.CONTENT_URI, true, mObserver);

    }

 

    @Override

    public IBinder onBind(Intent intent)

    {

       return null;

    }

 

    @Override

    public void onDestroy()

    {

       Log.i(TAG, "onDestroy().");

      

        this.getContentResolver().unregisterContentObserver(mObserver);

      

       super.onDestroy();

 

        Process.killProcess(Process.myPid());

       System.exit(0);

    }

}

 

package org.anymobile.demo;

 

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

//import android.os.Handler;

//import android.os.Message;

import android.telephony.gsm.SmsManager;

 

import org.anymobile.demo.sms.MessageItem;

 

public class SystemEventReceiver extends BroadcastReceiver

{

    @Override

    public void onReceive(Context context, Intent intent)

    {

       if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))

       {

           context.startService(new Intent(Globals.IMICHAT_SERVICE));

       }

       else if (intent.getAction().equals(Globals.ACTION_SEND_SMS))

       {

           MessageItem mItem =

              (MessageItem) intent.getSerializableExtra(Globals.EXTRA_SMS_DATA);

           if (mItem != null && mItem.getPhone() != null && mItem.getBody() != null)

           {

              SmsManager.getDefault()

                  .sendTextMessage(mItem.getPhone(), null,

                     mItem.getBody(), null, null);

//            new Thread(mTasks).start();

           }

       }

    }

}

 

 OVER!

posted on 2010-08-10 11:50 Xu Jianxiang 阅读(44232) 评论(28)  编辑  收藏 所属分类: Android

评论:
# re: Android手机上监听短信的两种方式 2010-09-09 16:29 | liang
文章不错,支持!  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2010-09-11 09:53 | imiyoo
你好,能留个联系方式,想和你交流下  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2010-09-20 16:11 | me_4
好像Globals类没有上传。
期待更新下。
谢谢  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2010-09-30 15:26 | winny
同问,Globals类到底是什么样子的?  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2010-10-10 00:46 | anymobile
@imiyoo
徐建祥(netpirate@gmail.com)  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2010-10-10 00:47 | anymobile
@me_4
Globals类是项目专业的常量定义类,自行定义即可。  回复  更多评论
  
# re: Android手机上监听短信的两种方式[未登录] 2010-11-10 17:26 | 111
Globals类具体怎么写,给个提示,谢谢  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2010-12-14 22:29 | Xu Jianxiang
/****************************************************************
* COPYRIGHT Mobim Technology CO.,LTD *
*****************************************************************/
/*****************************************************************
* FileName: Globals.java
* version: 1.0.0
* Authors: Xu Jian Xiang,
* Date: 2010-8-13
* Purpose:
* Notes:
******************************************************************/
package org.anymobile.common;

public class Globals
{

public static final String ACTION_SEND_SMS = "com.mobimtech.imichat.intent.action.SEND_SMS";
public static final String EXTRA_SMS_DATA = "com.mobimtech.imichat.intent.extra.SMS_DATA";

}  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2010-12-24 16:35 | lulu021
您好,刚刚看到您的这篇文章,我正在做相关的东西,希望您能给予指点,我在做关于短信的同步软件,也就是在该软件上面可以监听到短信的接受,和删除。
但是现在就是有一个问题,就是现在的android系统的短信里面有个会话删除(delete thread)如果仅删除一条短信的话,我的软件可以同步的更新掉,可是一旦用户是删除整个会话(和某人的全部信息)的话,则我的软件上面的短信还是显示,没有被同步删除掉~~~不知道我有没有表述清楚,希望您能帮忙指点~~~再次感谢~~~  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2011-01-05 13:49 | linkewei
你好,我正在做短信拦截或提示的管理软件,请问一下程序能不能做到当前哪个程序在后台偷偷的发送短信,我的QQ:65440001,谢谢,希望能得到你的指点。  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2011-01-07 21:57 | Xu Jianxiang
@lulu021
用此监听短信数据库,只要有变更都可以观察到。  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2011-01-07 21:58 | Xu Jianxiang
@linkewei
发短信后就会变更短信数据库,悄悄发短信的程序会监听到事件后删掉这条记录,大家干同样的事,就要比优先级了,呵呵。  回复  更多评论
  
# re: Android手机上监听短信的两种方式[未登录] 2011-07-24 19:13 | Ivan
收到短信后怎么在Activity或者状态栏显示短信内容呢  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2011-07-29 20:50 | 莫名其妙
主次不分,废代码一大堆,其实监听短信的关键代码就那么几行而已,搞这么多东西谁有耐心看  回复  更多评论
  
# re: Android手机上监听短信的两种方式[未登录] 2011-08-10 14:17 | Xu Jianxiang
@莫名其妙
人如其名,哈哈!  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2011-08-23 22:18 | dongjin
楼主,那个SMS类中,Filter的值为“!imichat“,那个imichat是什么意思啊?  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2011-08-23 22:26 | dongjin
是不是这么回事啊,楼主这段程序是不是那个什么艾米聊天的一部分啊?  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2013-04-18 23:33 | dadangjia
学习了,挺不错的,就是不太符合我的需求,我要做的不是MU。其次我有个问题,通过数据库的删除短信,可以屏蔽通知栏显示吗?  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2013-05-06 21:02 | lao
学习  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2013-09-06 10:12 | 沈宇峰
第一种方式可以成功吗  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2014-04-02 15:50 | 博主
IMICHAT_SERVICE什么意思?  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2014-04-02 15:50 | 博主
IMICHAT_SERVICE什么意思。。  回复  更多评论
  
# re: Android手机上监听短信的两种方式[未登录] 2014-04-12 13:27 | Jack
@linkewei
你的做好了吗
希望能够指导下我  回复  更多评论
  
# re: Android手机上监听短信的两种方式[未登录] 2014-04-12 13:27 | Jack

@linkewei
QQ 610107915  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2014-04-21 17:09 | 百川
我用第一种方法,广播接收不到短信,不知道怎么回事?本人菜鸟,还望大神指点一二。  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2014-10-08 17:10 | zrw
@百川你注册了么222

  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2014-10-08 17:11 | zrw
问一下哈,我现在要处理大批的数据,然后在ContentObserver里面处理会Anr,能不能异步处理呢
  回复  更多评论
  
# re: Android手机上监听短信的两种方式 2015-04-08 18:35 | 刘中华
我不知道怎么玩  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: