Skip to content

SDK Android

SDK Android para Android 5.0+ (API 21+), empaquetado como un único .aar. Funciona tanto en aplicaciones basadas en Compose como en Views; el SDK es independiente del framework de UI.

Demo en GitHub

📦

Captcha-La/android-demo — ejemplo completo y ejecutable con cada paso de integración.

Instalación

El SDK se distribuye como un único .aar que descargas desde el panel de CaptchaLa. Colócalo en la carpeta libs/ del módulo de tu aplicación y refiérelo desde Gradle:

groovy
// settings.gradle (or repositories block)
dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
}

// app/build.gradle
android {
    defaultConfig {
        minSdk 21
    }
}

dependencies {
    implementation 'la.captcha:captchala:1.0.2'   // Maven Central
}

O descarga el AAR para la integración manual:

groovy
// app/build.gradle (drop captchala.aar into app/libs/)
android {
    defaultConfig {
        minSdk 21
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }
}

dependencies {
    implementation files('libs/captchala.aar')
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.code.gson:gson:2.10.1'
    implementation 'org.bouncycastle:bcprov-jdk18on:1.77'
}

Descarga: dash.captcha.la/downloads (último AAR).

xml
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Compila e instala la demo con:

bash
./gradlew installDebug

Inicio rápido

kotlin
import la.captcha.sdk.CaptchalaClient
import la.captcha.sdk.CaptchalaConfig
import la.captcha.sdk.CaptchalaError
import la.captcha.sdk.CaptchalaListener
import la.captcha.sdk.CaptchalaResult

class LoginActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 1. Fetch a one-shot server_token from YOUR backend
        //    (which calls the CaptchaLa server API with X-App-Key + X-App-Secret).
        val serverToken = runBlocking { fetchServerTokenFromYourBackend() }

        // 2. Build config — destroy any prior client so a fresh state is built.
        CaptchalaClient.destroy()
        val client = CaptchalaClient.getClient(applicationContext).init(
            CaptchalaConfig.Builder()
                .appKey("YOUR_APP_KEY")
                .action("login")            // login, register, pay, …
                .lang("en")                 // en, zh-CN, zh-TW, ja, ko, ms, vi, id
                .theme("light")             // "light" | "dark"
                .enableVoice(true)
                .enableOfflineMode(true)
                .serverToken(serverToken)
                .onServerTokenExpired { fetchServerTokenFromYourBackend() }
                .build()
        )

        // 3. Listen for terminal events.
        client.setListener(object : CaptchalaListener {
            override fun onReady() { /* challenge UI ready */ }
            override fun onSuccess(result: CaptchalaResult) {
                // Send result.passToken to your backend for validation.
                sendToBackend(result.passToken)
            }
            override fun onFail(error: CaptchalaError)  { /* recoverable */ }
            override fun onError(error: CaptchalaError) { /* terminal */ }
            override fun onClose() { /* user dismissed */ }
        })

        // 4. Open the CAPTCHA from a button tap.
        findViewById<Button>(R.id.btnVerify).setOnClickListener {
            client.verify(this)
        }
    }
}

Superficie de la API

SímboloPropósito
CaptchalaClient.getClient(ctx)Punto de entrada singleton. Devuelve el cliente compartido vinculado al contexto de la aplicación.
CaptchalaConfig.Builder()Builder fluido para appKey, action, lang, theme, enableVoice, enableOfflineMode, serverToken.
init(config)Inicializa el cliente con un CaptchalaConfig ya construido. Es económico invocarlo de nuevo — destruye y reconstruye el estado.
setListener(listener)Registra un CaptchalaListener para los callbacks onReady, onSuccess, onFail, onError, onClose.
verify(activity)Abre el CAPTCHA sobre la Activity indicada. El resultado se entrega a través del listener.
CaptchalaResultContiene passToken, challengeId, ttl, isOffline, isClientOnly. Envía passToken a tu backend.
CaptchalaClient.destroy()Destruye el singleton (libera el WebView y los handles nativos). Llámalo desde Activity.onDestroy si re-inicializas con frecuencia.

Validación en el servidor

Reenvía result.passToken (o result.token) a tu backend y valídalo contra la API de CaptchaLa. Nunca expongas X-App-Secret en el código del cliente.

bash
POST https://apiv1.captcha.la/v1/validate
X-App-Key: YOUR_APP_KEY
X-App-Secret: YOUR_APP_SECRET
Content-Type: application/json

{ "pass_token": "<result.passToken>", "client_ip": "<end-user IP>" }

Consulta la Referencia de la API para el endpoint de validación completo y el flujo de X-App-Key / X-App-Secret.

Solución de problemas

  • UnsatisfiedLinkError al arrancar
    Asegúrate de que tus abiFilters cubren armeabi-v7a, arm64-v8a, x86, x86_64 para que todos los dispositivos encuentren una librería nativa compatible. El app/build.gradle de la demo muestra la lista exacta de filtros.

  • ProGuard / R8 elimina clases del SDK en release
    Añade una regla keep para el paquete del SDK, p. ej. -keep class la.captcha.sdk.** { *; } y -dontwarn la.captcha.sdk.** en tu proguard-rules.pro.

  • minSdkVersion demasiado bajo
    El SDK requiere minSdkVersion 21 (Android 5.0). Versiones inferiores fallarán en tiempo de compilación.

  • Tráfico HTTP en claro bloqueado
    Tu manifest debe tener android:usesCleartextTraffic="false" (la demo lo hace). El endpoint de CaptchaLa es solo HTTPS.

Requisitos

  • Android 5.0+ (minSdkVersion 21)
  • AndroidX (compileSdk 33+)
  • Kotlin 1.8+ o cadena de herramientas Java equivalente (Java 17 origen / destino)
  • ABIs: armeabi-v7a, arm64-v8a, x86, x86_64

MIT-licensed examples · CaptchaLa is operated independently