Android용 앱 플립

OAuth 기반 App Flip 연결(App Flip)은 Android 앱을 Google 계정 연결 흐름에 삽입합니다. 기존 계정 연결 흐름에서는 사용자가 브라우저에 자격 증명을 입력해야 합니다. App Flip을 사용하면 Android 앱에 대한 사용자 로그인이 지연되어 기존 인증을 활용할 수 있습니다. 사용자가 앱에 로그인한 경우 계정을 연결하기 위해 자격 증명을 다시 입력할 필요가 없습니다. Android 앱에서 App Flip을 구현하려면 최소한의 코드 변경이 필요합니다.

이 문서에서는 앱 플립을 지원하도록 Android 앱을 수정하는 방법을 배웁니다.

샘플 사용해보기

연결 앱 플립 샘플 응용 프로그램은 안드로이드에 통합을 연결하는 응용 프로그램의 플립 호환 계정을 보여줍니다. 이 앱을 사용하여 Google 모바일 앱에서 수신되는 App Flip 의도에 응답하는 방법을 확인할 수 있습니다.

샘플 응용 프로그램은과 통합 사전 구성되어 안드로이드 앱 플립 테스트 툴 당신이 구성 구글 계정 연결하기 전에 앱 플립과 안드로이드 응용 프로그램의 통합을 확인하는 데 사용할 수 있습니다. 이 앱은 App Flip이 활성화되었을 때 Google 모바일 앱에 의해 트리거된 인텐트를 시뮬레이션합니다.

작동 원리

App Flip 통합을 수행하려면 다음 단계가 필요합니다.

  1. Google 앱 확인은 귀하의 응용 프로그램은 패키지 이름을 사용하여 장치에 설치되어있는 경우.
  2. Google 앱은 패키지 서명 검사를 사용하여 설치된 앱이 올바른 앱인지 확인합니다.
  3. Google 앱은 앱에서 지정된 활동을 시작하기 위한 인텐트를 빌드합니다. 이 인텐트에는 연결에 필요한 추가 데이터가 포함됩니다. 또한 Android 프레임워크를 통해 이 인텐트를 해결하여 앱이 App Flip을 지원하는지 확인합니다.
  4. 앱은 요청이 Google 앱에서 오는지 확인합니다. 이를 위해 앱은 패키지 서명과 제공된 클라이언트 ID를 확인합니다.
  5. 앱이 OAuth 2.0 서버에서 인증 코드를 요청합니다. 이 흐름이 끝나면 승인 코드 또는 오류를 Google 앱에 반환합니다.
  6. Google 앱은 결과를 검색하고 계정 연결을 계속합니다. 인증 코드가 제공되면 브라우저 기반 OAuth 연결 흐름에서와 동일한 방식으로 서버 간 토큰 교환이 발생합니다.

App Flip을 지원하도록 Android 앱 수정

앱 플립을 지원하려면 Android 앱에서 다음 코드를 변경하세요.

  1. 추가 <intent-filter> 사용자에 AndroidManifest.xml 앱 플립 의도 필드에 입력 한 값과 일치 액션 문자열로 파일.

    <activity android:name="AuthActivity">
      <!-- Handle the app flip intent -->
      <intent-filter>
        <action android:name="INTENT_ACTION_FROM_CONSOLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
    </activity>
    
  2. 호출 앱의 서명을 확인합니다.

    private fun verifyFingerprint(
            expectedPackage: String,
            expectedFingerprint: String,
            algorithm: String
    ): Boolean {
    
        callingActivity?.packageName?.let {
            if (expectedPackage == it) {
                val packageInfo =
                    packageManager.getPackageInfo(it, PackageManager.GET_SIGNATURES)
                val signatures = packageInfo.signatures
                val input = ByteArrayInputStream(signatures[0].toByteArray())
    
                val certificateFactory = CertificateFactory.getInstance("X509")
                val certificate =
                    certificateFactory.generateCertificate(input) as X509Certificate
                val md = MessageDigest.getInstance(algorithm)
                val publicKey = md.digest(certificate.encoded)
                val fingerprint = publicKey.joinToString(":") { "%02X".format(it) }
    
                return (expectedFingerprint == fingerprint)
            }
        }
        return false
    }
    
  3. 인텐트 매개변수에서 클라이언트 ID를 추출하고 클라이언트 ID가 예상 값과 일치하는지 확인하십시오.

    private const val EXPECTED_CLIENT = "<client-id-from-actions-console>"
    private const val EXPECTED_PACKAGE = "<google-app-package-name>"
    private const val EXPECTED_FINGERPRINT = "<google-app-signature>"
    private const val ALGORITHM = "SHA-256"
    ...
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val clientId = intent.getStringExtra("CLIENT_ID")
    
        if (clientId == EXPECTED_CLIENT &&
            verifyFingerprint(EXPECTED_PACKAGE, EXPECTED_FINGERPRINT, ALGORITHM)) {
    
            // ...authorize the user...
        }
    }
    
  4. 승인에 성공하면 결과 승인 코드를 다시 Google에 반환합니다.

    // Successful result
    val data = Intent().apply {
        putExtra("AUTHORIZATION_CODE", authCode)
    }
    setResult(Activity.RESULT_OK, data)
    finish()
    
  5. 오류가 발생하면 대신 오류 결과를 반환합니다.

    // Error result
    val error = Intent().apply {
        putExtra("ERROR_TYPE", 1)
        putExtra("ERROR_CODE", 1)
        putExtra("ERROR_DESCRIPTION", "Invalid Request")
    }
    setResult(-2, error)
    finish()
    

출시 의도의 내용

앱을 실행하는 Android 인텐트에는 다음 필드가 포함됩니다.

  • CLIENT_ID ( String ) : Google은 client_id 귀하의 응용 프로그램에 등록.
  • SCOPE ( String[] ) : 요청 범위의 목록.
  • REDIRECT_URI ( String ) : 리디렉션 URL.

응답 데이터의 내용

구글 응용 프로그램에 반환되는 데이터를 호출하여 응용 프로그램에 설정되어 setResult() . 이 데이터에는 다음이 포함됩니다.

  • AUTHORIZATION_CODE ( String ) : 인증 코드 값입니다.
  • resultCode ( int ) : 통신하는 프로세스의 성공 또는 실패는 다음 값 중 하나를 취
    • Activity.RESULT_OK : 성공을 나타냅니다 인증 코드가 반환됩니다.
    • Activity.RESULT_CANCELLED : 사용자가 작업을 취소 한 신호 것이다. 이 경우 Google 앱은 인증 URL을 사용하여 계정 연결을 시도합니다.
    • -2 : 에러가 발생했음을 나타낸다. 다양한 유형의 오류가 아래에 설명되어 있습니다.
  • ERROR_TYPE ( int ) : 오류 유형 다음 값 중 하나를 취
    • 1 : 복구 할 수없는 오류 : 구글 앱이 인증 URL을 사용하여 연결 계정을 시도합니다.
    • 2 : 복구 할 수없는 오류 : Google 앱의 중단 및 계정 연결.
    • 3 : 잘못되었거나 누락 된 요청 매개 변수.
  • ERROR_CODE ( int ) : 오류의 성격을 나타내는 정수. 각 오류 코드 수단은, 참고하여주십시오을 확인하려면 오류 코드 테이블 .
  • ERROR_DESCRIPTION ( String , 선택적) : 오류를 설명 읽을 상태 메시지.

대한 값 AUTHORIZATION_CODE 때 예상 resultCode == Activity.RESULT_OK . 다른 모든 경우의 값 AUTHORIZATION_CODE 비어 있어야합니다. 경우 resultCode == -2 , 다음 ERROR_TYPE 값은 인구가 될 것으로 예상된다.

오류 코드 표

아래 표는 다양한 오류 코드와 각각이 복구 가능한 오류인지 또는 복구 불가능한 오류인지를 보여줍니다.

에러 코드 의미 복구 가능 복구 불가능
1 INVALID_REQUEST
2 NO_INTERNET_CONNECTION
3 OFFLINE_MODE_ACTIVE
4 CONNECTION_TIMEOUT
5 INTERNAL_ERROR
6 AUTHENTICATION_SERVICE_UNAVAILABLE
8 CLIENT_VERIFICATION_FAILED
9 INVALID_CLIENT
10 INVALID_APP_ID
11 INVALID_REQUEST
12 AUTHENTICATION_SERVICE_UNKNOWN_ERROR
13 AUTHENTICATION_DENIED_BY_USER
14 CANCELLED_BY_USER
15 FAILURE_OTHER
16 USER_AUTHENTICATION_FAILED

모든 오류 코드의 경우를 통해 오류 결과를 반환해야합니다 setResult 적절한 대체가 trigerred되어 있는지 확인 할 수 있습니다.