Android용 앱 플립

OAuth 기반 앱 플립 연결 (앱 플립)은 Google 계정 연결 흐름 기존 계정 연결 흐름에서는 브라우저에 사용자 인증 정보를 입력할 수 있습니다. 앱 플립 사용 시 Android 앱에 로그인할 수 있는데, 이렇게 하면 기존의 있습니다. 사용자가 앱에 로그인되어 있으면 사용자 인증 정보를 다시 입력하여 계정을 연결합니다. 최소한의 코드 양 변경사항이 없습니다.

이 문서에서는 Android 앱을 수정하여 앱 플립

샘플 사용해 보기

앱 플립 연결 샘플 앱 은 Android에서 앱 플립과 호환되는 계정 연결 통합을 보여줍니다. 나 이 앱을 사용하여 Google 모바일 앱

샘플 앱은 App Flip Test Tool과 통합되도록 사전 구성되어 있으며 Android 이는 Android 앱과 앱의 통합을 확인하는 데 사용할 수 있는 Google과의 계정 연결을 구성하기 전에 뒤집으세요. 이 앱은 앱 플립이 사용 설정된 경우 Google 모바일 앱에 의해 트리거되는 인텐트를 반환합니다.

작동 방식

앱 플립 통합을 실행하려면 다음 단계를 따라야 합니다.

  1. Google 앱은 다음을 사용하여 앱이 기기에 설치되어 있는지 확인합니다. 패키지 이름을 입력합니다.
  2. Google 앱은 패키지 서명 검사를 사용하여 설치된 올바른 앱인지 확인합니다.
  3. Google 앱은 앱에서 지정된 활동을 시작하는 인텐트를 빌드합니다. 이 인텐트에는 연결에 필요한 추가 데이터가 포함되어 있습니다. 또한 를 통해 이 인텐트를 해결하여 앱이 앱 플립을 지원하는지 확인합니다. Android 프레임워크입니다.
  4. 요청이 Google 앱에서 비롯되는지 앱이 확인합니다. 이렇게 하려면 앱이 패키지 서명과 제공된 클라이언트 ID를 확인합니다.
  5. 앱에서 OAuth 2.0 서버로부터 승인 코드를 요청합니다. 인증 코드 또는 오류를 반환합니다. Google 앱
  6. Google 앱은 결과를 검색하고 계정 연결을 계속 진행합니다. 만약 승인 코드가 제공되면 토큰 교환은 브라우저 기반 OAuth 연결에서와 동일한 방식으로 있습니다.

앱 플립을 지원하도록 Android 앱 수정

앱 플립을 지원하려면 Android 앱의 코드를 다음과 같이 변경합니다.

  1. 작업으로 AndroidManifest.xml 파일에 <intent-filter>를 추가합니다. 앱 플립 인텐트 입력란에 입력한 값과 일치하는 문자열을 반환합니다.

    <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. 호출 앱의 서명 유효성 검사

    <ph type="x-smartling-placeholder">
    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입니다.

응답 데이터의 내용

Google 앱에 반환되는 데이터는 setResult()를 호출하여 앱에서 설정합니다. 이 데이터에는 다음이 포함됩니다.

  • AUTHORIZATION_CODE (String): 승인 코드 값입니다.
  • resultCode (int): 프로세스의 성공 또는 실패를 전달합니다. 다음 값 중 하나를 사용합니다. <ph type="x-smartling-placeholder">
      </ph>
    • Activity.RESULT_OK: 성공을 나타냅니다. 승인 코드가 반환됩니다.
    • Activity.RESULT_CANCELLED: 사용자가 프로세스입니다 이 경우 Google 앱은 승인 URL을 입력합니다.
    • -2: 오류가 발생했음을 나타냅니다. 다양한 유형의 오류 아래에 설명되어 있습니다.
  • ERROR_TYPE (int): 오류 유형으로, 다음 중 하나를 취합니다. 값: <ph type="x-smartling-placeholder">
      </ph>
    • 1: 복구 가능한 오류: Google 앱에서 다음을 사용하여 계정 연결을 시도합니다. 승인 URL입니다.
    • 2: 복구할 수 없는 오류: Google 앱에서 계정 연결을 취소합니다.
    • 3: 요청 매개변수가 잘못되었거나 누락되었습니다.
  • ERROR_CODE (int): 오류의 특성을 나타내는 정수입니다. 보기 자세히 알아보려면 오류 코드 표에 나와 있습니다.
  • ERROR_DESCRIPTION (String, 선택사항): 사람이 읽을 수 있는 상태 메시지 반환합니다.

다음과 같은 경우 AUTHORIZATION_CODE 값이 예상됩니다. resultCode == Activity.RESULT_OK입니다. 다른 모든 경우에는 이 AUTHORIZATION_CODE 필드는 비어 있어야 합니다. resultCode == -2인 경우 ERROR_TYPE 값이 채워져야 합니다.

오류 코드 표

아래 표에는 다양한 오류 코드와 각 오류가 복구 가능한 오류인지 복구할 수 없는 오류인지 여부가 나와 있습니다.

오류 코드 의미 복구 가능 Unrecoverable
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를 통해 오류 결과를 반환해야 합니다. 적절한 대체가 트리거되는지 확인합니다