写在开头
google官方介绍 如果在没有读写短信权限的情况下获取用户的短信验证码呢?google为我们提供了SMSRetrieverAPI这个Api。解决了我们在用户收到短信后自动回填界面的需求。但是google为了安全性,短信格式需要时固定的,那么我们先来看下短信的固定格式!
短信格式
短信固定格式(#号可以不要,sha256一定需要) <#> Your ExampleApp code is: 123ABC78 FA+9qCX9VSu
google要求我们的短信:
- 不能超过140个字节
- 包含一个11个字符的哈希字符串来标识您的应用(也就是上文的sha256)
sha256如何生成
网上通用的生成方式,总结了一个工具类AppSignatureHashHelper
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;
}
}
接下来我们要开始集成SMSRetrieverAPI了
首先我们要依赖google的两个库才能使用这个功能
dependencies {
implementation 'com.google.android.gms:play-services-auth:19.2.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.1'
}
然后要通过google的系统广播的action–SmsRetriever.SMS_RETRIEVED_ACTION和SmsRetriever实现监听的需求
接下来第一步 先创建SMSReceiver这个BroadcastReceiver接收系统给我推送的SMS广播,并创建OTPReceiveListener接口来实现监听结果的返回,代码如下:
public class SMSReceiver extends BroadcastReceiver {
private OTPReceiveListener otpListener;
public void setOTPListener(OTPReceiveListener otpListener) {
this.otpListener = otpListener;
}
@Override
public void onReceive(Context context, Intent intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch (status.getStatusCode()) {
case CommonStatusCodes.SUCCESS:
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
if (otpListener != null) {
otpListener.onOTPReceived(message);
}
break;
case CommonStatusCodes.TIMEOUT:
if (otpListener != null) {
otpListener.onOTPTimeOut();
}
break;
case CommonStatusCodes.API_NOT_CONNECTED:
if (otpListener != null) {
otpListener.onOTPReceivedError("API NOT CONNECTED");
}
break;
case CommonStatusCodes.NETWORK_ERROR:
if (otpListener != null) {
otpListener.onOTPReceivedError("NETWORK ERROR");
}
break;
case CommonStatusCodes.ERROR:
if (otpListener != null) {
otpListener.onOTPReceivedError("SOME THING WENT WRONG");
}
break;
}
}
}
public interface SMSReceiveListener {
void onSMSReceived(String otp);
void onSMSTimeOut();
void onSMSReceivedError(String error);
}
}
第二步的话我们要主动开启这个监听:
private void startSMSListener() {
try {
smsReceiver = new SMSReceiver();
smsReceiver.setOTPListener(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);
this.registerReceiver(smsReceiver, intentFilter);
SmsRetrieverClient client = SmsRetriever.getClient(this);
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
}
});
task.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
实现接口的方法获取结果:
@Override
public void onSMSReceived(String otp) {
}
@Override
public void onSMSTimeOut() {
}
@Override
public void onSMSReceivedError(String error) {
}
写在最后
这种方式不是一定会成功的,google告诉我们可以检测广播意图是使用短信API通过添加com.google.android.gms.auth.api.phone.permission.SEND允许你的接收SMS。此权限设置在 Google Play 服务 19.8.31 或更高版本中可用。也就是低于Google Play 服务 19.8.31 的手机是不能使用的,不过作为辅助功能,也可以了。。
|