휴대폰 인증시 인증번호 자동 입력하는 예제입니다.
2가지 방식이 있는데 SMS 퍼미션 받아서 사용하는 방법은 리젝대상입니다. 이 방식은 오는 문자를 전부 받아오는 방식입니다.
SmsRetriever 방식으로 해야 리젝 안당합니다.
1. SMS 문자내용이 80byte를 초과 하면 안됩니다. (MMS 안됨)
2. SMS 맨앞에 <#>가 반드시 포함되어야 한다.
3. SMS 맨마지막에 앱을 식별하는11글자 해시문자열을 포함해야한다.
(해시문자열은 앱에서 추출해서 사용하면 됩니다.)
** 주의 사항 : getAppSignatures 함수에서 hash 값을 받아올 때 Debug 모드와 Release 모드에 따라 다르게 추출됨.
ex) <#> [xxxxxxx] 본인확인 인증번호[123456] 입니다. sSJX3jjngYe
퍼미션 필요 없습니다.
AndroidManifest.xml 에 receiver 등록하는 예제들이 많은데 등록하면 두번 호출됩니다. 아래 이런거 등록하지 마세욤.
소스상에서 register 하기 때문에 AndroidManifest.xml에 등록 필요 없습니다.
<receiver
android:name=".Common.SmsReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
</intent-filter>
</receiver>
build.gradle
implementation 'com.google.android.gms:play-services-auth:21.2.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:18.1.0'
//implementation files('libs/play-services-auth-21.2.0.aar')
//implementation files('libs/play-services-auth-api-phone-18.1.0.aar')
BroadcastReceiver
public class SmsReceiver extends BroadcastReceiver {
// 문자에서 인증번호 6자 분리용 정규식 패턴
Pattern pattern = Pattern.compile("\\d{6}");
// 추출된 인증번호 저장용
public String authNumber = null;
// 인증 Hash 추출용
private final String HASH_TYPE = "SHA-256";
private final int NUM_HASHED_BYTES = 9;
private final int NUM_BASE64_CHAR = 11;
@Override public void onReceive(Context context, Intent intent) {
if(intent == null) {
return;
}
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
Status mStatus = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch (mStatus.getStatusCode()) {
case CommonStatusCodes.SUCCESS:
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
DLog.i(new Exception(), "SMS : " + message);
authNumber = null;
Matcher matcher = pattern.matcher(message);
if (matcher.find()) {
authNumber = matcher.group(0);
DLog.i(new Exception(), "SMS 인증번호 : " + authNumber);
}
break;
case CommonStatusCodes.TIMEOUT:
Log.e("error", "onReceive: failure");
break;
}
}
}
// Todo: SMS Hash 추출 (Package Hash : ex - sSJX3jjngYe)
public final String getAppSignatures(Context context) {
String hash = "";
try {
String packageName = context.getPackageName();
PackageManager packageManager = context.getPackageManager();
Signature[] signatures = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures;
for (android.content.pm.Signature signature : signatures) {
hash = getHash(packageName, signature.toCharsString());
if (hash != null) {
Log.d("==ss ", String.format("문자 마지막에 붙는 해쉬값 : %s", hash));
return hash;
}
}
} catch (PackageManager.NameNotFoundException var14) {
}
return hash;
}
private String getHash(String packageName, String signature) {
String appInfo = packageName + ' ' + signature;
try {
MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE);
messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));
byte[] hashSignature = Arrays.copyOfRange(messageDigest.digest(), 0, NUM_HASHED_BYTES);
String base64Hash = Base64
.encodeToString(hashSignature, Base64.NO_PADDING|Base64.NO_WRAP)
.substring(0, NUM_BASE64_CHAR);
return base64Hash;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
MainActivity
authNumber : 인증번호 6자리 값 입니다. SmsReceiver 클래스 변수로 값이 들어와 있는 상태이기 때문에 해당 값을 하이브리드 앱일 경우 웹으로 Javascript 로 보내주면 될듯합니다.
public class MainActivity extends AppCompatActivity {
private SmsReceiver smsReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Todo : SMS 문자 받아오기
smsReceiver = new SmsReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (authNumber != null) {
if (authNumber.isEmpty() == false) {
//JavaScript Interface 전송
Toast.makeText(context, "SMS : " + authNumber, Toast.LENGTH_SHORT).show();
/*
원인은 알 수 없으나 메세지 한번 들어오고 다시 보내면 문자가 안들어옴.
추측으로는 register 해제되는게 아닐까?
문자 받아서 처리후 다시 초기화 해주면 계속 받을 수 있어 이렇게 처리함.
*/
initSMSReceive();
}
}
}
};
initSMSReceive();
}
// Todo : SMS Receiver Register
private void initSMSReceive() {
SmsRetrieverClient client = SmsRetriever.getClient(this);
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(smsReceiver, intentFilter, Context.RECEIVER_EXPORTED);
} else {
registerReceiver(smsReceiver, intentFilter);
}
// 문자 뒤에 붙일 Hash 값. (고정값임)
// 이 Hash 값을 문자 마지막에 붙여주면 됨.
DLog.i(new Exception(), "Signatures Hash : " + smsReceiver.getAppSignatures(MainActivity.this));
}
});
task.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
}
});
}
}'Android(Java)' 카테고리의 다른 글
| [Java] ImageView Zoom In/Out (0) | 2024.07.03 |
|---|---|
| [Java] App Link / Deep Link Sceme 데이터 처리 (0) | 2024.06.18 |
| [Java] Permission 설정 및 거부시 처리 (0) | 2024.04.22 |
| [Java] 갤러리 이미지 추출하기 (0) | 2024.04.15 |
| [Java]WebView사용시 target=_blank 사용에 따른 onCreateWindow 호출되는 문제 (0) | 2024.04.12 |