Android 模拟器已收到短信,为什么 SMS Retriever 仍然超时?
短信到达后,SMS Retriever 仍可能超时
系统短信应用收到消息,说明短信已到达设备。SMS Retriever 还需要在监听期间识别出符合当前应用要求的短信。如果始终没有匹配成功,约 5 分钟后就会返回 CommonStatusCodes.TIMEOUT。SMS Retriever API 说明
现有代码只展示了广播接收部分,没有提供短信正文、应用哈希、startSmsRetriever() 的调用位置或模拟器配置,暂时无法确定唯一原因。建议先检查短信内容和启动顺序。
1. 检查短信是否包含正确的应用哈希
SMS Retriever 要求验证短信满足以下条件:
- 长度不超过 140 字节,注意单位是字节。
- 包含一次性验证码。
- 包含用于识别当前应用的 11 个字符的应用哈希。
应用哈希由应用包名和签名证书共同生成。测试时,应使用与模拟器中实际安装的 APK 对应的哈希。如果 debug 和 release 使用不同证书,或者构建变体修改了包名,哈希也会变化。短信格式与应用哈希生成规则
可以先用简短短信测试,例如:
Your verification code is: 123456
YOUR_APP_HASH
YOUR_APP_HASH 是占位符,发送前必须替换成实际的 11 字符哈希。仅发送普通文字或验证码,无法验证 SMS Retriever 是否正常。
如果使用 Google Play App Signing,还要区分应用签名证书和上传证书,根据实际分发 APK 的签名证书计算哈希。
2. 先启动监听,再发送测试短信
BroadcastReceiver 负责处理结果。注册接收器后,还需要调用 startSmsRetriever()。建议按以下顺序测试:
- 注册
SmsBroadcastReceiver。 - 调用
startSmsRetriever()。 - 等待启动成功的日志。
- 再通过模拟器发送包含正确哈希的短信。
在 Activity 中可以加入以下诊断代码,假设接收器已经注册:
SmsRetriever.getClient(this)
.startSmsRetriever()
.addOnSuccessListener {
Log.d("SmsRetriever", "Retriever started; send the test SMS now")
}
.addOnFailureListener { error ->
Log.e("SmsRetriever", "Failed to start retriever", error)
}
这里的 addOnSuccessListener 表示监听已启动。短信匹配成功后,才会通过广播进入现有代码的 CommonStatusCodes.SUCCESS 分支。官方接入流程也要求先开始监听,再请求发送验证短信。客户端监听流程
每次重新测试时,都要重新启动监听,等启动成功后再发送一条新短信,不要依赖之前已收到的消息。
3. 检查模拟器和接收器配置
SMS Retriever 依赖 Google Play services。检查 AVD 是否使用包含 Google APIs 的兼容系统镜像,以及 Google Play services 是否可用。模拟器能接收普通短信,并不代表这套 API 的运行条件已经满足。Google Play services 测试环境要求
接收器还应注册 SmsRetriever.SMS_RETRIEVED_ACTION,并在等待结果期间保持有效。既然已经能够进入 TIMEOUT 分支,排查时应优先检查短信是否匹配,以及短信是否在监听启动后到达。
如果这些条件都已确认,可以使用同一 APK、同一条短信在具备 Google Play services 的真机上对照测试,缩小模拟器环境相关问题的范围。仅凭当前代码,无法断定模拟器不支持该功能。
4. 根据时间和日志判断下一步
如果从启动监听到出现 TIMEOUT 大约经过了 5 分钟,通常说明本轮监听没有得到符合要求的短信。重点核对短信正文、哈希和发送时间。
如果刚发短信就出现 TIMEOUT,记录每次启动监听和接收广播的时间,检查此前是否已启动过监听,以及当前看到的是否是较早一轮的超时结果。现有信息不足以确认这一点。
另外,可以将 extras!! 改成空值检查,减少异常广播导致崩溃的可能,但这不会解决短信匹配失败。验证成功后,应提取验证码交给服务器校验;正式环境也应避免记录完整验证码短信。
备注:内容仅供参考。
