SDK d’Android
El SDK d’Android de Kixo és compatible amb Kotlin 2.0+ i Java, requereix minSdk 24 (Android 7.0) i està compilat contra compileSdk 35. L’app amfitriona continua sent responsable del seu propi targetSdk. Amb una sola crida a Kixo.configure dins de Application.onCreate, es registren automàticament pantalles, tocs, sessions, fallades i esdeveniments del cicle de vida. El seguiment de push requereix el pont d’FCM que s’explica més avall. El seguiment automàtic de peticions de xarxa no forma part de la versió actual d’Android. El SDK també admet repetició de sessió, identitat i objectius.
Inici ràpid
Tres fitxers. Afegeix el dipòsit Maven, afegeix la dependència i posa dues línies a la subclasse de Application.
Requisits de compilació: compileSdk 35, minSdk 24, Kotlin 2.0+ o Java, i bytecode de Java 17.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://raw.githubusercontent.com/kixoio/kixo-android-sdk/main/repo")
}
}
}Nota
Amb això ja tens tota la integració d’analítica. Els seguiments automàtics estàndard estan activats per defecte; per a push encara cal el pont d’FCM que tens a sota. Sobreescriu els indicadors individuals amb KixoConfiguration.Builder(...) només si ho necessites.
Afegeix-ho a l’app
El dipòsit Maven de Kixo està allotjat a GitHub Pages. Afegeix-lo al costat de google() i mavenCentral() a settings.gradle.kts:
// settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://raw.githubusercontent.com/kixoio/kixo-android-sdk/main/repo")
}
}
}Després, declara la dependència al mòdul de l’app:
// app/build.gradle.kts
dependencies {
implementation("io.kixo:kixo-android-sdk:0.1.20")
}Consell
android.permission.INTERNET i android.permission.ACCESS_NETWORK_STATE ja s’inclouen al manifest del SDK. Els permisos de notificació continuen depenent de l’app i es declaren quan actives les funcions de push.
Projectes amb diversos mòduls
La configuració implementation de Gradle és no transitiva: si declares implementation("io.kixo:kixo-android-sdk:0.1.20") en un mòdul de biblioteca (per exemple, :core_domain), Kixo NO passa a ser visible per a :app ni per a cap altre consumidor. Hi ha dos patrons que funcionen; tria’n un.
Patró A — cada mòdul que crida Kixo el declara pel seu compte (recomanat). manté al mínim el classpath de cada mòdul i evita recompilacions en cascada. Fes servir un catàleg de versions (libs.kixo.sdk) per editar la versió en un sol lloc.
// :core_domain/build.gradle.kts
dependencies {
implementation("io.kixo:kixo-android-sdk:0.1.20") // local use only
}
// :app/build.gradle.kts
dependencies {
implementation(project(":core_domain"))
implementation("io.kixo:kixo-android-sdk:0.1.20") // declared again — fine
}Patró B — reexporta-ho a través de api(...). És una declaració única, però l’ABI pública del mòdul de biblioteca passa a incloure tipus de Kixo, de manera que qualsevol canvi de versió obliga a recompilar tots els mòduls que en depenen. Fes-ho servir només si la biblioteca reutilitza tipus de Kixo a les seves signatures públiques, per exemple si una funció retorna KixoDiagnostics.
// :core_domain/build.gradle.kts
dependencies {
api("io.kixo:kixo-android-sdk:0.1.20") // re-exposed
}
// :app/build.gradle.kts
dependencies {
implementation(project(":core_domain")) // gets Kixo for free
}Avís
Si en un mòdul veus Unresolved reference: Kixo en temps de compilació, a aquest mòdul li falta la seva pròpia dependència del SDK. Afegeix-hi la línia implementation de més amunt o fes servir el patró B.
Inicialitza
Configura Kixo des de la subclasse de Application: onCreate s’executa abans de qualsevol activity, de manera que cada visualització de pantalla, toc i esdeveniment del cicle de vida es captura des del primer fotograma. Registra Application al manifest amb android:name=".MyApp".
import android.app.Application
import io.kixo.sdk.Kixo
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
Kixo.configure(
context = this,
projectId = "kx_proj_YOUR_PROJECT_ID",
apiKey = "kx_key_YOUR_API_KEY",
)
}
}Si necessites ajustar el detall fi —indicadors d’auto-seguiment, cadència d’enviament, mostreig de la repetició o un host d’API personalitzat—, crea explícitament un KixoConfiguration:
import io.kixo.sdk.Kixo
import io.kixo.sdk.KixoConfiguration
val config = KixoConfiguration.Builder(
projectId = "kx_proj_YOUR_PROJECT_ID",
apiKey = "kx_key_YOUR_API_KEY",
)
.autoTrackScreens(true)
.autoTrackTaps(true)
.autoTrackNetwork(false) // reserved; no-op in the current Android release
.autoTrackCrashes(true)
.autoTrackSessions(true)
.autoTrackPush(true)
.flushIntervalMillis(30_000)
.flushAt(20)
.maxBufferSize(200)
.build(applicationContext)
Kixo.configure(this, config)Nota
Idempotent. Una segona crida a configure des del mateix procés no fa res i es registra com a WARN; el SDK conserva la primera configuració. Els esdeveniments que el teu singleton d’autenticació envia abans que abans configure estigui llest es deixen en memòria intermèdia (màxim 50) i s’envien quan el SDK ja està connectat. Així, pots cridar Kixo.identify(...) des d’un punt global abans que Application.onCreate acabi.
Registra esdeveniments
Tres primitives concentren gairebé tota la instrumentació: track per als esdeveniments, markGoal per als senyals de conversió i addBreadcrumb per al context que no forma part d’un esdeveniment.
import io.kixo.sdk.Kixo
Kixo.track("video_played", mapOf(
"video_id" to "vid_42",
"duration_ms" to 18_500,
"autoplay" to false,
))
// markGoal(name, value?, currency?, properties?) — pass extra context
// through the named 'properties' argument (a Map can't be the 2nd
// positional arg; that slot is the Double 'value').
Kixo.markGoal("activated", properties = mapOf(
"step" to "onboarding_completed",
))
// Revenue goals use the typed value + currency parameters:
Kixo.markGoal("purchase_completed", value = 49.99, currency = "USD")
Kixo.addBreadcrumb(
message = "user toggled dark mode",
category = "ui",
level = "info",
)Consell
Els objectius es classifiquen per nivell. Els objectius marcats alimenten els embuts d’activació de Kixo i el cron diari de detecció de canvis: si el volum d’un objectiu cau un 70% respecte de la setmana anterior, apareix al dashboard amb la insígnia Cal revisar-ho. Fes servir markGoal per als pocs moments que realment importen; track per a la resta.
Esdeveniments estàndard
És una capa de comoditat sobre Kixo.track per als esdeveniments que Kixo reconeix pel nom: claus de cadena literals que el detector d’esdeveniments estàndard del backend identifica. Tens validació en temps de compilació de l’estructura de les propietats i una única font de veritat per als noms.
import io.kixo.sdk.Kixo
import io.kixo.sdk.SubscriptionInterval
Kixo.trackPurchase(
amount = 49.99,
currency = "USD",
productId = "pro_yearly",
)
Kixo.trackSubscriptionStart(
plan = "pro",
amount = 9.99,
currency = "USD",
interval = SubscriptionInterval.MONTH,
)
Kixo.trackSignup(method = "google")
Kixo.trackTrialStart(plan = "pro", days = 14)
Kixo.trackCancel(plan = "pro", reason = "too_expensive")
Kixo.trackUpgrade(fromPlan = "free", toPlan = "pro")
Kixo.trackActivation(event = "first_post_published")
Kixo.trackShare(channel = "twitter", contentId = "post_123")
Kixo.trackInvite(channel = "email", recipientCount = 5)Identifica usuaris
Associa els esdeveniments següents a un ID d’usuari estable i a un conjunt de trets. La unió entre anònim i identificat la fa Kixo: els esdeveniments capturats abans de identify s’atribueixen retroactivament al mateix usuari.
import io.kixo.sdk.Kixo
// Reserved standard property keys carry a $-prefix (Mixpanel
// convention) so they namespace away from your own custom traits
// and promote to the dashboard's profile columns. See
// io.kixo.sdk.StandardProperty for the typed catalogue, or the
// "Standard property catalog" section below for the full 37-key list.
Kixo.identify("user_123", mapOf(
"$email" to "jane@example.com", // identity
"$name" to "Jane Doe", // identity
"$plan" to "pro", // subscription pack
"$lifetime_orders" to 12, // e-commerce pack
"signup_source" to "twitter_ad", // custom trait
))
// Logout: clear identity, super-properties, and the persisted queue.
Kixo.reset()⚠️ Parany del signe del dòlar a Kotlin. Les claus d’identitat estàndard porten el prefix $ ($email, $name, $first_name) i, dins d’un literal de Kotlin, must escapar el signe del dòlar com "\$email". Si escrius "$email", s’interpola la variable email, de manera que el valor acaba silenciosament com a tret personalitzat i no omple mai les columnes de correu electrònic o nom d’Audience. La solució més simple és fer servir la sobrecàrrega tipada (SDK 0.1.13+), que no es pot escriure malament: Kixo.setUserProperty(StandardProperty.EMAIL, email).
Etiqueta un usuari per segmentar-lo
Fes servir setUserProperty amb un valor booleà per afegir a l’usuari una etiqueta senzilla de sí/no. L’etiqueta persisteix entre arrencades i serveix per a segments, campanyes de correu i consultes al xat, sense cap configuració més enllà de la crida del SDK.
// Tag a user as subscribed — segments + campaigns can target this
Kixo.setUserProperty("subscribe", true)
// VIP membership
Kixo.setUserProperty("vip", true)
// String + numeric values work too
Kixo.setUserProperty("plan_tier", "enterprise")
Kixo.setUserProperty("lifetime_orders", 42)
// Bulk-set
Kixo.setUserProperties(mapOf(
"subscribe" to true,
"plan_tier" to "enterprise",
))Les propietats es conserven amb SharedPreferences entre arrencades i s’adjunten automàticament a tots els esdeveniments sortints. Al xat, pots demanar coses com "envia un correu electrònic de benvinguda als usuaris on subscribe sigui true"; Kixo et crea el segment i et prepara l’esborrany de la plantilla. S’esborren amb Kixo.reset().
Catàleg estàndard de propietats
Les claus de propietat reservades porten el prefix $ per no barrejar-se amb els teus trets personalitzats. El catàleg de Kixo inclou 37 claus repartides en 3 paquets universals (identitat, geografia i cicle de vida) i 5 paquets verticals B2B (subscripció, comerç electrònic, mitjans, marketplace i fidelització). Defineix només les que s’apliquin al teu producte: el dashboard s’adapta i només mostra els paquets que tinguis emplenats.
Identitat
Sempre rellevant. Defineix les columnes de capçalera del perfil.
| Clau | Tipus | Descripció |
|---|---|---|
$email | cadena | Adreça electrònica principal, sovint usada com a clau de fusió per unificar identitats. |
$phone | cadena | Número de telèfon E.164. |
$name | cadena | Nom complet visible. |
$first_name | cadena | Nom. |
$last_name | cadena | Cognom. |
$avatar_url | cadena | URL completa de la imatge d’avatar de l’usuari. |
Geo
Context geogràfic.
| Clau | Tipus | Descripció |
|---|---|---|
$country | cadena | Codi de país ISO 3166. |
$city | cadena | Nom de la ciutat. |
$region | cadena | Estat o província. |
$timezone | cadena | Zona IANA com America/Los_Angeles. |
$language | cadena | Etiqueta IETF com en o ru-RU. |
$locale | cadena | Identificador de locale complet. |
Cicle de vida
Quan l’hem vist.
| Clau | Tipus | Descripció |
|---|---|---|
$created | ISO8601 | Moment del registre o de la creació del compte. |
$last_seen | ISO8601 | Hora de l’última interacció. |
Subscripció
Defineix-ho si el teu producte té plans.
| Clau | Tipus | Descripció |
|---|---|---|
$plan | cadena | Slug del nivell: free, pro, enterprise. |
$subscription_status | cadena | active / trial / cancelled / past_due. |
$trial_ends | ISO8601 | Quan caduca el període de prova actual. |
$mrr | nombre | Ingressos recurrents mensuals en la moneda del compte. |
$subscription_started | ISO8601 | Quan va començar la subscripció actual. |
Comerç electrònic
Defineix-ho si vens productes.
| Clau | Tipus | Descripció |
|---|---|---|
$lifetime_orders | nombre | Nombre de comandes completades. |
$lifetime_revenue | nombre | Despesa total. |
$aov | nombre | Valor mitjà de la comanda. |
$last_purchase | ISO8601 | Última compra satisfactòria. |
$first_purchase | ISO8601 | Primera compra completada amb èxit. |
$cart_abandoned_count | nombre | Nombre total d’abandonaments del carretó. |
Mitjans
Defineix-ho si publiques contingut.
| Clau | Tipus | Descripció |
|---|---|---|
$content_tier | cadena | free / premium / paid. |
$subscribed_categories | Cadena CSV o matriu | Categories que segueix l’usuari. |
$watch_time_total | nombre | Temps total de visualització en segons. |
$last_played | ISO8601 | Inici de reproducció més recent. |
Marketplace
Defineix-ho si el teu producte és una plataforma de dues bandes.
| Clau | Tipus | Descripció |
|---|---|---|
$seller_tier | cadena | Slug del nivell del venedor. |
$buyer_tier | cadena | Slug del nivell del costat comprador. |
$listings_count | nombre | Anuncis actius que pertanyen a l’usuari. |
$reviews_count | nombre | Ressenyes rebudes per l’usuari. |
$verified | booleà | Estat del KYC. |
Fidelització
Defineix-ho per a programes d’interacció i de recompenses.
| Clau | Tipus | Descripció |
|---|---|---|
$loyalty_points | nombre | Saldo actual de punts bescanviables. |
$vip_level | cadena | Slug del nivell VIP. |
$referral_count | nombre | Referències satisfactòries atribuïdes a aquest usuari. |
Consell
No hi veus el teu patró? Fes servir claus simples per als atributs personalitzats. Apareixeran al panell Custom Traits del dashboard sense embrutar les columnes del perfil. Els 5 paquets verticals de més amunt són propostes orientades a les formes B2B més habituals; la terminologia específica del client (p. ex. shipping_plan) es manté sense prefix.
Superpropietats
Parells clau-valor de sessió que s’adjunten automàticament a tots els esdeveniments sortints. A diferència dels trets identify, que descriuen la identitat, les superpropietats descriuen el context de la sessió: la variant A/B activa, el flavor de compilació o els feature flags activats. Es conserven entre arrencades i s’esborren amb reset(). Si hi ha conflicte, les properties de l’esdeveniment a track sempre tenen prioritat.
import io.kixo.sdk.Kixo
Kixo.setSuperProperty("build_flavor", "beta")
Kixo.setSuperProperties(mapOf(
"ab_variant" to "B",
"referrer_campaign" to "autumn-launch",
))
// Sugar for A/B tracking — stored as 'experiment_<id>'.
Kixo.setExperimentVariant("checkout_v2", "variant_a")
Kixo.unsetSuperProperty("build_flavor")
Kixo.clearSuperProperties()Notificacions push
Hi ha dos camins d’integració. Tria A si fas servir FCM i vols la configuració funcional més curta; tria B si ja tens un FirebaseMessagingService personalitzat que no pots reestructurar o si vols controlar explícitament quins lliuraments d’FCM veu Kixo.
Opció A — estén KixoFirebaseMessagingService (seguiment automàtic)
Estén KixoFirebaseMessagingService i crida super.onMessageReceived(...) des de la teva sobrescriptura: Kixo emet automàticament push_received (càrrega visible) o push_silent (només dades). La classe base també gestiona el registre de onNewToken si no el sobreescrius. El registre de AndroidManifest.xml és el mateix que en un servei FCM normal.
import com.google.firebase.messaging.RemoteMessage
import io.kixo.sdk.KixoFirebaseMessagingService
class MyMessagingService : KixoFirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage) // Kixo auto-tracks push_received
// … your own routing / notification display
}
}Nota
Kixo compila aquesta classe opcional contra Firebase Messaging, però no afegeix Firebase de manera transitiva a l’app. El SDK declara Firebase com a compileOnly; si tries aquesta opció, l’app ja ha de dependre de firebase-messaging, com passa amb qualsevol receiver d’FCM.
Opció B — crida l’API manual des del teu propi servei FCM
Registra el teu token d’FCM a Kixo amb FirebaseMessagingService.onNewToken i, després, registra explícitament cada lliurament. Fes servir aquest camí si vols que Kixo només vegi una part dels lliuraments d’FCM. Actualment, a Android el seguiment de lliuraments només és compatible amb FCM.
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import io.kixo.sdk.Kixo
import io.kixo.sdk.PushProvider
class MyMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
Kixo.setPushToken(token, PushProvider.FCM)
}
override fun onMessageReceived(message: RemoteMessage) {
// Convert the FCM payload to a Map<String, Any?> and log it —
// Kixo correlates this with the open / dismiss it sees later.
Kixo.logPushReceived(message.data.toMap(), appState = "background")
}
}Android no ofereix cap punt d’entrada universal del cicle de vida per a les obertures, els descartaments o els botons d’acció de les notificacions. Reenvia aquests senyals des dels intents o receivers de notificació que crea l’app:
import io.kixo.sdk.Kixo
Kixo.logPushOpened(payload = pushPayload) // open
Kixo.logPushOpened(payload = pushPayload, actionId = "reply") // action-button tap
Kixo.logPushDismissed(payload = pushPayload) // swipe-awayReproducció de sessions
Reprodueix una reconstrucció visual real del que ha vist l’usuari. A cada captura, el SDK codifica un fotograma comprimit de la pantalla (una imatge JPEG) juntament amb una instantània estructural de la jerarquia de vistes, i puja totes dues coses perquè el reproductor del dashboard pugui mostrar una reproducció fidel al píxel al costat de la cronologia d’interaccions. Configura la repetició de sessió del projecte a Tauler > Configuració > Reproducció de sessions. El SDK llegeix i actualitza automàticament aquesta política de projecte, incloent-hi l’emmascarament, els modes de captura i el permís de pujada amb dades mòbils.
import io.kixo.sdk.Kixo
import io.kixo.sdk.KixoConfiguration
val config = KixoConfiguration.Builder(
projectId = "kx_proj_YOUR_PROJECT_ID",
apiKey = "kx_key_YOUR_API_KEY",
)
.build(applicationContext)
Kixo.configure(this, config)Si la pujada amb dades mòbils està desactivada, la repetició en cua espera una xarxa permesa.
Consell
Emmascara abans de pujar. Kixo captura píxels, així que l’emmascarament s’aplica abans que res surti del dispositiu. Els camps de contrasenya i de correu electrònic es detecten i s’oculten automàticament; el text de les instantànies estructurals passa per un filtre de PII; i qualsevol vista marcada amb setKixoMask(true) es rasteritza com un rectangle opac al fotograma abans que es codifiqui el JPEG: els seus píxels no surten mai del dispositiu. Per defecte, les pantalles de Jetpack Compose queden emmascarades senceres (crida setKixoMask(false) al ComposeView més extern per incloure una pantalla que ja hagis revisat). Els operadors revisen el reproductor de la repetició al costat de la cronologia d’esdeveniments del dashboard.
Recollida de dades
El SDK captura les dades que tinguis activades al projecte i els esdeveniments i propietats que envia l’aplicació.
Depuració
Kixo.diagnostics() retorna una instantània de només lectura de l’estat del SDK. És útil en una pantalla de depuració amagada o en una prova de fum, i respon «per què no arriben els meus esdeveniments?» sense haver d’obrir el depurador.
import io.kixo.sdk.Kixo
val diag = Kixo.diagnostics()
Log.d("Kixo", "queued=${diag.queue.bufferedEventCount}")
Log.d("Kixo", "paused=${diag.paused}") // collection paused state
Log.d("Kixo", "lifecycleState=${diag.lifecycleState}") // SDK lifecycle stateForça un enviament des del teu entorn de proves: bloqueja fins a timeoutMs mentre espera una anada i tornada de xarxa:
import io.kixo.sdk.Kixo
// Async fire-and-forget — returns immediately.
Kixo.flush()
// Blocking variant for instrumentation tests. Never call on the main thread.
val landed: Boolean = Kixo.flushBlocking(timeoutMs = 5_000L)
assertTrue(landed)Compose Navigation
Les rutes d’Activity / Fragment generen immediatament esdeveniments screen_view i registres estructurats screen_visit amb metadades de permanència i de flux. Si fas servir Jetpack Compose Navigation, llança Kixo.screen des d’un LaunchedEffect associat a la ruta; així el SDK veu un sol esdeveniment per destinació, independentment del nombre de recomposicions.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import io.kixo.sdk.Kixo
@Composable
fun AppNavHost(nav: NavHostController) {
NavHost(navController = nav, startDestination = "home") {
composable("home") {
LaunchedEffect("home") { Kixo.screen("HomeScreen") }
HomeScreen()
}
composable("settings") {
LaunchedEffect("settings") { Kixo.screen("SettingsScreen") }
SettingsScreen()
}
}
}Agents de codi amb AI
La superfície pública del SDK és petita i pensada per treballar bé amb l’autocompleció: tots els mètodes pengen del singleton Kixo, tots els exemples de Kotlin d’aquesta guia comencen amb import io.kixo.sdk.Kixo, i el nostre README inclou un bloc «AI agent quick reference» que eines com Claude Code, Cursor i Codex poden enganxar directament al context. Si el teu agent s’encalla, el punt de partida canònic és aquest:
// Tell your AI coding agent:
// "Integrate the Kixo Android SDK using io.kixo:kixo-android-sdk
// from https://raw.githubusercontent.com/kixoio/kixo-android-sdk/main/repo.
// Call Kixo.configure(this, projectId, apiKey) in Application.onCreate.
// Then use Kixo.track / Kixo.identify / Kixo.markGoal as needed."Nota
Totes les seccions anteriors estan escrites pensant en aquest flux de treball: els imports sempre són explícits, els tipus sempre s’anomenen tal com són i el singleton del SDK no rep mai cap àlies. Passa aquesta pàgina al teu agent i deixa que se n’encarregui.