Android SDK
O Kixo Android SDK suporta Kotlin 2.0+ e Java, requer minSdk 24 (Android 7.0) e é compilado com compileSdk 35. A app anfitriã continua responsável pelo seu próprio targetSdk. Uma única chamada a Kixo.configure no seu Application.onCreate rastreia automaticamente ecrãs, toques, sessões, crashes e eventos do ciclo de vida. O rastreio de push requer a ponte FCM descrita abaixo. O rastreio automático de pedidos de rede não faz parte da versão Android atual. O SDK também suporta replay de sessões, identidade e objetivos.
Início rápido
Três ficheiros. Adicione o repositório Maven, adicione a dependência e depois junte duas linhas à sua subclasse de Application.
Requisitos de compilação: compileSdk 35, minSdk 24, Kotlin 2.0+ ou Java e bytecode 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
Isto basta para a integração de analytics. Os rastreadores automáticos padrão estão ativos por defeito; o push continua a precisar da ponte FCM abaixo. Só altere sinalizadores individuais com KixoConfiguration.Builder(...) quando for preciso.
Adicionar à app
O repositório Maven da Kixo está alojado no GitHub Pages. Adicione-o em settings.gradle.kts, juntamente com google() e mavenCentral():
// 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")
}
}
}Depois, declare a dependência no módulo da app:
// app/build.gradle.kts
dependencies {
implementation("io.kixo:kixo-android-sdk:0.1.20")
}Sugestão
android.permission.INTERNET e android.permission.ACCESS_NETWORK_STATE já vêm incluídos no manifesto do SDK. As permissões de notificações continuam a ser geridas pela sua app e são declaradas quando optar pelas funcionalidades de push.
Projetos com vários módulos
A configuração implementation do Gradle é não transitiva: declarar implementation("io.kixo:kixo-android-sdk:0.1.20") num módulo de biblioteca (por exemplo, :core_domain) NÃO torna Kixo visível para :app nem para qualquer outro consumidor. Há dois padrões que funcionam — escolha um.
Padrão A — cada módulo que chama Kixo declara a dependência (recomendado). Mantém o classpath de cada módulo no mínimo e evita recompilações em cascata. Use um catálogo de versões (libs.kixo.sdk) para alterar a versão num único local.
// :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
}Padrão B — reexportar através de api(...). É uma única declaração, mas a ABI pública do módulo da biblioteca passa a incluir tipos da Kixo — qualquer atualização de versão obriga a recompilar todos os módulos a jusante. Use isto apenas quando a biblioteca reutiliza tipos da Kixo nas suas próprias assinaturas públicas (por exemplo, se devolver KixoDiagnostics numa função).
// :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
}Aviso
Se vir Unresolved reference: Kixo durante a compilação de um módulo, esse módulo não declarou a sua própria dependência do SDK — adicione a linha implementation acima ou use o Padrão B.
Inicializar
Configure a Kixo na sua subclasse de Application — onCreate é executado antes de qualquer activity, por isso todas as visualizações de ecrã, toques e eventos do ciclo de vida são captados desde o primeiro fotograma. Registe Application no manifest com 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",
)
}
}Para afinações mais detalhadas (sinalizadores de rastreio automático, cadência de envio, amostragem de replay, anfitrião API personalizado), crie explicitamente um 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
Idempotente. Uma segunda chamada a configure no mesmo processo é ignorada e registada com WARN — o SDK mantém a primeira configuração. Os eventos colocados em fila pelo seu singleton de autenticação antes de antes de configure estar disponível ficam em buffer (limite de 50) e são reproduzidos assim que o SDK estiver ligado, por isso pode chamar Kixo.identify(...) a partir de um global antes de Application.onCreate terminar.
Registar eventos
Três primitivas suportam a maior parte da sua instrumentação: track para eventos, markGoal para sinais de conversão e addBreadcrumb para contexto não associado a eventos.
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",
)Sugestão
Os objetivos são classificados. Os objetivos assinalados alimentam os funis de ativação da Kixo e a tarefa diária de deteção de alterações — um objetivo cujo volume caia 70% de uma semana para a outra aparece no dashboard com um distintivo Precisa de revisão. Use markGoal para os poucos momentos que realmente importam; track para tudo o resto.
Eventos padrão
Abstração sobre Kixo.track para os eventos que a Kixo reconhece pelo nome — chaves de texto literais que o detetor de eventos padrão do backend identifica. Validação em compilação da estrutura das propriedades e uma única fonte de verdade para os nomes.
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)Identificar utilizadores
Associe os eventos seguintes a um ID de utilizador estável e a um conjunto de traits. A associação entre utilizadores anónimos e identificados é feita na Kixo — os eventos capturados antes de identify são atribuídos retroativamente ao mesmo utilizador.
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()⚠️ Armadilha do cifrão em Kotlin. As chaves de identidade padrão usam o prefixo $ ($email, $name, $first_name) — e, num literal de Kotlin, tem de escapar o cifrão como "\$email". Se escrever "$email", a string interpola a sua variável email, pelo que o valor acaba silenciosamente num trait personalizado e nunca preenche as colunas de email / nome na Audience. A correção mais simples é usar a sobrecarga tipada (SDK 0.1.13+), que elimina este erro: Kixo.setUserProperty(StandardProperty.EMAIL, email).
Marcar um utilizador para segmentação
Use setUserProperty com um valor boolean para associar ao utilizador uma etiqueta simples de sim/não. A etiqueta mantém-se entre arranques e pode ser usada em segmentos, campanhas de email e consultas no chat — sem configuração adicional além da chamada ao 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",
))As propriedades persistem através de SharedPreferences entre arranques e são anexadas automaticamente a todos os eventos enviados. No chat, diga coisas como "envia um email de boas-vindas aos utilizadores em que subscribe é true" — a Kixo cria o segmento e redige o modelo por si. São limpas em Kixo.reset().
Catálogo de propriedades padrão
As chaves de propriedade reservadas usam o prefixo $, para ficarem separadas dos seus atributos personalizados. O catálogo da Kixo abrange 37 chaves em 3 pacotes universais (identidade, geografia, ciclo de vida) e 5 pacotes verticais B2B (subscrição, comércio eletrónico, media, marketplace, fidelização). Defina apenas as que se aplicam ao seu produto — o dashboard adapta-se e mostra só os pacotes que preencher.
Identidade
Sempre relevante. Define as colunas do cabeçalho do perfil.
| Chave | Tipo | Descrição |
|---|---|---|
$email | cadeia de caracteres | Email principal, muitas vezes usado como chave de junção na consolidação de identidades. |
$phone | cadeia de caracteres | Número de telefone E.164. |
$name | cadeia de caracteres | Nome completo apresentado. |
$first_name | cadeia de caracteres | Nome próprio. |
$last_name | cadeia de caracteres | Apelido. |
$avatar_url | cadeia de caracteres | URL completo da imagem de avatar do utilizador. |
Geo
Contexto geográfico.
| Chave | Tipo | Descrição |
|---|---|---|
$country | cadeia de caracteres | Código do país segundo a ISO 3166. |
$city | cadeia de caracteres | Nome da cidade. |
$region | cadeia de caracteres | Estado ou província. |
$timezone | cadeia de caracteres | Zona IANA, como America/Los_Angeles. |
$language | cadeia de caracteres | Tag IETF, como en ou ru-RU. |
$locale | cadeia de caracteres | Identificador completo de locale. |
Ciclo de vida
Quando o vimos.
| Chave | Tipo | Descrição |
|---|---|---|
$created | ISO8601 | Data e hora de registo ou criação da conta. |
$last_seen | ISO8601 | Momento da última interação. |
Subscrição
Defina se o seu produto tem planos.
| Chave | Tipo | Descrição |
|---|---|---|
$plan | cadeia de caracteres | Slug do nível — free, pro, enterprise. |
$subscription_status | cadeia de caracteres | active / trial / cancelled / past_due. |
$trial_ends | ISO8601 | Quando termina o período experimental atual. |
$mrr | número | Receita recorrente mensal na moeda da conta. |
$subscription_started | ISO8601 | Quando começou a subscrição atual. |
Comércio eletrónico
Defina se vende produtos.
| Chave | Tipo | Descrição |
|---|---|---|
$lifetime_orders | número | Número de encomendas concluídas. |
$lifetime_revenue | número | Despesa total. |
$aov | número | Valor médio da encomenda. |
$last_purchase | ISO8601 | Compra concluída mais recente. |
$first_purchase | ISO8601 | Primeira compra bem-sucedida. |
$cart_abandoned_count | número | Total acumulado de abandonos de carrinho. |
Media
Defina se publica conteúdo.
| Chave | Tipo | Descrição |
|---|---|---|
$content_tier | cadeia de caracteres | free / premium / paid. |
$subscribed_categories | string CSV ou array | Categorias seguidas pelo utilizador. |
$watch_time_total | número | Tempo total de visualização em segundos. |
$last_played | ISO8601 | Início de reprodução mais recente. |
Marketplace
Defina se a sua plataforma é bilateral.
| Chave | Tipo | Descrição |
|---|---|---|
$seller_tier | cadeia de caracteres | Slug do nível do lado do vendedor. |
$buyer_tier | cadeia de caracteres | Slug do escalão do lado do comprador. |
$listings_count | número | Anúncios ativos do utilizador. |
$reviews_count | número | Avaliações recebidas pelo utilizador. |
$verified | boolean | Estado de KYC. |
Fidelização
Defina para programas de engagement e recompensas.
| Chave | Tipo | Descrição |
|---|---|---|
$loyalty_points | número | Saldo atual de pontos resgatáveis. |
$vip_level | cadeia de caracteres | Slug do nível VIP. |
$referral_count | número | Recomendações bem-sucedidas atribuídas a este utilizador. |
Sugestão
Não encontra o padrão certo? Use chaves simples para traits personalizados. Surgem no painel Custom Traits do dashboard sem poluírem as colunas de perfil. Os 5 conjuntos verticais acima são sugestões para os formatos B2B mais comuns — a terminologia específica de cada cliente (por exemplo, shipping_plan) fica sem prefixo.
Superpropriedades
Pares chave/valor por sessão, anexados automaticamente a todos os eventos enviados. Diferem dos traits identify (que descrevem a identidade); as superpropriedades descrevem o contexto da sessão — variante A/B ativa, flavor de build, sinalizadores de funcionalidades ativados. Mantêm-se entre arranques; são limpas em reset(). Em caso de conflito, as properties por evento em track prevalecem sempre.
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()Notificações push
Há dois caminhos de integração. Escolha A se usa FCM e quer a configuração funcional mais curta; escolha B se já tem um FirebaseMessagingService personalizado que não consegue reestruturar ou se quer controlo explícito sobre que entregas FCM a Kixo vê.
Opção A — estender KixoFirebaseMessagingService (rastreio automático)
Crie uma subclasse de KixoFirebaseMessagingService e chame super.onMessageReceived(...) na sua substituição — a Kixo emite automaticamente push_received (payload visível) ou push_silent (apenas dados). A classe base também trata do registo de onNewToken se não o substituir. O registo de AndroidManifest.xml mantém-se igual ao de um serviço 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
A Kixo compila esta classe opcional com Firebase Messaging, mas não adiciona o Firebase à sua app de forma transitiva. O SDK declara o Firebase como compileOnly; uma app que escolha esta opção tem de já depender de firebase-messaging, como acontece com qualquer recetor FCM.
Opção B — chamar a API manualmente a partir do seu próprio serviço FCM
Registe o seu token FCM na Kixo através de FirebaseMessagingService.onNewToken e depois registe explicitamente cada entrega. Use esta via quando quiser que a Kixo veja apenas um subconjunto das entregas FCM. Atualmente, as entregas em Android suportam apenas 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")
}
}O Android não expõe um ponto universal do ciclo de vida para aberturas, dispensas ou botões de ação das notificações. Encaminhe esses sinais a partir dos intents ou receivers de notificação criados pela sua 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-awayReprodução de sessão
Reproduza uma reconstrução visual fiel do que o utilizador viu. Em cada captura, o SDK codifica uma imagem comprimida do ecrã (JPEG), juntamente com um instantâneo estrutural da hierarquia de vistas, e envia ambos — para que o leitor do dashboard apresente uma reprodução com precisão ao píxel a par da cronologia de interações. Configure o replay do projeto em Painel → Definições → Reprodução de sessão. O SDK lê e atualiza automaticamente essa política do projeto, incluindo mascaramento, modos de captura e permissão de envio por rede móvel.
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)Quando o envio por rede móvel está desativado, o replay em fila espera por uma rede permitida.
Sugestão
Mascarar antes do envio. A Kixo capta píxeis, por isso o mascaramento é aplicado antes de de qualquer conteúdo sair do dispositivo. Os campos de palavra-passe e email são detetados e ocultados automaticamente; o texto nos instantâneos estruturais passa por um filtro de PII; e qualquer vista marcada com setKixoMask(true) é rasterizada como um retângulo opaco no fotograma antes de de o JPEG ser codificado — os respetivos píxeis nunca saem do dispositivo. Os ecrãs Jetpack Compose são mascarados por inteiro por predefinição (chame setKixoMask(false) no ComposeView mais exterior para incluir um ecrã que já tenha auditado). Os operadores analisam o leitor de replay ao lado da cronologia de eventos no dashboard.
Recolha de dados
O SDK capta os dados ativados no seu projeto, bem como os eventos e propriedades enviados pela sua aplicação.
Depuração
Kixo.diagnostics() devolve um instantâneo só de leitura do estado do SDK — útil num ecrã de depuração oculto ou num smoke test. Responde a «porque é que os meus eventos não estão a chegar?» sem precisar de um 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 stateForce um envio a partir da sua infraestrutura de testes — bloqueia até timeoutMs durante uma ida e volta de rede:
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)Navegação do Compose
As rotas de Activity / Fragment produzem imediatamente eventos screen_view e registos estruturados screen_visit, com metadados de permanência e fluxo, sem configuração adicional. Para Jetpack Compose Navigation, dispare Kixo.screen a partir de um LaunchedEffect indexado pela rota — assim, o SDK vê um evento por destino, independentemente do número de recomposições.
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()
}
}
}Agentes de código com AI
A superfície pública do SDK é pequena e pensada para funcionar bem com o preenchimento automático de código — todos os métodos estão no singleton Kixo, todos os exemplos Kotlin deste guia começam com import io.kixo.sdk.Kixo, e o nosso README inclui um bloco «referência rápida para agente de AI» que ferramentas como Claude Code, Cursor e Codex podem colar diretamente no contexto. Se o seu agente ficar bloqueado, o ponto de partida canónico é:
// 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
Cada secção acima foi escrita a pensar nesse fluxo de trabalho — os imports são sempre explícitos, os tipos são sempre referidos pelo nome e o singleton do SDK nunca recebe um alias. Entregue esta página ao seu agente e deixe-o avançar.