Android 短信验证码自动填充
本文主要介绍国外google上线的app 短信自动填充方案。
本方案主要是使用google提出的,防止开发者使用SMS相关权限造成的用户信息泄露
目录
注意点:
1、本方式不适合华为手机,华为有自己的获取方式
2、本方式不需要添加任何短信权限
3、项目版本
开发成本:
Android代码
1、导库
1)在项目根目录的build.gradle中添加下面代码
2)项目级build.gradle引用库
2、注册广播
1)静态注册
2)动态注册
3、启动监听
4、广播代码
其他开发成本
短信模板 (短信后i按加上11位哈市值)
1)命令(mac 命令)
2)代码,放入项目中运行,打包、启动app(注意debug签名与正是签名包的不同,正式的hashcode 需要正式打包,然后打印出来))
注意点:
1、本方式不适合华为手机,华为有自己的获取方式
2、本方式不需要添加任何短信权限
3、项目版本
compileSdkVersion>=34
minSdkVersion>=19
开发成本:
app需要集成两个google库,后端只需要改短信模板,在短信后面添加11位hash值,hash值生成方式在下面链接可以看到
google开发地址(国内需要翻墙)
Android代码
1、导库
1)在项目根目录的build.gradle中添加下面代码
buildscript {repositories {...google()mavenCentral()}
}allprojects {repositories { google()mavenCentral()}
}
2)项目级build.gradle引用库
dependencies {implementation 'com.google.android.gms:play-services-auth:21.2.0'implementation 'com.google.android.gms:play-services-auth-api-phone:18.1.0'
}
2、注册广播
1)静态注册
<receiverandroid:name="<路径>.MySMSBroadcastReceiver"android:exported="true"android:permission="com.google.android.gms.auth.api.phone.permission.SEND"><intent-filter><action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED" /></intent-filter></receiver>
2)动态注册
if(smsBrod==null){smsBrod= MySMSBroadcastReceiver(this,null)}val intentFilter = IntentFilter();intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {this@TestAlendActivity.registerReceiver(smsBrod,intentFilter,SmsRetriever.SEND_PERMISSION,null, Context.RECEIVER_EXPORTED)}
3、启动监听
fun googleMSM() {val client = SmsRetriever.getClient(this)val task: Task<Void> = client.startSmsRetriever()task.addOnSuccessListener(OnSuccessListener<Void?> {Log.i("SMS_CON", "googleMSM addOnSuccessListener")if(smsBrod==null){smsBrod= MySMSBroadcastReceiver(this,null)}val intentFilter = IntentFilter();intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {this@TestAlendActivity.registerReceiver(smsBrod,intentFilter,SmsRetriever.SEND_PERMISSION,null, Context.RECEIVER_EXPORTED)}})task.addOnFailureListener(OnFailureListener {Log.i("SMS_CON", "googleMSM addOnFailureListener")})}
4、广播代码
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;import com.google.android.gms.auth.api.phone.SmsRetriever;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;import org.json.JSONException;
import org.json.JSONObject;import java.lang.ref.SoftReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** BroadcastReceiver to wait for SMS messages. This can be registered either* in the AndroidManifest or at runtime. Should filter Intents on* SmsRetriever.SMS_RETRIEVED_ACTION.*/
public class MySMSBroadcastReceiver extends BroadcastReceiver {public MySMSBroadcastReceiver() {}@Overridepublic void onReceive(Context context, Intent intent) {Log.i("SMS_CON", "googleMSM MySMSBroadcastReceiver action=" + intent.getAction());if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {Bundle extras = intent.getExtras();Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);Log.i("SMS_CON", "status =" + status);if(status!=null){switch (status.getStatusCode()) {case CommonStatusCodes.SUCCESS:// (Optional) Get SMS Sender address - only available in// GMS version 24.20 onwards, else it will return null
// String senderAddress = extras.getString(SmsRetriever.EXTRA_SMS_ORIGINATING_ADDRESS);// Get SMS message contentsString message = extras.getString(SmsRetriever.EXTRA_SMS_MESSAGE);// Extract one-time code from the message and complete verification// by sending the code back to your server.Log.i("SMS_CON", "message =" + message);if (message != null) {Pattern code = Pattern.compile("(\\d{6})");Matcher matcher = code.matcher(message);String otp = "";if (matcher.find()) {otp = matcher.group(0);} else {otp = message;}Log.i("SMS_CON", "otp =" + otp);Toast.makeText(context,"otp=\n"+otp,Toast.LENGTH_LONG).show();}break;case CommonStatusCodes.TIMEOUT:// Waiting for SMS timed out (5 minutes)// Handle the error ...Log.i("SMS_CON", "TIMEOUT =");break;}}}}
}
其他开发成本
短信模板 (短信后i按加上11位哈市值)
Hash值生成方式
1)命令(mac 命令)
keytool -exportcert -keystore keystory名称.jks -storepass 你的密码 -alias 别名 | xxd -p | tr -d "[:space:]" | echo -n 你的包名 `cat` | shasum -a 256 | tr -d "[:space:]-" | xxd -r -p | base64 | cut -c1-11
2)代码,放入项目中运行,打包、启动app(注意debug签名与正是签名包的不同,正式的hashcode 需要正式打包,然后打印出来))
aab文件也可以通过命令安装到手机,网上搜一下 bundletool.jar 这个工具
import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.util.Base64;
import android.util.Log;import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;public class AppSignatureHashHelper extends ContextWrapper {public static final String TAG = AppSignatureHashHelper.class.getSimpleName();private static final String HASH_TYPE = "SHA-256";public static final int NUM_HASHED_BYTES = 9;public static final int NUM_BASE64_CHAR = 11;public AppSignatureHashHelper(Context context) {super(context);}public ArrayList<String> getAppSignatures() {ArrayList<String> appSignaturesHashs = new ArrayList<>();try {String packageName = getPackageName();PackageManager packageManager = getPackageManager();Signature[] signatures = packageManager.getPackageInfo(packageName,PackageManager.GET_SIGNATURES).signatures;for (Signature signature : signatures) {String hash = hash(packageName, signature.toCharsString());if (hash != null) {appSignaturesHashs.add(String.format("%s", hash));}}} catch (Exception e) {Log.e(TAG, "Package not found", e);}return appSignaturesHashs;}@TargetApi(19)private static String hash(String packageName, String signature) {String appInfo = packageName + " " + signature;try {MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE);messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));byte[] hashSignature = messageDigest.digest();hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES);String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP);base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR);return base64Hash;} catch (NoSuchAlgorithmException e) {Log.e(TAG, "No Such Algorithm Exception", e);}return null;}
}
调用方式
String hashcodeStr= AppSignatureHashHelper(this).getAppSignatures()
上面会生成11位hash值,放在短信后面就行了
***以上是获取短信,短信自动填充代码就不写了,拿到字符串 设置到输入框就行,推荐按使用动态注册,可以给广播传入回调接口,处理返回的验证码(otp)
到这里就完成了,上面获取命令的方式是通过自己签名的方式,如果是让google生成签名,则需要去看链接里的步骤,比较详细
测试的话 可以让别人发短信给你 ,在app里会受到广播
相关文章:
Android 短信验证码自动填充
本文主要介绍国外google上线的app 短信自动填充方案。 本方案主要是使用google提出的,防止开发者使用SMS相关权限造成的用户信息泄露 目录 注意点: 1、本方式不适合华为手机,华为有自己的获取方式 2、本方式不需要添加任何短信权限 3、…...

数据库 MySQL 是否需要容器化?
容器的定义:容器是为了解决“在切换运行环境时,如何保证软件能够正常运行”这一问题。 目前,容器和 Docker 依旧是技术领域最热门的词语,无状态的服务容器化已经是大势所趋,同时也带来了一个热点问题被大家所争论不以…...

Kettle的安装及简单使用
Kettle的安装及简单使用一、kettle概述二、kettle安装部署和使用Windows下安装案例1:MySQL to MySQL案例2:使用作业执行上述转换,并且额外在表stu2中添加一条数据案例3:将hive表的数据输出到hdfs案例4:读取hdfs文件并将…...

Golang | Leetcode Golang题解之第420题强密码检验器
题目: 题解: func strongPasswordChecker(password string) int {hasLower, hasUpper, hasDigit : 0, 0, 0for _, ch : range password {if unicode.IsLower(ch) {hasLower 1} else if unicode.IsUpper(ch) {hasUpper 1} else if unicode.IsDigit(ch)…...
面试金典题3
URL化。编写一种方法,将字符串中的空格全部替换为%20。假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的“真实”长度。 示例 1: 输入:"Mr John Smith ", 13 输出:"Mr%20John%20Smith&…...

FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
Android早期的MediaPlayer控件对于网络视频的兼容性很差,所以后来单独推出了Exoplayer库增强支持网络视频,在《Android Studio开发实战:从零基础到App上线(第3版)》一书第14章的“14.3.3 新型播放器ExoPlayer”就详细介绍了Exoplayer库的详细…...
Python使用总结之py-docx将word文件中的图片保存,并将内容返回
Python使用总结之py-docx将word文件中的图片保存,并将内容返回 使用py-docx读取word文档的内容,其中包含标题、文本和图片等信息。该方法将标题和内容返回,并将文件中的图片保存到指定的文件夹中。 实现步骤 加载文件内容读取文件的段落对文…...

Radware 报告 Web DDoS 攻击活动
新一代 HTTPS 洪水攻击的频率和强度急剧增加,攻击者引入的复杂程度也在迅速提高。2024 年上半年,Web 分布式拒绝服务 (DDoS) 攻击的频率和强度显著增加。其中很大一部分活动可以归因于受政治紧张局势驱使的黑客活动分子。 众所周知,当今的黑…...

OpenCV运动分析和目标跟踪(2)累积操作函数accumulateSquare()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将源图像的平方加到累积器图像中。 该函数将输入图像 src 或其选定区域提升到2的幂次方,然后加到累积器 dst 中: dst ( …...

PCIe进阶之TL:Common Packet Header Fields TLPs with Data Payloads Rules
1 Transaction Layer Protocol - Packet Definition TLP有四种事务类型:Memory、I/O、Configuration 和 Messages,两种地址格式:32bit 和 64bit。 构成 TLP 时,所有标记为 Reserved 的字段(有时缩写为 R)都必须全为0。接收者Rx必须忽略此字段中的值,PCIe Switch 必须对…...

Linux之实战命令01:xargs应用实例(三十五)
简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【…...

Redisson实现分布式锁(看门狗机制)
目录 可重入锁: 锁重试和看门狗机制: 主从一致性: 首先引入依赖,配置好信息 3.使用Redisson的分布式锁 可重入锁: 可重入锁实现是通过redsi中的hash实现的,key依旧是业务名称加id,然后第一个…...

记录一次显卡驱动安装
1. 驱动安装 1.1. 查看适合的版本 apt-get update ubuntu-drivers devices输出结果: 1.2. 安装合适的驱动版本 根据上面输出的内容 apt-get install nvidia-driver-545完成后重启 reboot查看新的驱动 nvidia-smi2. 安装/升级cuda 在nvidia-smi中显示的CUDA…...
nginx的作用是什么
Nginx是一个轻量级、高性能的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,它的作用广泛且重要。以下是Nginx的主要作用: 1. 作为Web服务器 高效处理静态文件:Nginx对静态文件(如HTML、图片…...

【全网最全】2024年华为杯研赛B题成品论文获取入口(后续会更新)
您的点赞收藏是我继续更新的最大动力! 一定要点击如下的卡片,那是获取资料的入口! 点击链接加入【2024华为杯研赛资料汇总】:https://qm.qq.com/q/hMgWngXvcQhttps://qm.qq.com/q/hMgWngXvcQ你是否在寻找数学建模比赛的突破点&a…...

计算机网络(八) —— Udp协议
目录 一,再谈端口号 1.1 端口号 1.2 netsta命令 二,UDP协议 2.1 关于UDP 2.2 Udp协议格式 2.3 Udp协议特点 2.4 Udp的缓冲区 一,再谈端口号 http协议本质是“请求 - 响应”形式的协议,但是应用层需要先将数据交给传输层&…...

【Linux篇】TCP/IP协议(笔记)
目录 一、TCP/IP协议族体系结构 1. 数据链路层 (1)介绍 (2)常用协议 ① ARP协议(Address Resolve Protocol,地址解析协议) ② RARP协议(Reverse Address Resolve Protocol&…...
std::pair和std::tuple
提示:文章 文章目录 前言一、背景二、 2.1 2.2 总结 前言 前期疑问: 本文目标: 一、背景 最近 std::pair和std::tuple 二、用法 1.1 创建 看代码规范,提到:通过std::pair 和std::tuple ,函数可以同…...
Access denied for user ‘root‘@‘114.254.154.110‘ (using password: YES)
navicat 连接远程服务器报错 1045 - Access denied for user root114.254.154.110 (using password: YES)报错解释: 这个错误表示客户端从IP地址114.254.154.110尝试以用户’root’身份连接到MySQL服务器时,被拒绝访问。原因可能是密码错误、用户’roo…...

深度学习03-神经网络01-什么是神经网络?
神经网络的基本概念 人工神经网络(Artificial Neural Network,ANN): 是一种模仿生物神经网络的计算模型。由多个神经元(或称为节点)组成,这些节点通过不同的连接来传递信息。 每个神经元可以接…...
Redisson 分布式锁的使用详解
一、分布式锁的概述 1.1 分布式锁的背景 在单机系统中,Java 提供了 synchronized 和 Lock 等锁机制来确保并发情况下的线程安全。然而,在分布式系统中,多个服务实例运行在不同的物理或虚拟机上,无法直接使用这些本地的锁机制来控…...

计算机网络:物理层 --- 基本概念、编码与调制
目录 一. 物理层的基本概念 二. 数据通信系统的模型 三. 编码 3.1 基本概念 3.2 不归零制编码 3.3 归零制编码 3.4 曼切斯特编码 3.5 差分曼切斯特编码 编辑 四. 调制 4.1 调幅 4.2 调频 4.3 调相 4.4 混合调制 今天我们讲的是物理…...

使用Maven创建一个Java项目并在repository中使用
JDK环境:1.8.0_371 Maven环境 :Apache Maven 3.6.3 配置完成jdk和mvn后,进入到指定文件夹下执行如下语句: mvn archetype:generate -DgroupIdtop.chengrongyu -DartifactIdCyberSpace -DarchetypeArtifactIdmaven-archetype-quic…...

如何使用IIC外设(硬件IIC)
本文重点叙述如何使用芯片自带的 IIC 外设,即硬件 IIC,实现 IIC 通信。文章《IIC通信基础_cpu的iic通信-CSDN博客》 中,叙述了软件 IIC 通信和硬件 IIC 通信的区别, 并且重点叙述了 IIC 的通信协议。在使用软件进行 IIC 通信时&am…...

使用 Vue 3、Vite 和 TypeScript 的环境变量配置
使用 Vue 3、Vite 和 TypeScript 的环境变量配置 在开发现代前端应用时,环境变量是一个非常重要的概念。它可以帮助我们根据不同的环境(开发、测试、生产)配置不同的行为,比如 API 请求地址、调试选项等。在 Vue 3、Vite 和 Type…...

F28335 的串行外设接口(以下简称 SPI)
1 SPI 介绍 1.1 SPI 简介 1.2 F28335 的 SPI模块介绍 (1)F28335 的 SPI 特点...

科技引领未来生活——“光影漫游者”展览馆应用—轻空间
随着科技的快速发展,展览馆作为展示文化、科技和艺术的场所,正逐渐从传统的静态展示向高科技互动体验转变。由轻空间打造的“光影漫游者”展览馆,凭借其前沿的气承式结构和智能化系统,将参观者带入了一个未来感十足、充满科技魅力…...
ego-planner开源代码之启动参数介绍分析
ego-planner开源代码之启动参数介绍&分析 1. 源由2. 逻辑分析3. 启动参数section 1 三维地图尺寸section 2 里程计话题映射section 3 advanced_param.xml配置section 3.1section 3.2section 3.3section 3.4section 3.5section 3.6section 3.7section 3.8 section 4 轨迹服务…...
828 华为云征文|华为 Flexus 云服务器打造 Laverna 在线笔记应用
一、引言 在当今数字化时代,高效的笔记管理工具对于学习、工作和生活都至关重要。Laverna 作为一款功能强大的开源在线笔记应用,提供了 Markdown 编辑、加密支持等特性,是替代 Evernote 的绝佳选择。在 2024 年 9 月 14 日这个充满创新的日子…...
数据结构与算法-Trie树添加与搜索
trie树的使用场景 我们若需要制作一个通讯录的软件,使用常规树结构查询的复杂度为O(logn),但trie树的复杂度确与数据多少无关,与单词长度有关,这就大大缩减的查询的时间复杂度。 trie树的基本实现 基础结构 package com.study.trieDemo;i…...