휴대폰 인증시 인증번호 자동 입력하는 예제입니다.

 

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) {
            }
        });
    }
}

+ Recent posts