Integração Android
🤖 Integração Android
Este guia mostra como invocar o GuardianKey Mobile SDK na etapa de login do seu próprio app Android — a mesma ligação usada pelo app de exemplo de referência. O SDK é escrito em Kotlin Multiplatform, mas no Android é um AAR/biblioteca normal que você consome a partir de Kotlin ou Java.
Requisitos:
minSdk 26+, Kotlin, umaActivitysua para a tela de login. O tier biométrico exige que aActivityde login seja umaFragmentActivity.
1. Adicione a dependência do SDK
O módulo do SDK é :sdk (namespace do artefato io.guardiankey.gkas). Escolha uma:
Opção A — incluir o módulo (monorepo / código‑fonte):
// settings.gradle.kts
include(":sdk")
// app/build.gradle.kts
dependencies {
implementation(project(":sdk"))
}
Opção B — consumir o AAR. Gere‑o e publique no mavenLocal() (ou coloque o
.aar em um repositório flat):
./gradlew :sdk:assembleRelease # gera sdk/build/outputs/aar/sdk-release.aar
# ou, se o SDK estiver configurado para publicar:
./gradlew :sdk:publishToMavenLocal
Como o SDK depende de Ktor, coroutines e AndroidX Biometric, declare essas dependências transitivas no seu app ao consumir um AAR “puro”:
dependencies {
implementation("io.ktor:ktor-client-okhttp:<versão>")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:<versão>")
implementation("androidx.biometric:biometric:<versão>")
}
2. Declare as permissões
Adicione as permissões usadas pelos coletores amplos. Todas são opcionais em
runtime — se negadas, o sinal correspondente apenas reporta available:false e
o login continua.
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
Se o seu backend usar
httpem texto claro durante o desenvolvimento, defina tambémandroid:usesCleartextTraffic="true"no<application>.
3. Hospede a tela de login em uma FragmentActivity
O tier de identidade biométrico exibe um BiometricPrompt, que precisa de uma
FragmentActivity. Faça sua Activity de login ser uma FragmentActivity e
exponha ao SDK a que está em primeiro plano, via um pequeno holder.
// ActivityHolder.kt
object ActivityHolder {
private var ref = java.lang.ref.WeakReference<FragmentActivity>(null)
var current: FragmentActivity?
get() = ref.get()
set(value) { ref = java.lang.ref.WeakReference(value) }
}
class LoginActivity : FragmentActivity() {
override fun onResume() {
super.onResume()
ActivityHolder.current = this
}
override fun onPause() {
super.onPause()
if (ActivityHolder.current === this) ActivityHolder.current = null
}
// 4. Encaminhe eventos de toque ao coletor comportamental (só tempo/geometria).
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (ev != null) GkasTouchTracker.feed(ev)
return super.dispatchTouchEvent(ev)
}
}
4. Encaminhe eventos de toque (sinal comportamental)
O SDK não consegue observar toques globalmente, então o app encaminha os eventos
brutos para GkasTouchTracker.feed(...) — tipicamente a partir de
Activity.dispatchTouchEvent, como acima. O tracker guarda apenas características
comportamentais dos toques e nunca captura o conteúdo digitado. Isso alimenta
o sinal comportamental do SDK. Se você pular este passo, esse sinal apenas fica
vazio e o login continua funcionando.
5. Solicite permissões em runtime (best‑effort)
Peça as permissões perigosas antes/na tela de login. Não bloqueie o login pelo resultado — permissões negadas apenas degradam os sinais correspondentes.
private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { /* best-effort */ }
private fun requestCollectorPermissions() {
val perms = mutableListOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
perms += Manifest.permission.BLUETOOTH_CONNECT
perms += Manifest.permission.BLUETOOTH_SCAN
}
permissionLauncher.launch(perms.toTypedArray())
}
6. Crie a instância do SDK
Construa um GuardianKeyGkas com a URL base do seu backend e um PlatformContext.
O activityProvider permite ao tier biométrico encontrar a activity em primeiro
plano.
import io.guardiankey.gkas.GkasSdkConfig
import io.guardiankey.gkas.GuardianKeyGkas
import io.guardiankey.gkas.PlatformContext
val gkas = GuardianKeyGkas.create(
config = GkasSdkConfig(
backendBaseUrl = "https://seu-backend.exemplo.com/api", // sem barra no final
httpTimeoutMs = 8000,
debug = BuildConfig.DEBUG,
),
platform = PlatformContext(
context = applicationContext,
activityProvider = { ActivityHolder.current },
),
)
Para o emulador Android alcançar um backend na máquina host, use
http://10.0.2.2:8080.
7. Conduza o login
Chame os três passos em ordem dentro de uma coroutine (ex.: em um ViewModel).
Mapeie o LoginResult para a sua navegação.
import io.guardiankey.gkas.LoginRequest
import io.guardiankey.gkas.LoginResult
fun login(username: String, password: String) = viewModelScope.launch {
try {
val config = gkas.fetchConfig() // 1) GET /config
val solution = gkas.buildSolution(config, username) // 2) coleta + assina
val result = gkas.login( // 3) POST /login
LoginRequest(
username = username,
password = password,
gkasSolution = solution,
config = config,
)
)
when (result) {
is LoginResult.Allowed -> goToHome()
is LoginResult.Blocked -> showBlocked(result.reason) // permanece no login
is LoginResult.Error -> showError(result.message)
}
} catch (e: Throwable) {
showError("Falha de comunicação: ${e.message}")
}
}
Essa é a integração inteira: fetchConfig → buildSolution → login, e então
reagir a Allowed / Blocked / Error.
✅ Checklist
- Dependência do SDK adicionada (módulo
:sdkou AAR + deps transitivas). - Permissões no manifest; solicitação em runtime ligada (best‑effort).
-
Activityde login é umaFragmentActivity; activity em foco exposta via holder. -
dispatchTouchEventencaminha paraGkasTouchTracker.feed(...). -
GuardianKeyGkas.create(...)construído com URL do backend +PlatformContext. - Login chama
fetchConfig → buildSolution → logine trata a decisão.
Veja a referência de API para a API pública
completa e o contrato /config e /login do backend.