일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- retrofit2
- 안드로이드
- 사용법
- #안드로이드
- #리사이클러뷰 어댑터
- #안드로이드 개발자 #안드로이드 신입 #개발자 이직 #안드로이드 면접 #신입 개발자
- 안드로이드 아키텍쳐
- 안드로이드해상도
- retrofi
- 안드로이드 익명클래스
- 빗버킷 #bitbucket #authorization failed #깃
- #SMS API #안드로이드 SMS #SMS Retriever
- 메모리릭
- 키스토어
- 안드로이드 메모리릭
- 리사이클러뷰 체크박스
- 구글맵안돼요
- #리사이클러뷰
- 레트로핏
- MVVM
- retrofit
- zeplin
- #android #안드로이드 #glide #gif #이미지다운로드
- #ContentProvider #App DataShare
- 클린아키텍쳐
- 제플린
Archives
- Today
- Total
땀이 삐질삐질 나는 개발 일기
SMS Retriever API 사용 본문
개요
- 2019 / 01 / 09 부터 구글 플레이 스토어상의 SMS 권한 정책이 변경
- 자동 인증을 위한 SMS Read, Write 권한 제거
- 자동 인증 기능 대안 API → SMS Retriever API
Reference : https://developers.google.com/identity/sms-retriever/verify
사용
SMS Retriever API 사용하여 문자 인증 순서
- 사용자 전화번호 획득 → HintRequest & PendingIntent
- SMS 검색기 시작 → SmsRetrieverClient & start()
- 서버에 인증 요청 → Client to Server
- 인증 번호 수신 → 지정된 Form 문자
<#> 내용 + HashCode(전체 HashCode의 앞 11글자)
EX) <#> Authorization Code : 3356 INRiCZwJsdf - 인증 및 서버 반환
이때 HashCode 구성하는 방법
- 앱의 공개 키 인증서를 소문자의 16 진수 문자열로 가져옵니다
- 패키지 명과, 공백 하나, 얻은 공개키 문자열을 하나의 스트링으로 합친 후
- SHA-256으로 암호화
- 인증 후 서버 회신
HashCode를 얻어오기 위한 Helper 클래스
(단, 헬퍼 클래스는 상용 앱 내에 호출되지 않아야 하고, HashCode를 얻은 후 클래스를 제거하는 것을 권함)
public class AppSignatureHelper extends ContextWrapper { public static final String TAG = AppSignatureHelper.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 AppSignatureHelper(Context context) { super(context); } /** * Get all the app signatures for the current package * @return */ public ArrayList<String> getAppSignatures() { ArrayList<String> appCodes = new ArrayList<>(); try { // Get all package signatures for the current package String packageName = getPackageName(); PackageManager packageManager = getPackageManager(); Signature[] signatures = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures; // For each signature create a compatible hash for (Signature signature : signatures) { String hash = hash(packageName, signature.toCharsString()); if (hash != null) { appCodes.add(String.format("%s", hash)); } } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Unable to find package to obtain hash.", e); } return appCodes; } 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(); // truncated into NUM_HASHED_BYTES hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES); // encode into Base64 String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP); base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR); Log.d(TAG, String.format("pkg: %s -- hash: %s", packageName, base64Hash)); return base64Hash; } catch (NoSuchAlgorithmException e) { Log.e(TAG, "hash:NoSuchAlgorithm", e); } return null; } } |
GoogleClientServie 객체 init
private GoogleApiClient mCredentialsApiClient; public void setGoogleServieClient() { mCredentialsApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .enableAutoManage(this, this) .addApi(Auth.CREDENTIALS_API) .build(); } |
각 전화번호 얻기
private static final int RESOLVE_HINT = 1000; // Construct a request for phone numbers and show the picker private void requestHint() { HintRequest hintRequest = new HintRequest.Builder() .setPhoneNumberIdentifierSupported(true) .build(); PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent( mCredentialsApiClient, hintRequest); startIntentSenderForResult(intent.getIntentSender(), RESOLVE_HINT, null, 0, 0, 0); } // Obtain the phone number from the result @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RESOLVE_HINT) { if (resultCode == RESULT_OK) { Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY); // credential.getId(); <-- will need to process phone number string } } } |
SMSClient 작성
//Set Start SmsRetrieverClient public void setSmsClient() { // Get an instance of SmsRetrieverClient, used to start listening for a matching // SMS message. SmsRetrieverClient client = SmsRetriever.getClient(this /* context */); // Starts SmsRetriever, which waits for ONE matching SMS message until timeout // (5 minutes). The matching SMS message will be sent via a Broadcast Intent with // action SmsRetriever#SMS_RETRIEVED_ACTION. Task<Void> task = client.startSmsRetriever(); // Listen for success/failure of the start Task. If in a background thread, this // can be made blocking using Tasks.await(task, [timeout]); task.addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // Successfully started retriever, expect broadcast intent // ... } }); task.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Failed to start retriever, inspect Exception for more details // ... } }); } |
브로드 캐스트 리시버
class SmsBrReceiver extends BroadcastReceiver { /* public void setTimeout() { h.postDelayed(r, MAX_TIMEOUT); }*/ @Override public void onReceive(Context context, Intent intent) { if (intent == null) { return; } String action = intent.getAction(); if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(action)) { Bundle extras = intent.getExtras(); Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS); switch (status.getStatusCode()) { case CommonStatusCodes.SUCCESS: String smsMessage = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE); break; case CommonStatusCodes.TIMEOUT: break; default: break; } } } } |
'개발 Tip' 카테고리의 다른 글
다른 앱과 Data Share하는 방법 Feat. ContentProvider (0) | 2019.05.17 |
---|---|
여러개의 EditText의 String 값을 깔끔하게 Null & Empty 검사하는 방법 (0) | 2019.05.16 |
안드로이드 RecyclerView Item Delete (0) | 2019.04.21 |
RecyclerView 와 Retrofit2를 사용해 영화 목록 얻어오기 (0) | 2019.04.11 |
LinkedTreeMap 을 DTO로 변환 시 발생하는 문제 (1) | 2019.03.21 |
Comments