对读取短信验证码封装库的思考

简介: 在我的目前阶段,许多开源项目的产生都是直接来源于项目本身的需求,比如这次要讲的读取短信验证码的封装库。项目目前挂在 github 上的公司组织下,地址为:https://github.com/parkingwang/sms-captcha。

在我的目前阶段,许多开源项目的产生都是直接来源于项目本身的需求,比如这次要讲的读取短信验证码的封装库。

项目目前挂在 github 上的公司组织下,地址为:https://github.com/parkingwang/sms-captcha。使用方法很简单,在界面创建时注册:

mCaptchaObserver = SmsCaptcha.with(this)
        .captchaLength(4)
        .addressLike("10657%")
        .fillTo(mSmsCode)
        .createAndRegister();

界面销毁时移除注册:

mCaptchaObserver.unregister();

业务的实现

这里读取短信验证码的实现说来也很简单,核心逻辑就是动态注册一个短信的内容观察者,然后继承 ContentObserver,在收到回调之后查询指定号码的未读短信,通过正则过滤出验证码出来。最核心的代码如下:

do {
    // 获取短信内容
    final String body = cursor.getString(cursor.getColumnIndex(BODY));
    // 使用正则表达式匹配出验证码
    final Matcher matcher = mCaptchaPattern.matcher(body);
    if (!matcher.find() || matcher.groupCount() != 1) {
        // 匹配不出来则找下一条
        continue;
    }
    String code = matcher.group(1);
    if (TextUtils.isDigitsOnly(code)) {
        if (mCaptchaListener != null) {
            // 找到后回调并退出
            mCaptchaListener.onCaptchaReceived(code);
        }
        break;
    }
} while (cursor.moveToNext());

完整的代码可参考项目:https://github.com/parkingwang/sms-captcha。全部代码也很简单,目前就两个类,加一起也就两百多行。

封装的思考

在做好了之后,我就想到如何把它造成一个通用的轮子,以便可以在其他项目中使用。

验证码的正则表达式

首先,从内容中匹配出验证码,最简单有效的就是使用正则表达式了,所以,接下来的思考就是如何设计拼接出尽可能通用的正则表达式。
应用的验证码的文本格式通常按顺序包含如下信息:
包含应用名称的信息,“验证码”这三个字,连续的多位数字,其他内容。
需要注意的是,在这个“其他内容”中,也可能会包含多位数字,比如像这样的:如有疑问,请拨打客服电话xxx-xxxxxxxx。像这样的信息,如果你的正则表达式是如下这样的:

.*应用名称.*验证码.*\d{4}.*

由于正则表达式默认是贪婪模式,那么它就会匹配到后面的电话号码中的数字。所以需要使验证码这三个字与数字之间的搜索为懒惰模式,即加上问号,改为如下:

.*应用名称.*验证码.*?\d{4}.*

这种情况是确实存在的。当你是为一个项目写代码时,可以不考虑。但是当你是想做一个 SDK 给多个项目使用时,却应当尽可能地考虑存在的情况。尽可能的考虑严谨、周全。

另外,如果验证码的位数不固定,可能是 4-6 位之间,则匹配则为 \d{4,6},则如果都是4位,也可以写为 \d{4,4}

短信的查询条件

注册了短信的内容观察者之后,会在短信内容会变化时回调,然后在收到回调之后,我们就需要按照条件去查询符合结果的短信,并检索出内容里包含的验证码。这里的查询条件也简单说一下。
首先,要查询的短信验证码必须是未读的,因为已读的短信可能是过去已经使用的,对我们没有任何意义。
其次,有些应用的验证验证码的发送号码可能不是固定的,比如更换了短信服务端,所以应允许发送号码的模糊查询,可以查询以什么开头的号码。所以查询条件应该可以指定为:

address=xxxxxx AND read=0

address LIKE %xxxxx AND read=0

这两种模式。

剩下的封装工作就都比较简单,就不足一谈了。

对产品的思考

当你把代码实现之后,跑到手上的华为测试机,可能会发现,什么效果都没有。是代码出问题了吗?
再细查,会发现查询短信的时候,都没有查询出手机接收到的那条验证码短信,然后再试图扩大查询范围,发现手机里凡是涉及到验证码的短信都查询不出来。
各种尝试无果之后,你点开了短信里的“设置”,发现有个“高级”,点进去之后看到了一个“验证码安全保护”的功能,底下有一行小字“禁止第三方应用读取和使用验证码信息”的描述,这个功能是打开的状态。你恍然大悟,把它给关掉,再一试,果然验证码出来了。

但是这个功能是手机厂商默认打开的,而功能这么隐蔽,用户一般是不会去关闭的,那么怎么解决这个问题呢?
获取短信验证码的方法必然存在多种。之前负责对应项目的前同事,在获取不到验证码之后并没有细究原因,而是转向了另一种获取验证码的方式——通过截取通知栏的内容,从中获取验证码。

然而这种方式,它首先需要让用户授权应用读取通知栏内容的权限。这是一个很隐蔽也很敏感的权限,一旦你同意了,就意味着这个应用可以读取到所有应用发送到通知栏上的内容。而且打开了这个权限之后,用户自己很难再找到这个授权的地方去关闭它,所以它会是一个引起一些敏感用户不适的一个坑。

是不是要采取这种方式,我们回归到读取验证码本身这条产品需求上。
关于程序员对产品的思考,在去年与一个厦门的朋友聊天时,很同意他的一些观点。程序员需要有产品思维,需要有自己对产品的思考,去思考它的出发点。没有一点产品思维的话,以后的提升空间是有限的。
回到原来的话题上。这条需求是为了自动填充验证码,减少用户的输入,从而提升用户体验。
那么,为了实现这一点,而去要求用户去打开一个可能有些用户觉得特别敏感的权限,并且事后用户自己很难去关闭它,是提升了用户体验还是存在着损害用户体验或引起敏感用户对应用安全的不适感的风险呢?要知道,即便是支付宝或微信,用户都会怀疑其是否窃听、偷调摄像头、分析聊天内容,更不用说我们这种目前用户级别很小的应用了。

另一方面,自动填充验证码,这其实是一个可选的需求。换句话说,即便不能读取到验证码帮用户输入,用户也不会因此而觉得应用存在问题,可能许多用户甚至都不会想到这个问题。所以应避免把它给做得太重,从而舍本逐末。

目录
相关文章
方法:如何一次性把大量号码一键导入手机通讯录?
第一步:一堆大量号码一键导入手机通讯录,需要借助软件,金芝号码提取导入助手。第二步:在电脑上打开你的表格,里面的大量号码你先复制好,如果有对应的铭字你也复制好,然后分别粘贴进前面说的软件,接着你点软件上的“通讯录转换”,就可以得到一个通讯录文件。第三步:你从电脑上把这个文件发给你的手机,在手机上打开,就可以一键批量把大量号码导入通讯录。电脑文件怎么发送给手机,这个很容易呀,你的电脑上不是有电脑Q或者电脑微吗?发给你的手机微或者手机q就ok了,多方便!
方法:如何一次性把大量号码一键导入手机通讯录?
|
9月前
微信录音上传至七牛云控制器代码
微信录音上传至七牛云控制器代码
58 0
|
7月前
|
移动开发
微信h5扫码接口范例:使用localStorage防止扫码后表单其他内容丢失
微信h5扫码接口范例:使用localStorage防止扫码后表单其他内容丢失
72 0
|
物联网 开发者
演示读取TypeA TypeB nfc卡号|学习笔记
快速学习演示读取TypeA TypeB nfc卡号
485 0
演示读取TypeA TypeB nfc卡号|学习笔记
|
Java
java实现手机邮箱格式验证
java实现手机邮箱格式验证
304 0
|
小程序 开发者
微信小程序模板消息接口下线了,不用慌,调用统一服务消息接口来实现相同功能
做过微信开发的应该都有一点感触,就是他的开发文档不是一成不变的,接口有时候会被下线,但也不是一下子就不能用了,一般会兼容旧接口,然后提醒你使用新接口有更多好处。如果接口真的直接下线了,也会提供另一种能够实现相同功能的接口给你替换。所以有天你以为代码都写好了,没有bug了,悠哉悠哉的时候,忽然产品经理说微信的哪个接口不能用了,快去改一下,不要惊讶,老老实实去改就对了哈。
636 0
微信小程序模板消息接口下线了,不用慌,调用统一服务消息接口来实现相同功能
|
存储 JSON 小程序
unicloud云函数开发微信客服消息自动回复图片消息(完整步骤)
unicloud云函数开发微信客服消息自动回复图片消息(完整步骤)
349 0
unicloud云函数开发微信客服消息自动回复图片消息(完整步骤)
|
小程序 前端开发 JavaScript
解决微信小程序MQTT通讯真机调试失败的问题附加可用代码
原因:模拟器上测试可以,选中了不校验合法域名,真机调试没能连接服务器,解决思路换了个mqtt.js 可参考 https://unpkg.com/mqtt@2.18.8/dist/mqtt.min.js 废话不多说!上代码 前端部分自己改改就可以用了,我懒得改了 微信小程序index.wxml <view style="width: 750rpx;height:330rpx;"> <image src="https://img-blog.csdnimg.cn/295062b06acc
230 0
|
存储 Android开发
方法:一键把一堆手机号码一次性快速导入手机通讯录
手机是人们日常沟通常用的工具,所以自然就要用到手机里面的通讯录联系。因此我们常要把别人的号码存入到手机通讯录里面,如果只是存五个十个那就动动手指就可以了。但是如果你想存把一个电脑excel表格里面的几百个、几千个、几万个等数量级别的联系人一键导入手机通讯录,显然手动一个个来存入是不现实的。我这里演示,通过借助网上常见的便捷工具软件,金芝号码提取导入助手,代替你手动工作来快速完成这个工作,如何一键把一堆手机号码一次性快速导入手机通讯录,省事省时省力。下面做个操作过程的图文讲解。
3129 0
方法:一键把一堆手机号码一次性快速导入手机通讯录