咨询:SmsRetriever能否在Android模拟器运行?回调未触发问题
解决SMS Retriever API模拟器测试时BroadcastReceiver不回调的问题
我之前也碰到过一模一样的问题,折腾了好半天才找到原因,给你几个核心的排查和解决方向:
1. 先确认短信格式完全符合要求
这是最容易踩坑的点!SMS Retriever API只会拦截包含应用签名哈希值的短信,格式必须满足:
- 短信内容可以包含任意文本,但末尾必须跟上你的应用的11位哈希值(比如
FA+9qCX9VSu) - 哈希值要单独放在一行,或者跟在文本最后,不能被其他内容截断
怎么获取这个哈希值?可以用Google官方提供的AppSignatureHelper类生成,代码大概是这样:
public class AppSignatureHelper extends ContextWrapper { private static final String TAG = "AppSignatureHelper"; private static final int NUM_HASHED_BYTES = 9; private static final int NUM_BASE64_CHAR = 11; public AppSignatureHelper(Context context) { super(context); } public ArrayList<String> getAppSignatures() { ArrayList<String> appCodes = 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.toByteArray()); if (hash != null) { appCodes.add(String.format("%s", hash)); } } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Unable to find package to obtain signature", e); } return appCodes; } private String hash(String packageName, byte[] signature) { String appInfo = packageName + " " + Base64.encodeToString(signature, Base64.NO_WRAP); try { MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); 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, "Unable to compute hash: " + e); } return null; } }
调用这个类的getAppSignatures()就能拿到你的应用的哈希值,注意debug和release签名的哈希是不一样的,模拟器用的是debug签名的哈希。
2. 检查BroadcastReceiver的注册是否正确
- 如果是动态注册:要确保在调用
SmsRetrieverClient.startSmsRetriever()之前完成注册,而且不要提前调用unregisterReceiver() - 如果是静态注册(推荐),必须在
AndroidManifest.xml里正确声明:
<receiver android:name=".YourSmsRetrieverReceiver" android:exported="true"> <intent-filter> <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED" /> </intent-filter> </receiver>
这里android:exported="true"必须加,因为是系统给你的广播接收器发消息,必须允许外部访问。
3. 模拟器手动发短信的局限性
很多Android模拟器(比如默认的AVD)手动发送短信的时候,并不会触发SMS Retriever的广播——因为这个API是监听运营商下发的短信通道,而手动发的短信不走这个流程。
解决方法是用adb命令模拟真实短信,比如:
adb shell am broadcast -a com.google.android.gms.auth.api.phone.SMS_RETRIEVED --es sms "你的验证码是123456。FA+9qCX9VSu"
或者用更贴近真实场景的短信发送命令:
adb shell service call isms 5 s16 "com.android.mms.service" s16 "+1234567890" s16 "【你的应用名】你的验证码是123456。FA+9qCX9VSu" s16 null s16 null
用adb发的短信会触发系统的短信接收流程,就能正常触发你的BroadcastReceiver了。
4. 其他排查点
- 检查模拟器的Google Play Services版本:必须是10.2以上的版本,建议更新到最新版
- 确认你的
onReceive()方法里的逻辑没有问题:比如有没有正确判断SmsRetriever.SMS_RETRIEVED_ACTION,有没有处理Status的不同状态(比如超时、成功) - 不需要申请
READ_SMS权限:SMS Retriever API不需要这个权限,别画蛇添足加了反而出问题
内容的提问来源于stack exchange,提问作者esilver
相关产品推荐
相关产品推荐

