Ir para a documentação

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():

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")
        }
    }
}

Depois, declare a dependência no módulo da app:

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

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
}

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

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
}

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 ApplicationonCreate é 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".

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",
        )
    }
}

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:

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

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.

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",
)

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.

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)

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.

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()

⚠️ 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.

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",
))

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.

ChaveTipoDescrição
$emailcadeia de caracteresEmail principal, muitas vezes usado como chave de junção na consolidação de identidades.
$phonecadeia de caracteresNúmero de telefone E.164.
$namecadeia de caracteresNome completo apresentado.
$first_namecadeia de caracteresNome próprio.
$last_namecadeia de caracteresApelido.
$avatar_urlcadeia de caracteresURL completo da imagem de avatar do utilizador.

Geo

Contexto geográfico.

ChaveTipoDescrição
$countrycadeia de caracteresCódigo do país segundo a ISO 3166.
$citycadeia de caracteresNome da cidade.
$regioncadeia de caracteresEstado ou província.
$timezonecadeia de caracteresZona IANA, como America/Los_Angeles.
$languagecadeia de caracteresTag IETF, como en ou ru-RU.
$localecadeia de caracteresIdentificador completo de locale.

Ciclo de vida

Quando o vimos.

ChaveTipoDescrição
$createdISO8601Data e hora de registo ou criação da conta.
$last_seenISO8601Momento da última interação.

Subscrição

Defina se o seu produto tem planos.

ChaveTipoDescrição
$plancadeia de caracteresSlug do nível — free, pro, enterprise.
$subscription_statuscadeia de caracteresactive / trial / cancelled / past_due.
$trial_endsISO8601Quando termina o período experimental atual.
$mrrnúmeroReceita recorrente mensal na moeda da conta.
$subscription_startedISO8601Quando começou a subscrição atual.

Comércio eletrónico

Defina se vende produtos.

ChaveTipoDescrição
$lifetime_ordersnúmeroNúmero de encomendas concluídas.
$lifetime_revenuenúmeroDespesa total.
$aovnúmeroValor médio da encomenda.
$last_purchaseISO8601Compra concluída mais recente.
$first_purchaseISO8601Primeira compra bem-sucedida.
$cart_abandoned_countnúmeroTotal acumulado de abandonos de carrinho.

Media

Defina se publica conteúdo.

ChaveTipoDescrição
$content_tiercadeia de caracteresfree / premium / paid.
$subscribed_categoriesstring CSV ou arrayCategorias seguidas pelo utilizador.
$watch_time_totalnúmeroTempo total de visualização em segundos.
$last_playedISO8601Início de reprodução mais recente.

Marketplace

Defina se a sua plataforma é bilateral.

ChaveTipoDescrição
$seller_tiercadeia de caracteresSlug do nível do lado do vendedor.
$buyer_tiercadeia de caracteresSlug do escalão do lado do comprador.
$listings_countnúmeroAnúncios ativos do utilizador.
$reviews_countnúmeroAvaliações recebidas pelo utilizador.
$verifiedbooleanEstado de KYC.

Fidelização

Defina para programas de engagement e recompensas.

ChaveTipoDescrição
$loyalty_pointsnúmeroSaldo atual de pontos resgatáveis.
$vip_levelcadeia de caracteresSlug do nível VIP.
$referral_countnúmeroRecomendaçõ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.

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()

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.

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

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.

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")
    }
}

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:

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

Reproduçã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.

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)

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.

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

Force um envio a partir da sua infraestrutura de testes — bloqueia até timeoutMs durante uma ida e volta de rede:

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)

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.

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()
        }
    }
}

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

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

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.