android获取短信验证码并自动填写的实现二
2015-09-30 09:51
579 查看
之前我提供了一种获取短信息验证码并自动填写的实现方式,就是直接通过短信广播监听短信。但是,这种方式有它的缺陷:当你的手机安装了其他一些短信应用(例如QQ通讯录)或者手机本身限制了权限的情况下,这种方式有可能会不起作用,无法做到自动填写,而且就算把优先级设高,也不能保证不会被别的应用“抢先”。
后来查资料知道,可以通过监听短信数据库的方式实现。监听短信数据库主要是通过ContentObserver这个类来完成。ContentObserver主要是通过Uri来监测特定的Databases的表,当ContentObserver所观察的Uri发生变化时,便会触发它。思路就是监听短信数据库中特定号码的未读短信。我们可以通过百度找到许多demo,但是我发现很多demo中存在着Bug,在接收到短信后引起崩溃。还有一种情况,当真机连接着电脑,电脑装有类似豌豆荚之类的软件的时候,手机收到短信后,豌豆荚之类的可能会把该短信的状态改成“已读”,这样也会导致崩溃。
通过调试,终于把Bug修复了,布局和短信权限就不再赘述。在MainActivity中增加一个内部类SmsContent。
记得在onCreate中注册短信变化监听
记得注销监听
其中,下发的验证码短信一般都是一个字符串,其中包含6位数字,我们需要把这6位数字提取出来,我们可以用正则表达式写一个静态方法。
public static String getyzm(String body, int YZMLENGTH)
{
// 首先([a-zA-Z0-9]{YZMLENGTH})是得到一个连续的六位数字字母组合
// (?<![a-zA-Z0-9])负向断言([0-9]{YZMLENGTH})前面不能有数字
// (?![a-zA-Z0-9])断言([0-9]{YZMLENGTH})后面不能有数字出现
Pattern p = Pattern.compile("(?<![a-zA-Z0-9])([a-zA-Z0-9]{" + YZMLENGTH + "})(?![a-zA-Z0-9])");
Matcher m = p.matcher(body);
if (m.find())
{
System.out.println(m.group());
return m.group(0);
}
return null;
}
至此,android获取短信验证码并自动填写的功能就实现了。
后来查资料知道,可以通过监听短信数据库的方式实现。监听短信数据库主要是通过ContentObserver这个类来完成。ContentObserver主要是通过Uri来监测特定的Databases的表,当ContentObserver所观察的Uri发生变化时,便会触发它。思路就是监听短信数据库中特定号码的未读短信。我们可以通过百度找到许多demo,但是我发现很多demo中存在着Bug,在接收到短信后引起崩溃。还有一种情况,当真机连接着电脑,电脑装有类似豌豆荚之类的软件的时候,手机收到短信后,豌豆荚之类的可能会把该短信的状态改成“已读”,这样也会导致崩溃。
通过调试,终于把Bug修复了,布局和短信权限就不再赘述。在MainActivity中增加一个内部类SmsContent。
/** * 监听短信数据库 */ class SmsContent extends ContentObserver { private Cursor cursor = null; public SmsContent(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); //读取收件箱中指定号码的短信 cursor = managedQuery(Uri.parse("content://sms/inbox"), new String[]{"_id", "address", "read", "body"}, " address=? and read=?", new String[]{"1065811201", "0"}, "_id desc");//按id排序,如果按date排序的话,修改手机时间后,读取的短信就不准了 MyLog.l("cursor.isBeforeFirst() " + cursor.isBeforeFirst() + " cursor.getCount() " + cursor.getCount()); if (cursor != null && cursor.getCount() > 0) { ContentValues values = new ContentValues(); values.put("read", "1"); //修改短信为已读模式 cursor.moveToNext(); int smsbodyColumn = cursor.getColumnIndex("body"); String smsBody = cursor.getString(smsbodyColumn); MyLog.v("smsBody = " + smsBody); edtPassword.setText(MatchesUtil.getDynamicPassword(smsBody)); } //在用managedQuery的时候,不能主动调用close()方法, 否则在Android 4.0+的系统上, 会发生崩溃 if(Build.VERSION.SDK_INT < 14) { cursor.close(); } } }
记得在onCreate中注册短信变化监听
SmsContent content = new SmsContent(new Handler()); //注册短信变化监听 this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, content);
记得注销监听
this.getContentResolver().unregisterContentObserver(content);
其中,下发的验证码短信一般都是一个字符串,其中包含6位数字,我们需要把这6位数字提取出来,我们可以用正则表达式写一个静态方法。
/** * 从字符串中截取连续6位数字 * 用于从短信中获取动态密码 * @param str 短信内容 * @return 截取得到的6位动态密码 */ public static String getDynamicPassword(String str) { Pattern continuousNumberPattern = Pattern.compile("[0-9\\.]+"); Matcher m = continuousNumberPattern.matcher(str); String dynamicPassword = ""; while(m.find()){ if(m.group().length() == 6) { System.out.print(m.group()); dynamicPassword = m.group(); } } return dynamicPassword; }
public static String getyzm(String body, int YZMLENGTH)
{
// 首先([a-zA-Z0-9]{YZMLENGTH})是得到一个连续的六位数字字母组合
// (?<![a-zA-Z0-9])负向断言([0-9]{YZMLENGTH})前面不能有数字
// (?![a-zA-Z0-9])断言([0-9]{YZMLENGTH})后面不能有数字出现
Pattern p = Pattern.compile("(?<![a-zA-Z0-9])([a-zA-Z0-9]{" + YZMLENGTH + "})(?![a-zA-Z0-9])");
Matcher m = p.matcher(body);
if (m.find())
{
System.out.println(m.group());
return m.group(0);
}
return null;
}
至此,android获取短信验证码并自动填写的功能就实现了。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories