android 监听短信并获取验证码

来源:互联网 发布:linux如何调用内核 编辑:程序博客网 时间:2024/05/18 17:40

最近想给 app 添加自动获取短信验证码的功能,让注册流程更加友好,在网上搜索了一些资料,主要的实现方法有两种。
第一:实现广播 BroadCastReceiver 来监听收件箱,在需要监听的地方注册广播监听,然后再Activity 结束的地方unregist掉。
第二:利用 ContentObserver 来监听短信数据库,当有指定的新信息到来时调用相应的方法来实现信息内容的读取。以下仅给出第二种方法的实现代码(亲测可行哦!)。

  • 修改 AndroidManifest.xml 获取短信接收和读取权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/><uses-permission android:name="android.permission.READ_SMS"/>
  • 新建一个Activity
package com.example.myapp;import android.app.Activity;import android.content.ContentResolver;import android.content.Context;import android.database.ContentObserver;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.widget.EditText;import java.util.regex.Matcher;import java.util.regex.Pattern;public class MyActivity extends Activity {    /**     * Called when the activity is first created.     */    private EditText verifyText;    private SmsObserver smsObserver;    private Uri SMS_INBOX = Uri.parse("content://sms/");    public void getSmsFromPhone() {        ContentResolver cr = getContentResolver();        //这个projection参数初始化要尤其注意哦!由于我只想获取验证码内容,我就只填了“body”,如果给位还需要获取发件人信息的话,可以继续添加        String[] projection = new String[] { "body"};        String where = " address = '1069041810748872' AND date >  "              + (System.currentTimeMillis() - 60 * 1000);        //设置监听指定号码,10分钟内有效,如果您不需要指定号码的话,只需要去掉相应的条件就ok        Cursor cur = cr.query(SMS_INBOX, projection, where, null, "date desc");        if (null == cur)            return;        if (cur.moveToFirst()) {            String body = cur.getString(cur.getColumnIndex("body"));            //这里我是要获取自己短信服务号码中的验证码,务必记住这里获取的内容需要和projection字符串对应,否则短信数据库可能会找不到内容的。            Pattern pattern = Pattern.compile("[0-9]{4}");            //我获取的验证码是4位阿拉伯数字,正则匹配规则您可能需要修改            Matcher matcher = pattern.matcher(body);            if (matcher.find()) {                String res = matcher.group();                verifyText.setText(res);            }        }    }    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        verifyText = (EditText) findViewById(R.id.verifycode);        smsObserver = new SmsObserver(this, smsHandler);        getContentResolver().registerContentObserver(SMS_INBOX, true,                smsObserver);    }    public Handler smsHandler = new Handler() {        //这里可以进行回调的操作        //TODO    };    class SmsObserver extends ContentObserver {        public SmsObserver(Context context, Handler handler) {            super(handler);        }        @Override        public void onChange(boolean selfChange) {            super.onChange(selfChange);            //每当有新短信到来时,使用我们获取短消息的方法            getSmsFromPhone();        }    }}
  • main.xml如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:orientation="vertical"              android:layout_width="fill_parent"              android:layout_height="fill_parent"        >    <TextView            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:text="Hello World, MyActivity"            />    <EditText            android:id="@+id/verifycode"            android:layout_width="200dp"            android:layout_height="50dp"/></LinearLayout>

是不是很简单呢? 可能会有朋友碰到类似下面这样的问题:

Failed to read row 0, column 1 from a CursorWindow which has 1 rows, 1 columns.FATAL EXCEPTION: mainjava.lang.IllegalStateException: Could not execute method of the activityCaused by: java.lang.IllegalStateException: Couldn't read row 0, col 1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.

这种情况就是说CursorWindow没有成功的初始化,不妨通过打 log 的方式,看看cur中到底有什么,本人出现这个问题就在于 projection 没有设置好,导致初始化出来的cur并不是我想要的。
附上短信数据库简单分析:

*address:短信发送者电话号码
person:联系人编号,如果电话薄里有联系人则显示编号,没有联系人则显示null
read:读取状态,0为未读,1为已读
body:短信内容*

好了,就这些了,感谢!

0 0