Ves a la documentació

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:

kotlin
// 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:

kotlin
// 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.

kotlin
// :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.

kotlin
// :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".

kotlin
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:

kotlin
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.

kotlin
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.

kotlin
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.

kotlin
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.

kotlin
// 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.

ClauTipusDescripció
$emailcadenaAdreça electrònica principal, sovint usada com a clau de fusió per unificar identitats.
$phonecadenaNúmero de telèfon E.164.
$namecadenaNom complet visible.
$first_namecadenaNom.
$last_namecadenaCognom.
$avatar_urlcadenaURL completa de la imatge d’avatar de l’usuari.

Geo

Context geogràfic.

ClauTipusDescripció
$countrycadenaCodi de país ISO 3166.
$citycadenaNom de la ciutat.
$regioncadenaEstat o província.
$timezonecadenaZona IANA com America/Los_Angeles.
$languagecadenaEtiqueta IETF com en o ru-RU.
$localecadenaIdentificador de locale complet.

Cicle de vida

Quan l’hem vist.

ClauTipusDescripció
$createdISO8601Moment del registre o de la creació del compte.
$last_seenISO8601Hora de l’última interacció.

Subscripció

Defineix-ho si el teu producte té plans.

ClauTipusDescripció
$plancadenaSlug del nivell: free, pro, enterprise.
$subscription_statuscadenaactive / trial / cancelled / past_due.
$trial_endsISO8601Quan caduca el període de prova actual.
$mrrnombreIngressos recurrents mensuals en la moneda del compte.
$subscription_startedISO8601Quan va començar la subscripció actual.

Comerç electrònic

Defineix-ho si vens productes.

ClauTipusDescripció
$lifetime_ordersnombreNombre de comandes completades.
$lifetime_revenuenombreDespesa total.
$aovnombreValor mitjà de la comanda.
$last_purchaseISO8601Última compra satisfactòria.
$first_purchaseISO8601Primera compra completada amb èxit.
$cart_abandoned_countnombreNombre total d’abandonaments del carretó.

Mitjans

Defineix-ho si publiques contingut.

ClauTipusDescripció
$content_tiercadenafree / premium / paid.
$subscribed_categoriesCadena CSV o matriuCategories que segueix l’usuari.
$watch_time_totalnombreTemps total de visualització en segons.
$last_playedISO8601Inici de reproducció més recent.

Marketplace

Defineix-ho si el teu producte és una plataforma de dues bandes.

ClauTipusDescripció
$seller_tiercadenaSlug del nivell del venedor.
$buyer_tiercadenaSlug del nivell del costat comprador.
$listings_countnombreAnuncis actius que pertanyen a l’usuari.
$reviews_countnombreRessenyes rebudes per l’usuari.
$verifiedbooleàEstat del KYC.

Fidelització

Defineix-ho per a programes d’interacció i de recompenses.

ClauTipusDescripció
$loyalty_pointsnombreSaldo actual de punts bescanviables.
$vip_levelcadenaSlug del nivell VIP.
$referral_countnombreReferè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.

kotlin
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.

kotlin
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.

kotlin
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:

kotlin
import io.kixo.sdk.Kixo

Kixo.logPushOpened(payload = pushPayload)            // open
Kixo.logPushOpened(payload = pushPayload, actionId = "reply")  // action-button tap
Kixo.logPushDismissed(payload = pushPayload)         // swipe-away

Reproducció 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.

kotlin
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.

kotlin
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 state

Força un enviament des del teu entorn de proves: bloqueja fins a timeoutMs mentre espera una anada i tornada de xarxa:

kotlin
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.

kotlin
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:

kotlin
// 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.