App Flip para Android

El vínculo de cambio de app basado en OAuth (cambio de app) inserta tu app para Android en la de vinculación de Cuentas de Google. Un flujo de vinculación de cuentas tradicional requiere la usuario ingrese sus credenciales en el navegador. El uso de App Flip aplaza al usuario acceder a tu app de Android, lo que te permite aprovechar autorizaciones. Si el usuario accedió a tu app, no es necesario volver a ingresar sus credenciales para vincular su cuenta. Una cantidad mínima de código se requieren cambios para implementar el cambio de app en tu app para Android.

En este documento, aprenderás a modificar tu app para Android de modo que admita Cambio de app

Prueba la muestra

La app de ejemplo de vinculación de app demuestra una integración de vinculación de cuentas compatible con cambio de app en Android. Tú pueden usar esta app para verificar cómo responder a un intent entrante de cambio de app desde Apps de Google para dispositivos móviles.

La app de ejemplo está preconfigurada para integrarse con la herramienta de prueba de cambio de app para Android que puedes usar para verificar la integración de tu app para Android con la Revisa la información antes de configurar la vinculación de cuentas con Google. Esta aplicación simula la intent que activan las apps de Google para dispositivos móviles cuando está habilitado el cambio de app.

Cómo funciona

Los siguientes pasos son obligatorios para realizar una integración de cambio de app:

  1. La app de Google verifica si tu app está instalada en el dispositivo a través de su package name.
  2. La app de Google usa una verificación de firma del paquete para validar que el servidor app es la correcta.
  3. La app de Google crea un intent para iniciar una actividad designada en tu app. Este intent incluye datos adicionales necesarios para la vinculación. También verifica para ver si tu app admite el cambio de app. Para ello, resuelve este intent a través del framework de Android.
  4. Tu app valida que la solicitud provenga de la app de Google. Para ello, sigue estos pasos: tu app verifica la firma del paquete y el ID de cliente proporcionado.
  5. Tu app solicita un código de autorización de tu servidor de OAuth 2.0. En el final de este flujo, devuelve un código de autorización o un error al app de Google
  6. La app de Google recupera el resultado y continúa con la vinculación de cuentas. Si se proporciona un código de autorización, se produce el intercambio del token servidor a servidor, tal como lo hace en la vinculación de OAuth basada en el navegador de tu flujo de trabajo.

Cómo modificar tu app para Android para que admita el cambio de app

Para admitir el cambio de app, realiza los siguientes cambios de código en tu app para Android:

  1. Agrega un elemento <intent-filter> a tu archivo AndroidManifest.xml con una acción string que coincida con el valor que ingresaste en el campo App Flip Intent.

    <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. Valida la firma de la app que realiza la llamada.

    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. Extrae el ID de cliente de los parámetros del intent y verifica que el cliente El ID coincide con el valor esperado.

    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. Una vez que la autorización se haya realizado correctamente, devuelve el código de autorización resultante. a Google.

    // Successful result
    val data = Intent().apply {
        putExtra("AUTHORIZATION_CODE", authCode)
    }
    setResult(Activity.RESULT_OK, data)
    finish()
    
  5. Si se produjo un error, muestra un resultado de error.

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

Contenido del intent de inicio

El intent de Android que inicia tu app incluye los siguientes campos:

  • CLIENT_ID (String): client_id de Google registrado en tu app.
  • SCOPE (String[]): Una lista de los permisos solicitados.
  • REDIRECT_URI (String): Es la URL de redireccionamiento.

Contenido de los datos de respuesta

Los datos que se muestran a la app de Google se configuran en tu app llamando a setResult(). Entre estos datos, se incluyen los siguientes:

  • AUTHORIZATION_CODE (String): Es el valor del código de autorización.
  • resultCode (int): Comunica el éxito o el fracaso del proceso. toma uno de los siguientes valores:
    • Activity.RESULT_OK: Indica que la operación se realizó correctamente. se devuelve un código de autorización.
    • Activity.RESULT_CANCELLED: Indica que el usuario canceló la el proceso de administración de recursos. En ese caso, la app de Google intentará vincular las cuentas con la URL de autorización.
    • -2: Indica que se produjo un error. Diferentes tipos de errores se describen a continuación.
  • ERROR_TYPE (int): Es el tipo de error, que toma una de las siguientes opciones: valores:
    • 1: Error recuperable. La app de Google intentará vincular la cuenta con la URL de autorización.
    • 2: Error irrecuperable: Google app anula la vinculación de cuentas.
    • 3: Parámetros de solicitud no válidos o faltantes.
  • ERROR_CODE (int): Es un número entero que representa la naturaleza del error. Para ver qué significa cada código de error, consulta el tabla de códigos de error.
  • ERROR_DESCRIPTION (String, opcional): Mensaje de estado legible por humanos al describir el error.

Se espera un valor para AUTHORIZATION_CODE cuando resultCode == Activity.RESULT_OK En todos los demás casos, el valor para El campo AUTHORIZATION_CODE debe estar vacío. Si es resultCode == -2, entonces el Se espera que se propague el valor de ERROR_TYPE.

Tabla de códigos de error

En la siguiente tabla, se muestran los diferentes códigos de error y si cada uno es un error recuperable o irrecuperable:

Código de error Significado Recuperable Irrecuperable
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

Para todos los códigos de error, debes mostrar el resultado del error a través de setResult a garantizar que se active el resguardo adecuado.