百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Android采用动态广播和观察者模式来分别实现验证码自动填写

bigegpt 2024-08-21 12:01 2 浏览

用户体验是至关重要的,我之前也实现过,就是通过短信广播的形式去监听,但是近期看了一下观察者模式,觉得实现起来也是极好的,那具体怎么做呢?大家跟我一起看下去

这里,我将用两种方式来实现短信自动填写,一种是短信广播,一种是观察者模式

我们再开始之前先定义一下规则,就是我们的短信号码和模板,一般的短信推送,你的服务号码是固定的,当然,也有可能你的量级比较大,所以在全国各地都有,但是我们这里就假设为一般的应用,所以

服务中心号码:6505551212

短信模板:感谢你使用某某应用,你的验证码为:123456!

我们就是要拿到这个验证码,既然如此,那我们开始吧!

一.BroadcastReceiver

既然通过广播来实现,我们首先先把权限给加上,不然你等下忘记了咋办

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

然后你就可以思考了,我这里写了两个控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="match_parent"
 android:padding="10dp"
 android:gravity="center"
 android:layout_height="match_parent">
 <EditText
 android:id="@+id/et_sms"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" />
 <Button
 android:id="@+id/btn_get_code"
 android:text="获取验证码"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" />
</LinearLayout>

我这里的逻辑也很简单,只要点击获取验证码的按钮,我就动态注册广播,然后短信广播来了之后拿到短信的内容,去截取短信验证码填入就好了,所以可以看到我们的代码如下

/*

*项目名: SmsAutoWriter

*包名: com.liuguilin.smsautowriter

*文件名: ReceiverActivity

*创建者: LGL

*创建时间:2017/1/715:34

*描述: 广播监听

*/

public class ReceiverActivity extends AppCompatActivity {

private static final String TAG = "ReceiverActivity";

//短信Action

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

private EditText et_sms;

private Button btn_get_code;

private SmsReceiver receiver;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_receiver);

initView();

}

private void initView() {

et_sms = (EditText) findViewById(R.id.et_sms);

btn_get_code = (Button) findViewById(R.id.btn_get_code);

btn_get_code.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

//动态注册广播

receiver = new SmsReceiver();

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(SMS_ACTION);

intentFilter.setPriority(Integer.MAX_VALUE);

registerReceiver(receiver,intentFilter);

}

});

}

private class SmsReceiver extends BroadcastReceiver{

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

Log.i(TAG,"action:" + action);

if(SMS_ACTION.equals(action)) {

//获取短信内容返回的是一个Object数组

Object[] objs = (Object[]) intent.getExtras().get("pdus");

//遍历数组得到相关数据

for (Object obj : objs) {

//把数组元素转换成短信对象

SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj);

//发件人

String smsPhone = sms.getOriginatingAddress();

//内容

String smsContent = sms.getMessageBody();

Log.i(TAG, "短信的内容:" + smsPhone + ":" + smsContent);

if(smsPhone.equals("6505551212")){

String code = smsContent.substring(17,23);

et_sms.setText(code);

}

}

}

}

}

@Override

protected void onDestroy() {

super.onDestroy();

unregisterReceiver(receiver);

}

}

这段代码的逻辑很简单,当我们获取到短信内容直接直接截取就好了,这是在知道短信内容的前提下才行的,也是之前做的,感觉思路不咋滴,而且里面获取验证码,其实我们可用去用正则表达式去解析的,这个我们下文继续讲解,嘿嘿,我们来看下运行演示的效果

恩效果是实现了,那还有没有更加逻辑性的实现方式呢?答案是有的,就是通过观察者模式去实现

二.ContentObserver

我在之前的Rx文章中提到过观察者模式,实际上大部分人还是知道以及使用观察者的

  • 观察者
  • Observer将自己注册到被观察对象Subject中,被观察者将观察者存放在一个Container容器中
  • 被观察者
  • 被观察对象发生某种变化,从容器中得到所有观察过的观察者,将变化通知观察者

理论很简单,我们今天用到的是ContentObserver,有点类似于内容提供者,不过这里是内容观察者,他的主要工作就是观察特定的Uri引起的数据库变化,做出相应的处理,在数据库中,有点类似触发器Trigger,而我们监听短信自动填写,也是用的这个,我们具体去看下代码的实现吧,先来看下我们的Activity

/*
 *项目名: SmsAutoWriter
 *包名: com.liuguilin.smsautowriter
 *文件名: ObserverActivity
 *创建者: LGL
 *创建时间:2017/1/715:34
 *描述: 观察者模式
 */
public class ObserverActivity extends AppCompatActivity implements View.OnClickListener {
 private SmsObserver smsObserver;
 public Handler handler = new Handler() {
 @Override
 public void handleMessage(Message msg) {
 super.handleMessage(msg);
 switch (msg.what) {
 case 1000:
 String code = (String) msg.obj;
 et_sms.setText(code);
 break;
 }
 }
 };
 private EditText et_sms;
 private Button btn_get_code;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_observer);
 initView();
 }
 private void initView() {
 et_sms = (EditText) findViewById(R.id.et_sms);
 btn_get_code = (Button) findViewById(R.id.btn_get_code);
 btn_get_code.setOnClickListener(this);
 }
 @Override
 protected void onDestroy() {
 super.onDestroy();
 if(smsObserver != null){
 getContentResolver().unregisterContentObserver(smsObserver);
 }
 }
 @Override
 public void onClick(View v) {
 switch (v.getId()) {
 case R.id.btn_get_code:
 if(smsObserver == null){
 smsObserver = new SmsObserver(this, handler);
 }
 Uri uri = Uri.parse("content://sms");
 //注册
 getContentResolver().registerContentObserver(uri, true, smsObserver);
 break;
 }
 }
}

我在里面,同样是一模一样的控件,一个是输入框,一个是按钮,连理论也是很类似,如果你点击了按钮,我就给你注册,不过现在不是注册广播,而是注册观察者罢了,而在onDestroy中,我把观察者给取消掉了,其实主要的逻辑还是看SmsObserver

/*
 *项目名: SmsAutoWriter
 *包名: com.liuguilin.smsautowriter
 *文件名: SmsObserver
 *创建者: LGL
 *创建时间:2017/1/716:04
 *描述: 短信
 */
public class SmsObserver extends ContentObserver{
 private static final String TAG = "SmsObserver";
 private Context mContext;
 private Handler handler;
 private String code = "";
 public SmsObserver(Context mContext,Handler handler) {
 super(handler);
 this.mContext = mContext;
 this.handler = handler;
 }
 @Override
 public void onChange(boolean selfChange, Uri uri) {
 super.onChange(selfChange, uri);
 Log.i(TAG,"短信有变化:" + uri.toString());
 //第一遍没有存储在数据库中
 if(uri.toString().equals("content://sms/raw")){
 return;
 }
 //收件箱
 Uri inboxUri = Uri.parse("content://sms/inbox");
 Cursor c = mContext.getContentResolver().query(inboxUri,null,null,null,"date desc");
 if(c != null){
 if(c.moveToFirst()){
 String phone = c.getString(c.getColumnIndex("address"));
 String content = c.getString(c.getColumnIndex("body"));
 Log.i(TAG,"短信内容:" + phone + ":" + content);
 //连续6个数字
 Pattern pattern = Pattern.compile("(\\d{6})");
 Matcher matcher = pattern.matcher(content);
 if(matcher.find()){
 code = matcher.group(0);
 Log.i(TAG,"验证码:" + code);
 }
 handler.obtainMessage(1000,code).sendToTarget();
 }
 c.close();
 }
 }
}

这里的逻辑比较多,我们慢慢来说,首先,我们的构造方法传一个上下文,一个handler进来,这个肯定是有需要的参数的,可以不提,继承的是ContentObserver,重写onChange方法这个才是重点,我们监听的就是数据库的这个url发生改变,很明显,我们设置的就是短信的数据库,所以一有短信就会触发这个方法,在这个方法里面,我们做了什么事情呢?首先判断这个url是否等于content://sms/raw,如果是的话,说明短信还没有存入数据库,一般一条短信来了之后会触发两次onChange方法,所以第一次就直接return获取,然后用Cursor 查询收件箱,这个没的说,拿到短信内容之后用正则表达式**(\d{6})**去获取里面连续6个数字,也就是我们的验证码,这样,通过Handler去更新UI,齐活,这个思路是不是更加的明了而且有效,我们这里要注意下需要添加一个阅读短信的权限

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

我们最后跑一遍

OK,到这里,我也说了两种监听的方式,你喜欢用哪种就用哪种咯,如果大家还有其他方式处理的话,欢迎来群里讨论一下哟!

源码下载:http://download.csdn.net/detail/qq_26787115/9731472

加群开车:417046685

相关推荐

悠悠万事,吃饭为大(悠悠万事吃饭为大,什么意思)

新媒体编辑:杜岷赵蕾初审:程秀娟审核:汤小俊审签:周星...

高铁扒门事件升级版!婚宴上‘冲喜’老人团:我们抢的是社会资源

凌晨两点改方案时,突然收到婚庆团队发来的视频——胶东某酒店宴会厅,三个穿大红棉袄的中年妇女跟敢死队似的往前冲,眼瞅着就要扑到新娘的高额钻石项链上。要不是门口小伙及时阻拦,这婚礼造型团队熬了三个月的方案...

微服务架构实战:商家管理后台与sso设计,SSO客户端设计

SSO客户端设计下面通过模块merchant-security对SSO客户端安全认证部分的实现进行封装,以便各个接入SSO的客户端应用进行引用。安全认证的项目管理配置SSO客户端安全认证的项目管理使...

还在为 Spring Boot 配置类加载机制困惑?一文为你彻底解惑

在当今微服务架构盛行、项目复杂度不断攀升的开发环境下,SpringBoot作为Java后端开发的主流框架,无疑是我们手中的得力武器。然而,当我们在享受其自动配置带来的便捷时,是否曾被配置类加载...

Seata源码—6.Seata AT模式的数据源代理二

大纲1.Seata的Resource资源接口源码2.Seata数据源连接池代理的实现源码3.Client向Server发起注册RM的源码4.Client向Server注册RM时的交互源码5.数据源连接...

30分钟了解K8S(30分钟了解微积分)

微服务演进方向o面向分布式设计(Distribution):容器、微服务、API驱动的开发;o面向配置设计(Configuration):一个镜像,多个环境配置;o面向韧性设计(Resista...

SpringBoot条件化配置(@Conditional)全面解析与实战指南

一、条件化配置基础概念1.1什么是条件化配置条件化配置是Spring框架提供的一种基于特定条件来决定是否注册Bean或加载配置的机制。在SpringBoot中,这一机制通过@Conditional...

一招解决所有依赖冲突(克服依赖)

背景介绍最近遇到了这样一个问题,我们有一个jar包common-tool,作为基础工具包,被各个项目在引用。突然某一天发现日志很多报错。一看是NoSuchMethodError,意思是Dis...

你读过Mybatis的源码?说说它用到了几种设计模式

学习设计模式时,很多人都有类似的困扰——明明概念背得滚瓜烂熟,一到写代码就完全想不起来怎么用。就像学了一堆游泳技巧,却从没下过水实践,很难真正掌握。其实理解一个知识点,就像看立体模型,单角度观察总...

golang对接阿里云私有Bucket上传图片、授权访问图片

1、为什么要设置私有bucket公共读写:互联网上任何用户都可以对该Bucket内的文件进行访问,并且向该Bucket写入数据。这有可能造成您数据的外泄以及费用激增,若被人恶意写入违法信息还可...

spring中的资源的加载(spring加载原理)

最近在网上看到有人问@ContextConfiguration("classpath:/bean.xml")中除了classpath这种还有其他的写法么,看他的意思是想从本地文件...

Android资源使用(android资源文件)

Android资源管理机制在Android的开发中,需要使用到各式各样的资源,这些资源往往是一些静态资源,比如位图,颜色,布局定义,用户界面使用到的字符串,动画等。这些资源统统放在项目的res/独立子...

如何深度理解mybatis?(如何深度理解康乐服务质量管理的5个维度)

深度自定义mybatis回顾mybatis的操作的核心步骤编写核心类SqlSessionFacotryBuild进行解析配置文件深度分析解析SqlSessionFacotryBuild干的核心工作编写...

@Autowired与@Resource原理知识点详解

springIOCAOP的不多做赘述了,说下IOC:SpringIOC解决的是对象管理和对象依赖的问题,IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系...

java的redis连接工具篇(java redis client)

在Java里,有不少用于连接Redis的工具,下面为你介绍一些主流的工具及其特点:JedisJedis是Redis官方推荐的Java连接工具,它提供了全面的Redis命令支持,且...