安卓短信自动填充踩坑
安卓短信自动填充踩坑
前言
最近弄了个短信自动填充功能,一开始觉得很简单,不就是动态注册个广播接收器去监听短信消息不就可以了吗?结果没这么简单,问题就出在机型的适配上。小米的短信权限、荣耀的短信监听都是坑,暂时就用这两个手机测了,其他的遇到了再补充。
下面简单讲讲:
权限
申请权限
短信属于隐私权限,Android 6.0后需要动态申请权限。首先在manifest里面注册权限:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
在需要用的地方,动态申请下:
String[] smsPermission = {Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_SMS};
小米短信权限问题
本来这样权限问题就搞定了,但是在小米手机上就不行。小米手机会把短信归类到通知类权限里:

在 ContextCompat.checkSelfPermission 的时候会直接返回true,并且不会弹出权限对话框,而是在实际使用的时候才会咨询用户,按理说好像和我们逻辑没有冲突,但是在使用receiver进行监听前,不是得确保有权限么?实际效果也是,在没有权限时,不能获取到短信的广播。
小米短信权限解决
在网上找了找办法,好像也没多少博文,但是大致有了思路:不是用的时候才申请么?那我就先用一下,再去用receiver监听。下面是方法:
// 读取一下试试,能读取到就有权限
boolean flag = false;
try {Uri uri = Uri.parse("content://sms/inbox");ContentResolver cr = context.getContentResolver();String[] projection = new String[]{"_id"};Cursor cur = cr.query(uri, projection, null, null, "date desc");if (null != cur) {cur.close();}lag = true;
}catch (Exception e) {e.printStackTrace();
}
这里仅针对小米手机啊,对小米手机的判断我只是用 android.os.Build.MANUFACTURER 简单判断了下,如果有更高要求请查找资料。
使用Receiver进行监听
编写SmsReceiver
这里也是网上随便找了个代码,能用,但是在荣耀手机上却是偶尔能收到一次,后面几次就收不到了,打了log也没进入到onReceive中,这就很离奇了,排查了很久。同样的代码,在小米手机上是没问题的,那就只可能是适配问题了。
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;public class SmsReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//Toast.makeText(context, "收到信息", Toast.LENGTH_LONG).show();Log.d("SmsReceiver", "onReceive: " + intent.getAction());if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){//intent.getExtras()方法就是从过滤后的意图中获取携带的数据,// 这里携带的是以“pdus”为key、短信内容为value的键值对// android设备接收到的SMS是pdu形式的Bundle bundle = intent.getExtras();SmsMessage msg;if (null != bundle){//生成一个数组,将短信内容赋值进去Object[] smsObg = (Object[]) bundle.get("pdus");//遍历pdus数组,将每一次访问得到的数据方法object中for (Object object:smsObg){//获取短信msg = SmsMessage.createFromPdu((byte[])object);//获取短信内容String content = msg.getDisplayMessageBody();Log.d("SmsReceiver", "onReceive: content = " + content);//获取短信发送方地址String from = msg.getOriginatingAddress();Log.d("SmsReceiver", "onReceive: from = " + from);// TODO ...}}}}
}
使用方法:
// 使用广播进行监听
IntentFilter smsFilter = new IntentFilter();
smsFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
smsFilter.addAction("android.provider.Telephony.SMS_DELIVER");
if (smsReceiver == null) {smsReceiver = new SmsReceiver();
}
context.registerReceiver(smsReceiver, smsFilter);
接触监听,最好在收到短信的时候就取消注册广播:
context.unregisterReceiver(smsReceiver);
解决荣耀无法连续监听短信的问题
既然上面的方法没用了,只能找新的办法喽,网上很多提供了两种办法,第二种就是通过ContentResolver去监听短信添加的更新动作,其实也和广播类似,代码如下:
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.provider.Telephony;
import android.util.Log;import androidx.annotation.RequiresApi;@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public class ReadSmsObserver extends ContentObserver {private final Context context;public ReadSmsObserver(Handler handler, Context context) {super(handler);this.context = context;}private static final String SMS_INBOX_URI = "content://sms/inbox";//API level>=23,可直接使用Telephony.Sms.Inbox.CONTENT_URI,用于获取cusor// private static final String SMS_URI = "content://sms";//API level>=23,可直接使用Telephony.Sms.CONTENT_URI,用于注册内容观察者private static final String[] PROJECTION = new String[]{Telephony.Sms._ID,Telephony.Sms.ADDRESS,Telephony.Sms.BODY,Telephony.Sms.DATE};@Overridepublic void onChange(boolean selfChange, Uri uri) {super.onChange(selfChange);Log.d("ReadSmsObserver", "onChange: ");// 当收到短信时调用一次,当短信显示到屏幕上时又调用一次,所以需要return掉一次调用if(uri.toString().equals("content://sms/raw")){return;}// 读取短信收件箱,只读取未读短信,即read=0,并按照默认排序Cursor cursor = context.getContentResolver().query(Uri.parse(SMS_INBOX_URI), PROJECTION,Telephony.Sms.READ + "=?", new String[]{"0"}, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER);if (cursor == null) return;// 获取倒序的第一条短信if (cursor.moveToFirst()) {// 读取短信发送人String address = cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS));Log.d("ReadSmsObserver", "onChange: address = " + address);// 读取短息内容String smsBody = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY));Log.d("ReadSmsObserver", "onChange: smsBody = " + smsBody);// TODO 传递出去,最好切下线程}// 关闭cursor的方法cursor.close();}
}
用的时候要注册和取消注册:
// 使用ContentResolver进行监听
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {if (smsObserver == null) {smsObserver = new ReadSmsObserver(new SmsHandler(), context);}context.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, smsObserver);
}
取消注册:
context.getContentResolver().unregisterContentObserver(smsObserver);
结语
这些机型的兼容性搞起来真头疼,上面两种方法可以兼容起来使用,收到一条短信后直接取消注册就行了。
相关文章:
安卓短信自动填充踩坑
安卓短信自动填充踩坑 前言 最近弄了个短信自动填充功能,一开始觉得很简单,不就是动态注册个广播接收器去监听短信消息不就可以了吗?结果没这么简单,问题就出在机型的适配上。小米的短信权限、荣耀的短信监听都是坑,…...
【抽象类和接口的区别】
抽象类和接口都是Java中实现多态的机制,它们都是用来约束子类必须要实现的方法。但是它们有以下区别: 实现方式 实现方式:抽象类是一个类,而接口是一个接口。一个类只能继承一个抽象类,但可以实现多个接口。 构造方…...
接口导出文件功能
1.写接口 export function getExport(params) { return fetch({ url: ******.export, method: post, data: params, responseType:blob, }) } 2.编写前端页面 <el-button :loading"exportDisable" :disabled&quo…...
深圳大学计软《面向对象的程序设计》实验9 期中复习
A. 机器人变身(类与对象)【期中模拟】 题目描述 编写一个机器人类,包含属性有机器名、血量、伤害值、防御值、类型和等级。其中血量、伤害和防御和等级、类型相关: 普通型机器人,类型为N,血量、伤害、防…...
python之异步编程
一、异步编程概述 异步编程是一种并发编程的模式,其关注点是通过调度不同任务之间的执行和等待时间,通过减少处理器的闲置时间来达到减少整个程序的执行时间;异步编程跟同步编程模型最大的不同就是其任务的切换,当遇到一个需要等…...
为什么很多计算机专业大学生毕业后还会参加培训?
基于IT互联网行业越来越卷的现状,就算是科班出身,很多也是达不到用人单位的要求。面对这样的现实情况,有的同学会选择继续深造,比如考个研,去年考研人数457万人次,可见越来越的同学是倾向考研提升学历来达到…...
JUC并发编程之JMM_synchronized_volatile
目录 JUC并发编程之JMM_synchronized_volatile 什么是JMM模型? JMM和JVM的区别 JMM不同于JVM内存区域模型 主内存 工作内存 Java内存模型与硬件内存架构的关系 JMM存在的必要性 数据同步八大原子操作 同步规则分析 并发编程的可见性,原子性与有序…...
hashCode 和 equals 的处理
文章目录hashCode 和 equals 的处理1. 阿里巴巴编程规范要求2. equals和hashcode的分析2.1 Object方法2.2 只覆写(Override)equals带来的问题问题演示问题分析问题处理hashCode 和 equals 的处理 1. 阿里巴巴编程规范要求 2. equals和hashcode的分析 2…...
17. OPenGL实现旋转移动物体
1. 说明: 整体思路:如果想实现动态,可以使用一个矩阵和我们给定的坐标值进行相乘,实时的改变坐标值 类似于坐标的齐次变换,然后使用一个定时器,在规定时间内触发重新绘制的函数。 实际效果: OP…...
《SQL基础》14. 存储过程 · 存储函数
存储过程 存储函数存储过程基本语法变量系统变量用户定义变量局部变量if判断参数case判断while循环repeat循环loop循环游标条件处理程序存储函数存储过程 存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合。调用存储过程可以简化应用开发人员的工作,减…...
NFT Insider #87:The Sandbox 收购游戏开发工作室 Sviper,GHST 大迁徙即将拉开帷幕
引言:NFT Insider由NFT收藏组织WHALE Members(https://twitter.com/WHALEMembers)、BeepCrypto(https://twitter.com/beep_crypto)联合出品,浓缩每周NFT新闻,为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周…...
html部分codewhy网课学习笔记
day1 网页显示的过程和服务器 浏览器内核,也称为渲染引擎 head标签描述网页的原数据,如title shifttab是向前缩进 div>ul>li可以快速生成 <div> <ul> <li></li> </ul> </div> 在早期,单标签如<input>也可写为&l…...
电脑出问题了怎么重装系统修好
电脑在使用过程中经常会出现各种各样的问题,如系统崩溃、蓝屏、病毒感染等。这些问题如果不能及时得到解决,将会给用户带来很多麻烦和损失。小白一键重装系统是一个功能强大的工具,可以帮助用户快速解决电脑常见问题。下面我们就来详细介绍如…...
Nginx国密支持问题记录
文章目录添加国密支持可能出现的问题国密不生效,查看 Nginx 可执行文件路径是否正确证书无法解析Nginx无法启动添加国密支持 NGINX添加国密支持 添加国密支持可以直接按照官网的操作顺序操作即可 参考网址:https://www.gmssl.cn/gmssl/index.jsp 可能出…...
基于ensp的小型局域网网络搭建及需求分析
一 需求分析本实验的目的在于建立小型局域网。由于公司由财政部、人事部、科技部三个部门组成,分布在同一个交换机下。设计以下网络:三个个部门使用两台交换机连接,然后连接到汇聚交换机,再通过路由器与外网以及其他部门网络相连。…...
Kubernetes学习(二)Pod
创建Pod kubectl创建nginx pod 编写 nginx pod的yaml文件 apiVersion: v1 kind: Pod metadata:name: my-nginxlabels:name: my-nginx spec:containers:- image: nginxname: my-nginxresources:limits:memory: "128Mi"cpu: "500m"ports:- name: nginx-po…...
【Docker】docker | 迁移docker目录
一、场景说明1、物理机磁盘空间不够用了2、docker的镜像、容器、卷等资料的默认路径为: /var/lib/docker3、增加了数据盘挂在,需要将docker的全部资料更换个目录二、操作确认是否满足切换条件1)服务是否能够暂停,如果可以就OK2&am…...
day24_多线程进阶
今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 创建线程的几种方式 1) 继承 2) 实现Runnable 3) calla…...
Qt实现系统桌面目录下文件搜索的GUI:功能一:文件查找与现实
⭐️我叫恒心,一名喜欢书写博客的研究生在读生。 原创不易~转载麻烦注明出处,并告知作者,谢谢!!! 这是一篇近期会不断更新的博客欧~~~ 有什么问题的小伙伴 欢迎留言提问欧。 功能点一:文件查找与…...
有关数据库的一级、二级、三级封锁协议
一级封锁协议 一级封锁协议是指,事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK).一级封锁协议可防止丢失修改,并保证事务T是可恢复的。在…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
