Android SDK
Kixo Android SDK understøtter Kotlin 2.0+ og Java, kræver minSdk 24 (Android 7.0) og er bygget mod compileSdk 35. Din app er fortsat selv ansvarlig for sin egen targetSdk. Ét kald til Kixo.configure i din Application.onCreate giver automatisk sporing af skærme, tryk, sessioner, nedbrud og livscyklusevents. Push-sporing kræver FCM-broen beskrevet nedenfor. Automatisk sporing af netværksforespørgsler er ikke med i den nuværende Android-udgivelse. SDK'et understøtter også session replay, identitet og mål.
Kom godt i gang
Tre filer. Tilføj Maven-repoet, tilføj afhængigheden, og indsæt derefter to linjer i din Application-underklasse.
Byggekrav: compileSdk 35, minSdk 24, Kotlin 2.0+ eller Java samt Java 17-bytecode.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://raw.githubusercontent.com/kixoio/kixo-android-sdk/main/repo")
}
}
}Bemærk
Så er analytics-integrationen på plads. Standard auto-trackers er slået til som standard; push kræver stadig FCM-broen nedenfor. Overstyr kun de enkelte flag med KixoConfiguration.Builder(...), når det er nødvendigt.
Tilføj til din app
Kixo Maven-repoet hostes på GitHub Pages. Tilføj det sammen med google() og mavenCentral() i 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")
}
}
}Deklarér derefter afhængigheden i app-modulet:
// app/build.gradle.kts
dependencies {
implementation("io.kixo:kixo-android-sdk:0.1.20")
}Tip
android.permission.INTERNET og android.permission.ACCESS_NETWORK_STATE følger med i SDK-manifestet. Notifikationstilladelser styres fortsat af din app og deklareres, når du slår pushfunktioner til.
Projekter med flere moduler
Gradles konfiguration implementation er ikke transitiv: Hvis du deklarerer implementation("io.kixo:kixo-android-sdk:0.1.20") i et bibliotekmodul (fx :core_domain), bliver Kixo IKKE synlig for :app eller andre forbrugere. Der er to mønstre, der virker — vælg ét.
Mønster A — hvert modul, der kalder Kixo, deklarerer det selv (anbefalet). holder hvert moduls classpath minimalt og undgår kædereaktioner af rebuilds. Brug et versionskatalog (libs.kixo.sdk), så du kun retter versionsnummeret ét sted.
// :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
}Mønster B — reeksportér via api(...). Én deklaration, men bibliotekmodulets offentlige ABI kommer nu til at indeholde Kixo-typer — enhver versionsændring udløser rebuild af alle downstream-moduler. Brug kun dette, når biblioteket genbruger Kixo-typer i sine egne offentlige signaturer, fx ved at returnere KixoDiagnostics fra en funktion.
// :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
}Advarsel
Hvis du ser Unresolved reference: Kixo ved kompilering i et modul, mangler modulet sin egen afhængighed af SDK'et — tilføj implementation-linjen ovenfor, eller brug mønster B.
Initialiser
Konfigurer Kixo i din underklasse af Application — onCreate kører før nogen activity, så alle skærmvisninger, tryk og livscyklushændelser registreres fra første frame. Registrer Application i dit manifest med 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",
)
}
}Hvis du vil finjustere indstillinger som auto-track-flags, flush-interval, replay-sampling og brugerdefineret API-host, skal du oprette en KixoConfiguration eksplicit:
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)Bemærk
Idempotent. Et ekstra kald til configure fra samme proces bliver logget som WARN og har ingen effekt — SDK'et beholder den første konfiguration. Events, som din auth-singleton lægger i kø fra før til configure, bliver bufferet (op til 50) og afspillet, når SDK'et er koblet på, så du kan kalde Kixo.identify(...) fra en global, før Application.onCreate er færdig.
Spor events
Tre grundelementer står for det meste af din instrumentering: track til events, markGoal til konverteringssignaler og addBreadcrumb til kontekst, der ikke er et event.
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",
)Tip
Mål bliver vurderet. Markerede mål bruges i Kixo's aktiveringstragte og i det daglige cronjob til ændringsdetektion — et mål, hvis volumen falder 70 % fra uge til uge, vises i dit dashboard med mærket Kræver gennemgang. Brug markGoal til de få øjeblikke, der virkelig betyder noget, og track til alt andet.
Standardevents
Et lag oven på Kixo.track til de events, Kixo genkender på navn — faste strengnøgler, som backendens standardevent-detektor matcher. Giver validering af property-form ved kompilering og ét samlet sted for navngivning.
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)Identificér brugere
Knyt efterfølgende events til et stabilt bruger-id og et sæt traits. Sammenkædning fra anonym til kendt sker i Kixo — events registreret før identify bliver efterfølgende tilskrevet samme bruger.
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()⚠️ Pas på dollartegnet i Kotlin. Standardnøgler til identitet har præfikset $ ($email, $name, $first_name) — og i en Kotlin-literal skal du escape dollartegnet som "\$email". Skriver du "$email", bliver din variabel email interpoleret i strengen, så værdien i stilhed ender som en trait med navnet brugerdefineret og aldrig udfylder kolonnerne for e-mail og navn i Audience. Den enkleste løsning er at bruge den typede overload (SDK 0.1.13+), som ikke kan bruges forkert: Kixo.setUserProperty(StandardProperty.EMAIL, email).
Tag en bruger til segmentering
Brug setUserProperty med en boolsk-værdi for at knytte et enkelt ja/nej-tag til brugeren. Tagget bevares på tværs af appstarter og bruges i segmenter, e-mailkampagner og chatforespørgsler — uden anden opsætning end SDK-kaldet.
// 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",
))Properties gemmes via SharedPreferences på tværs af appstarter og vedhæftes automatisk alle udgående events. I chat kan du fx skrive "send en velkomstmail til brugere, hvor subscribe er true" — så bygger Kixo segmentet og laver et udkast til skabelonen for dig. Ryddes ved Kixo.reset().
Standardkatalog over egenskaber
Reserverede property keys har præfikset $, så de holdes adskilt fra jeres egne traits. Kixo's katalog dækker 37 nøgler fordelt på 3 universelle pakker (identitet, geo, livscyklus) og 5 B2B-pakker (abonnement, e-handel, medier, markedsplads, loyalitet). Angiv de nøgler, der passer til jeres produkt — dashboardet tilpasser sig og viser kun de pakker, I faktisk bruger.
Identitet
Altid relevant. Angiver kolonnerne i profiloverskriften.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$email | streng | Primær e-mailadresse, ofte brugt som merge key til identity stitching. |
$phone | streng | E.164-telefonnummer. |
$name | streng | Fuldt visningsnavn. |
$first_name | streng | Fornavn. |
$last_name | streng | Efternavn. |
$avatar_url | streng | Fuld URL til brugerens avatarbillede. |
Geografi
Geografisk kontekst.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$country | streng | ISO-landekode efter 3166-standarden. |
$city | streng | Bynavn. |
$region | streng | Delstat eller provins. |
$timezone | streng | IANA-zone som America/Los_Angeles. |
$language | streng | IETF-tag som en eller ru-RU. |
$locale | streng | Fuldt locale-id. |
Livscyklus
Hvornår vi sidst så dem.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$created | ISO8601 | Tidspunkt for tilmelding eller kontooprettelse. |
$last_seen | ISO8601 | Tidspunkt for seneste aktivitet. |
Abonnement
Angiv denne, hvis dit produkt har abonnementer.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$plan | streng | Slug for niveau — free, pro, enterprise. |
$subscription_status | streng | active / trial / cancelled / past_due. |
$trial_ends | ISO8601 | Hvornår den nuværende prøveperiode udløber. |
$mrr | tal | Månedlig tilbagevendende omsætning i kontoens valuta. |
$subscription_started | ISO8601 | Hvornår det nuværende abonnement startede. |
E-handel
Angiv denne, hvis I sælger produkter.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$lifetime_orders | tal | Antal gennemførte ordrer. |
$lifetime_revenue | tal | Samlet forbrug. |
$aov | tal | Gennemsnitlig ordreværdi. |
$last_purchase | ISO8601 | Seneste gennemførte køb. |
$first_purchase | ISO8601 | Første gennemførte køb. |
$cart_abandoned_count | tal | Samlet antal forladte indkøbskurve. |
Medier
Angiv denne, hvis I udgiver indhold.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$content_tier | streng | free / premium / paid. |
$subscribed_categories | CSV-streng eller array | Kategorier, som brugeren følger. |
$watch_time_total | tal | Samlet afspilningstid i sekunder. |
$last_played | ISO8601 | Seneste afspilningsstart. |
Markedsplads
Angiv denne, hvis I driver en platform med to sider.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$seller_tier | streng | Slug for sælgers niveau. |
$buyer_tier | streng | Slug for købers niveau. |
$listings_count | tal | Aktive annoncer, som brugeren ejer. |
$reviews_count | tal | Anmeldelser, brugeren har modtaget. |
$verified | boolsk | KYC-status. |
Loyalitet
Bruges til engagements- og belønningsprogrammer.
| Nøgle | Type | Beskrivelse |
|---|---|---|
$loyalty_points | tal | Aktuel saldo af indløselige point. |
$vip_level | streng | Slug for VIP-niveau. |
$referral_count | tal | Vellykkede henvisninger tilskrevet denne bruger. |
Tip
Kan du ikke se dit mønster? Brug nøgler uden præfiks til brugerdefinerede traits. De vises i dashboardets panel for Custom Traits uden at rode profilkolonnerne til. De fem vertikale pakker ovenfor er kvalificerede bud på de mest almindelige B2B-mønstre — kundespecifik terminologi (fx shipping_plan) forbliver uden præfiks.
Super-properties
Nøgle/værdi-par for sessionen, som automatisk vedhæftes alle udgående events. I modsætning til identify traits, der beskriver identitet, beskriver super-properties sessionens kontekst — aktiv A/B-variant, build flavor og tilvalgte feature flags. De bevares på tværs af appstarter og ryddes ved reset(). Ved navnekollision har properties på det enkelte event via track altid forrang.
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()Pushnotifikationer
Der er to integrationsveje. Vælg A, hvis du bruger FCM og vil have den korteste vej til en fungerende opsætning. Vælg B, hvis du allerede har en tilpasset FirebaseMessagingService, som du ikke kan bygge om, eller hvis du vil styre præcist, hvilke FCM-leveringer Kixo ser.
Mulighed A — udvid KixoFirebaseMessagingService (automatisk sporing)
Nedarv fra KixoFirebaseMessagingService, og kald super.onMessageReceived(...) i din override — så udsender Kixo automatisk push_received (synlig payload) eller push_silent (kun data). Basisklassen håndterer også registrering af onNewToken, hvis du ikke overstyrer den. Registrering af AndroidManifest.xml er uændret i forhold til en almindelig FCM-tjeneste.
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
}
}Bemærk
Kixo kompilerer denne valgfrie klasse mod Firebase Messaging, men tilføjer ikke Firebase transitivt til din app. SDK'et deklarerer Firebase som compileOnly; en app, der vælger denne mulighed, skal allerede afhænge af firebase-messaging, ligesom enhver FCM receiver gør.
Mulighed B — kald den manuelle API fra din egen FCM-tjeneste
Registrér dit FCM-token hos Kixo via FirebaseMessagingService.onNewToken, og log derefter hver levering eksplicit. Brug denne løsning, hvis Kixo kun skal se en delmængde af dine FCM-leveringer. Leveringssporing på Android understøtter i øjeblikket kun 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 stiller ikke et universelt lifecycle-hook til rådighed for åbninger, afvisninger eller handlingsknapper på notifikationer. Videresend derfor disse signaler fra de notification intents eller receivers, som din app opretter:
import io.kixo.sdk.Kixo
Kixo.logPushOpened(payload = pushPayload) // open
Kixo.logPushOpened(payload = pushPayload, actionId = "reply") // action-button tap
Kixo.logPushDismissed(payload = pushPayload) // swipe-awaySessionsafspilning
Afspil en visuel rekonstruktion af det, brugeren så. Ved hver optagelse koder SDK'et et komprimeret skærmbillede (et JPEG-billede) sammen med et strukturelt øjebliksbillede af view-hierarkiet og uploader begge dele, så afspilleren i dashboardet kan gengive afspilningen pixelpræcist side om side med interaktionstidslinjen. Konfigurer replay for projektet i Dashboard → Indstillinger → Sessionsafspilning. SDK'et læser og opdaterer automatisk projektets politik, herunder maskering, optagelsestilstande og tilladelse til upload via mobilnet.
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)Når upload via mobilnet er slået fra, venter replay i kø, til et tilladt netværk er tilgængeligt.
Tip
Maskér før upload. Kixo indsamler pixels, så maskering sker før, før noget forlader enheden. Felter til adgangskode og e-mail bliver automatisk genkendt og redigeret væk, tekst i strukturelle snapshots kører gennem et PII-filter, og alle views, du markerer med setKixoMask(true), bliver rasteriseret til et dækkende rektangel i billedet før, før JPEG bliver kodet — de pågældende pixels forlader aldrig enheden. Skærme i Jetpack Compose maskeres som standard i deres helhed (kald setKixoMask(false) på den yderste ComposeView for at inkludere en skærm, du har gennemgået). Medarbejdere kan gennemgå replay-afspilleren side om side med hændelsestidslinjen i dashboardet.
Dataindsamling
SDK'et indsamler de data, der er slået til i projektet, samt de events og properties, som appen sender.
Fejlfinding
Kixo.diagnostics() returnerer et skrivebeskyttet øjebliksbillede af SDK'ets tilstand — nyttigt på en skjult debug-skærm eller i en smoke test. Besvarer "hvorfor kommer mine events ikke igennem?" uden en debugger.
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 stateTving et flush fra dit testharness — blokerer i op til timeoutMs på en roundtrip over netværket:
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
Ruter for Activity og Fragment giver straks screen_viewevents og strukturerede screen_visit-poster med metadata om opholdstid og flow uden ekstra opsætning. I Jetpack Compose Navigation skal du sende Kixo.screen fra en LaunchedEffect med ruten som nøgle — så ser SDK'et præcis ét event pr. destination, uanset hvor mange recompositions der sker.
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()
}
}
}AI-kodeagenter
SDK'ets offentlige API er lille og lavet til kodefuldførelse — alle metoder ligger på singletonen Kixo, alle Kotlin-eksempler i denne guide starter med import io.kixo.sdk.Kixo, og vores README indeholder en blok med "AI agent quick reference", som værktøjer som Claude Code, Cursor og Codex kan indsætte direkte i deres kontekst. Hvis din agent går i stå, er dette det autoritative udgangspunkt:
// 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."Bemærk
Alle afsnit ovenfor er skrevet til den arbejdsgang — imports er altid eksplicitte, typer er altid navngivet, og SDK-singletonen får aldrig et alias. Giv siden til din agent, og lad den køre.