(七)android开发中两种方式监听短信的原理和实现

一、监听短信的两种方式的简介

Android程序开发中,有两种方式监听短信内容:一、接收系统的短信广播;二、应用观察者模式,监听短信数据库。

第一种方式接收系统的短信广播: A、这种方式只对新收到的短消息有效,运行代码,并不会读取收件箱中已读或未读的消息,只有当收到新来的短消息时,才会执行onReceive()方法。

B、并且这个广播是有序广播,如果当别的程序先读取到了这个广播,然后拦截掉了个这个广播,你将接收不到。当然我们可以通过设置priority的数值,其实有时是不管用的,现在在一些定制的系统或是有安全软件的情况下,往往短消息都被截取到,并被干掉。

第二种方式应用观察者模式,监听短信数据库:这种方式比方法一稍微复杂一些,不过使用起来也很方便,不受其它程序干扰,并且这种方式可以获取手机上的收件箱、已发送、草稿箱等等数据库的变化。

二、接收系统的短信广播方式的实现

2.1 在AndroidManifest.xml中添加权限

<uses-permission android:name="android.permission.RECEIVE_SMS" /> <!-- 接收短信权限 -->
<uses-permission android:name="android.permission.READ_SMS" /> <!-- 读取短信权限 -->

2.2 在AndroidManifest.xml中注册 广播

<receiver android:name="com.example.smslistenerdemo.SmsReceiver" >
            <intent-filter android:priority="2147483647" >
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
 </receiver>

2.3 SmsReceiver.java中的代码如下所示

package com.example.smslistenerdemo;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;

/**
 * 类说明:
 *
 * @author fuyanan
 * @date 2015-8-28
 * @version 1.0.0
 */
public class SmsReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        SmsMessage msg = null;
        if (null != bundle) {
            Object[] smsObj = (Object[]) bundle.get("pdus");
            for (Object object : smsObj) {
                msg = SmsMessage.createFromPdu((byte[]) object);
                Date date = new Date(msg.getTimestampMillis());// 时间
                SimpleDateFormat format = new SimpleDateFormat(
                        "yyyy-MM-dd HH:mm:ss");
                String receiveTime = format.format(date);
                Log.i("fuyanan", "address:" + msg.getOriginatingAddress()
                        + "   body:" + msg.getDisplayMessageBody() + "  time:"
                        + msg.getTimestampMillis());
            }
        }
    }
}

三、应用观察者模式,监听短信数据库

3.1 ContentObserver简介

ContentObserver——内容观察者,目的是观察(捕捉)指定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变哈时,便会触发它。

抽象类ContentResolver类中的方法原型如下,注册/取消注册ContentObserver方法

(1)注册:public final void  registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)。

功能:为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理。

参数:uri   需要观察的Uri(需要在UriMatcher里注册,否则该Uri也没有意义了)

notifyForDescendents  为false 表示精确匹配,即只匹配该Uri;为true 表示可以同时匹配其派生的Uri,举例如下:

假设UriMatcher 里注册的Uri共有一下类型:

1 、content://com.qin.cb/student (学生)

2 、content://com.qin.cb/student/#

3、 content://com.qin.cb/student/schoolchild(小学生,派生的Uri)

假设我们当前需要观察的Uri为content://com.qin.cb/student,如果发生数据变化的 Uri 为 content://com.qin.cb/student/schoolchild ,当notifyForDescendents为 false,那么该ContentObserver会监听不到, 但是notifyForDescendents                       为ture,能捕捉该Uri的数据库变化。

observer   ContentObserver的派生类实例

(2)取消注册:public final void  unregisterContentObserver(ContentObserver observer)

功能:取消对给定Uri的观察

3.2  应用观察者模式,监听短信数据库的实现demo

3.2.1  在AndroidManifest.xml中添加权限

  <uses-permission android:name="android.permission.RECEIVE_SMS" /> <!-- 接收短信权限 -->
  <uses-permission android:name="android.permission.READ_SMS" /> <!-- 读取短信权限 -->

3.2.2 SMSContentObserver.java中的代码如下所示

package com.example.smslistenerdemo;

import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;

/**
 * 类说明:监听短信有两种方式:第一通过接受系统短息广播;第二监听短信数据库
 * 本类是用来观察系统里短信收件箱的数据库的变化,只要短信收件箱数据库发生变化,就会触发该类。
 *
 * @author fuyn
 * @date 2015-7-20
 * @version 1.0.0
 */
public class SMSContentObserver extends ContentObserver {
    private static final int MSG_INBOX = 1;
    private Context mContext;
    private Handler mHandler; // 更新UI线程

    public SMSContentObserver(Context mContext,
            Handler mHandler) {
        super(mHandler); // 所有ContentObserver的派生类都需要调用该构造方法
        this.mContext = mContext;
        this.mHandler = mHandler;
    }

    /**
     * 当观察到的Uri发生变化时,回调该方法去处理。所有ContentObserver的派生类都需要重载该方法去处理逻辑
     * selfChange:回调后,其值一般为false,该参数意义不大
     */
    @Override
    public void onChange(boolean selfChange) {
        // TODO Auto-generated method stub
        super.onChange(selfChange);
        mHandler.obtainMessage(MSG_INBOX, "SMS Received").sendToTarget();
    }

}

3.2.3 MainActivity.java中的代码如下所示

package com.example.smslistenerdemo;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.EditText;

public class MainActivity extends Activity {
    private EditText login_et_sms_code;
    private SMSContentObserver smsContentObserver;
    protected static final int MSG_INBOX = 1;
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_INBOX:
                setSmsCode();
                break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        login_et_sms_code = (EditText) this
                .findViewById(R.id.login_et_sms_code);
        smsContentObserver = new SMSContentObserver(MainActivity.this, mHandler);
    }

    private void setSmsCode() {
        Cursor cursor = null;
        // 添加异常捕捉
        try {
            cursor = getContentResolver().query(
                    Uri.parse("content://sms/inbox"),
                    new String[] { "_id", "address", "read", "body", "date" },
                    null, null, "date desc"); // datephone想要的短信号码
            if (cursor != null) { // 当接受到的新短信与想要的短信做相应判断
                String body = "";
                while (cursor.moveToNext()) {
                    body = cursor.getString(cursor.getColumnIndex("body"));// 在这里获取短信信息
                    long smsdate = Long.parseLong(cursor.getString(cursor
                            .getColumnIndex("date")));
                    long nowdate = System.currentTimeMillis();
                    // 如果当前时间和短信时间间隔超过60秒,认为这条短信无效
                    if (nowdate - smsdate > 60 * 1000) {
                        break;
                    }
                    // 下面匹配验证码
                    Pattern pattern = Pattern.compile("\\d{6}");
                    Matcher matcher = pattern.matcher(body);
                    if (matcher.find()) {
                        String smsCodeStr = matcher.group(0);
                        Log.i("fuyanan", "sms find: code=" + matcher.group(0));// 打印出匹配到的验证码
                        login_et_sms_code.setText(smsCodeStr);
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        if (smsContentObserver != null) {
            getContentResolver().registerContentObserver(
                    Uri.parse("content://sms/"), true, smsContentObserver);// 注册监听短信数据库的变化
        }
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        if (smsContentObserver != null) {
            getContentResolver().unregisterContentObserver(smsContentObserver);// 取消监听短信数据库的变化
        }

    }

}

3.2.4 activity_main.xml中的代码如下所示

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <EditText
        android:id="@+id/login_et_sms_code"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:cursorVisible="false"
        android:hint="请输入验证码"
        android:inputType="number" />

</RelativeLayout>

3.2.5 程序的运行结果如下所示

时间: 2024-10-03 22:41:35

(七)android开发中两种方式监听短信的原理和实现的相关文章

Android 监听短信 两种方式

1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. AndroidManifest.xml: <uses-permission android:name="android.permission.SEND_SMS"></uses-permission> <uses-permission android:name="android.permission.RECEIVE_SMS"

Android 监听短信2种方式:Broadcast和ContentObserver

1. 基于Broadcast接受短信 1.1 原理 Android收到短信后系统会发送一个android.provider.Telephony.SMS_RECEIVED广播.把它放在Bundle(intent.Extras)中,Bundle可以理解为一个Map,短信采用"pdus"作为键,pdus应该是protocol description units的简写,也就是一组短信.Android不是一接收到短信就立刻发出广播的,他会有一定的延迟,所以就有可能会有多条短信,所以才会用数组来存

Android 开发事件响应之基于监听的事件响应

Android 开发事件响应之基于监听的事件响应 本文将介绍Android 操作系统如何通过监听来实现对事件的响应. Android 开发事件响应之基于监听的事件响应 背景介绍 Android 开发事件响应类型 内部类 匿名内部类 外部类 直接绑定标签 总结 背景介绍 对于任何可视化开发来说,都会涉及到对控件的响应.我们通过举例:实现对Button 按钮的点击来讲解Android 里面对事件相应的办法. Android 开发事件响应类型 在Android 开发中,有两种方式可以对事件作出响应,分

三种方式监听NGUI的事件方法

NGUI研究院之三种方式监听NGUI的事件方法(七) NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定在按钮上,当按钮点击时就可以监听到,这种方法不太好很不灵活. 1 2 3 4 void OnClick() { Debug.Log("Button is Click!!!"); }   2.使用SendMessage 选择按钮后,在Unity导航菜单栏中选择Component->In

(转)NGUI研究院之三种方式监听NGUI的事件方法

NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定在按钮上,当按钮点击时就可以监听到,这种方法不太好很不灵活. 1 2 3 4 void OnClick() { Debug.Log("Button is Click!!!"); }   2.使用SendMessage 选择按钮后,在Unity导航菜单栏中选择Component->Interaction->Button Messag

Android开发之使用BroadcastReceiver实时监听电量(源代码分享)

Android系统中实时的监听手机电量以及开机启动功能都是通过BroadcastReceiver组件实现的.我们可以动态注册这个类的一个实例通过Context.registerReceiver()方法或者静态注册,通过<Receiver>标记在androidmanifest . xml.注意:如果我们注册一个接收器在Activity.onResume()实现,我们应该注销Activity在Activity生命周期的onPause方法中.(这将减少不必要的系统开销).切记不能注销Activity

Android开发手记(15) 拨打电话和收发短信

1.Intent简介 Android组价之间的通信,由Intent来协助完成.Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用. Intent可以启动一个Activity,也可以启动一个Service,还可以发起一个广播Broadcasts.分别通过startActivity();startService();startBroadcasts();来执行操作. 在

Android 监听短信(同时监听广播和数据库)

暗扣,强烈谴责这种侵害用户利益的行为... 下面给大家介绍Android暗扣原理.......  Android4.4以下的系统玩游戏就要小心了哈 暗扣方式之一:短信订购,即监听--------拦截------------处理短信. 暗扣方式之二:模拟人为操作(又叫模拟流量),通过后台程序代码模拟人的点击行为,暗自给用户订购业务,由运营商收取你的费用,当然这其中也需要涉及监听/拦截/处理短信.使用这种方式的原理无非是Http处理网页,还涉及接入点切换问题,这里就不详细讲解. 回归正题:有的时候,

Android实战简易教程-第三十六枪(监听短信-实现短信验证码自动填入)

一般用户喜欢用手机号作为用户名注册APP账号,这时一般都是通过手机验证码的方式进行验证,下面我们就研究一个非常实用的方法,通过监听短信-实现短信验证码的自动填入,提高用户体验. 首先我们看一下如何监听手机短信. 一.获取短信全部内容 1.新建一个SMSBroadcastReceiver: package com.example.messagecut; import java.text.SimpleDateFormat; import java.util.Date; import android.