转载使用 ContentObsever 拦截短信,获取短信内容
在一些应用上,比如手机银行,QQ,微信等,很多时候我们都需要通过发送验证码到手机上,然后把验证码填上去,然后才能成功地继续去做下面一步事情。
而如果每次我们都要离开当前界面,然后去查收短信,记住验证码,然后再回来输入到控件中,这感觉就会很麻烦,用户体验就会很差,而像微信等一些应用,则会在手机接到短信 后,将信息中的验证码给抽出来,帮我们将其填到对应的控件中,多方便,对吧。
这个功能就是通过ContentObserver来实现的。顾名思义,Content Observer,就是内容监听,它实现的功能就是对特定的Uri进行监听,当监听的Uri发生变化时,就能够根据开发者的意思去做相应的处理。
下面我们就利用一个小小的Demo来简单地看一下,Content Observer是如何应用的。
这个小Demo的功能就是会监听短信的到达,然后将短消息里面的内容放到一个TextView上面展示,具体效果如下面的GIF图片:
具体的步骤如下:
1)自定义一个类,它要继承ContentObserver类,并且实现其onChange方法:
public class SMSContentObserver extends ContentObserver{ private static final String TAG = "com.lms.codemo.SMSContentObserver"; private Handler mHandler; private Context mContext; private ContentResolver mContentResolver; private Uri uri = Uri.parse("content://sms/inbox"); private int mMsgCode; public SMSContentObserver(Handler handler) {
super(handler);
this.mHandler = handler;
} public SMSContentObserver(Handler handler, Context context, int msgCode){
super(handler);
this.mHandler = handler;
this.mContext = context;
this.mMsgCode = msgCode;
mContentResolver = mContext.getContentResolver();
} public void onChange(boolean selfChange) {
super.onChange(selfChange);
String[] projection = new String[] {"_id","address","body","type"};
Cursor cursor = mContentResolver.query(uri, projection, null, null, "date desc"); if(cursor == null){ }else if(!cursor.moveToFirst()){ }else{
do{
String msgBody = cursor.getString(cursor.getColumnIndex("body"));
int msgId = cursor.getInt(cursor.getColumnIndex("_id"));
String msgAddr = cursor.getString(cursor.getColumnIndex("address"));
String msgType = cursor.getString(cursor.getColumnIndex("type"));
Log.v(TAG, "msgId : " + msgId);
Log.v(TAG, "msgAddr : " + msgAddr);
Log.v(TAG, "msgBody : " + msgBody);
Log.v(TAG, "msgType : " + msgType);
Message message = Message.obtain();
message.what = mMsgCode;
message.obj = msgBody;
mHandler.sendMessage(message);
break;
}while(cursor.moveToNext());
cursor.close();
} } }
这个SMSContentObserver继承了ContentObserver,并且定义了一个包含context,handler和msgCode的构造函数,其中
1.1)context是为获得ContentResolver来查询系统短消息的Uri,
1.2)handler是为了将获取到的内容发送回UI线程,进行UI的更新,
1.3)msgCode是handler处理的消息代码,表明是处理短消息的消息。
ContentObserver的原理其实就在于监听指定Uri的变化,在这个类中,因为我们是要获取 收到的 短消息的内容,所以在这里要去查询短消息收件箱的内容,其URI定义如下:
private Uri uri = Uri.parse("content://sms/inbox");
当指定的Uri变化了, ContentObserver就会调用其onChange函数,我们可以看到在ContentObserver类中的关于onChange函数的定义:
/**
* This method is called when a content change occurs.
* <p>
* Subclasses should override this method to handle content changes.
* </p>
*
* @param selfChange True if this is a self-change notification.
*/
public void onChange(boolean selfChange) {
// Do nothing. Subclass should override.
}
在这里指出,这个方法就是在内容改变的时候会被调用,同时要求这个函数必须由子类来实现,因为具体的逻辑是我们自己来定义的。
在Onchange函数中,我们会通过context获得ContentResolver,按照日期的返序获得第一条短消息,然后通过Handler发送到UI主线程。真正在实际上应用的逻辑会更复杂,而不是单纯地将内容返回去,我们可以看到短消息的有几个主要的字段:
a)type,表明是发送(2)还是接收(1)
b)address,对应的号码
c)body,对应的消息内容
d)date,对应的日期
等等。
2)我们要将这个ConentObserver注册到对应的Context中,就跟注册广播一样啊,要在某个地方告诉系统,如果短消息内容变化了,你要告诉我一下,我好处理事情,对吧。
这个小demo里面,就是我们的主界面,MainActivity了,代码如下:
public class MainActivity extends Activity{ private static final String TAG = "com.lms.codemo.MainActivity"; private TextView tvShowMsg; private SMSContentObserver smsContentObserver; private static final int MSG_CODE = 1; private Handler mHandler = new Handler(){
public void handleMessage(Message msg){
if( MSG_CODE == msg.what){
String msgBody = (String) msg.obj;
Log.v(TAG, "msg_body: " + msgBody);
tvShowMsg.setText(msgBody);
}
}
}; protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
tvShowMsg = (TextView)findViewById(R.id.tvShowMsg); smsContentObserver = new SMSContentObserver(mHandler,this,MSG_CODE);
getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, smsContentObserver); } protected void onDestroy(){
super.onDestroy();
getContentResolver().unregisterContentObserver(smsContentObserver);;
}
2.1)在Activity中,我们主要就是创建了一个handler对象,将其还有context传给SMSContentObserver,这样,它才能将消息给传回来,在主线程中处理,处理很简单,将返回来的消息内容直接更新到TextView上面。
2.2)在Activity创建的时候,我们要创建实例化一个SMSContentObserver,然后调用ContentResolver的registerContentObserver方法,将指定的Uri绑定给它,这样,SMSContentObserver才知道它是要去监听这个Uri的内容,而在这里,当然就是监听短消息的内容了,如下:
Uri.parse("content://sms")
2.3)我们看一下这个函数的定义:
/**
* Register an observer class that gets callbacks when data identified by a
* given content URI changes.
*
* @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
* for a whole class of content.
* @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code>
* will also cause notifications to be sent. If <code>false</code> only changes to the exact URI
* specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values
* at or below the specified URI will also trigger a match.
* @param observer The object that receives callbacks when changes occur.
* @see #unregisterContentObserver
*/
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer)
{
registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
}
其中,中间这个参数notifyForDescendents的值如果为true呢,那么所有以指定Uri开头的Uri发生变化,都会触发指定的ContentObserver,就比如我们demo中,我们监听的其实是
“content://sms”,但其实真正变化的是,"conent://sms/inbox",但是因为我们设置为true了,所以我们就能够触发对应的事件,相反,如果设置为false,就不行了。
2.4)最后,如果我们不需要去监听内容的变化了,我们就要把它注销掉,跟广播其实一样的。
转载使用 ContentObsever 拦截短信,获取短信内容的更多相关文章
- 转载:Android自动化测试- 自动获取短信验证码
前言:android应用的自动化测试必然会涉及到注册登录功能,而许多的注册登录或修改密码功能常常需要输入短信验证码,因此有必要能够自动获得下发的短信验证码. 主要就是实时获取短信信息. android ...
- iOS点击获取短信验证码按钮
概述 iOS点击获取短信验证码按钮, 由于 Demo整体测试运行效果 , 整个修改密码界面都已展现, 并附送正则表达式及修改密码逻辑. 详细 代码下载:http://www.demodashi.com ...
- jQuery获取短信验证码+倒计时实现
jQuery 短信验证码倒计时 <script type="text/javascript" charset="utf-8"> $(function ...
- android自动获取短信验证码
前言:android应用的自动化测试必然会涉及到注册登录功能,而许多的注册登录或修改密码功能常常需要输入短信验证码,因此有必要能够自动获得下发的短信验证码.主要就是实时获取短信信息.android上获 ...
- 基于jquery的-获取短信验证码-倒计时
在制作短信验证的时候,需要做一个获取短信按钮,点击后显示倒计时, html代码如下: <input class="gain" type="button" ...
- PHP获取短信验证码
PHP如何获取短信验证码?以下是创蓝253短信平台下的PHP接口代码案例: <?php header("Content-type:text/html; charset=UTF-8& ...
- python+pymssql+selenium 获取短信验证码登录(实战练习)
登录页面输入手机号, 获取短信验证码(验证码有10分钟有效期) 1 连接sql server数据库,获取10分钟之内的有效短信验证码 2 页面输入手机号,并获取验证码.若存在有效验证码则输入验证码,若 ...
- android 获取短信验证码倒计时
android 获取短信验证码倒计时 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWVuZ2xlbGUxMzE0/font/5a6L5L2T/fonts ...
- 26.【转载】挖洞技巧:绕过短信&邮箱轰炸限制以及后续
邮箱轰炸可能对企业来说危害很小,但对用户危害很大.短信轰炸相比邮箱轰炸,带来的危害涉及到企业和用户. 那么这些问题都存在在哪些方面呢? ①:登录处 ②:注册处 ③:找回密码处 ④:绑定处 ⑤:活动领取 ...
随机推荐
- noip模拟赛 无题
分析:这道题和以前做过的模拟赛题很像:传送门. 对于前30%的数据可以直接暴力求,k=1的数据利用线段树求区间最大值,没有修改操作可以用主席树.100%的数据主席树是肯定用不了的,观察到K非常小,可以 ...
- easyUI pagination分页控件点击下一页后跳转到最后一页
easyui-pagination点击下一页直接跳转到最后一页的可能原因 今天做到聊天记录展示页面的时候发现一个bug:初次进入页面加载出第一页的数据,点击下一页的时候不是到第二页而是到最后一页. 如 ...
- Linux下汇编语言学习笔记22 ---
这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...
- Ubuntu 16.04使用百度云的方案
Ubuntu没有很好的解决方案,都是一些投机取巧的方案: 1.不建议安装百度云客户端,尤其对于免费用户来说,会限制速度. 2.可以使用网页版进行文件上传. 3.下载可以通过Chrome点击下载后,复制 ...
- Redis集群方案之主从复制(待实践)
Redis有主从复制的功能,一台主可以有多台从,从还可以有多台从,但是从只能有一个主.并且在从写入的数据不会复制到主. 配置 在Redis中,要实现主从复制架构非常简单,只需要在从数据库的配置文件中加 ...
- hibernate_Criteria_分页_去重
触发原因:实体类间存在一对多关系,并且在一这方加载多的时候用的加载模式是eager. 解决方法:1.非分页:criteria.setResultTransformer(Criteria.DISTINC ...
- dataTables 添加行内操作按钮
在上一篇博客中我们提到了用dataTables 做一个分页表格.今天进一步进阶,做一个行内带操作按钮的表格.效果如图. 记得最基础的实现方式是,我们要在js 中拼接字符串,嵌入一个带按钮的语句.但是现 ...
- Django学习系列之Form表单结合ajax
Forms结合ajax Forms的验证流程: 定义用户输入规则的类,字段的值必须等于html中name属性的值(pwd= forms.CharField(required=True)=<i ...
- HDU 2870 Largest Submatrix (单调栈)
http://acm.hdu.edu.cn/showproblem.php? pid=2870 Largest Submatrix Time Limit: 2000/1000 MS (Java/Oth ...
- 在head里的CSS link 竟然粗如今body里了?
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVhY2Vfb2Zfc291bA==/font/5a6L5L2T/fontsize/400/fill/I0 ...